From 5a3d796578fe944fe82cf71640484636701ce8ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 12:26:28 +0100 Subject: [PATCH 0001/1812] Implement std::istream subclass for constrained file streams --- components/files/constrainedfilestream.cpp | 107 +++++++++++++++++++++ components/files/constrainedfilestream.hpp | 20 ++++ 2 files changed, 127 insertions(+) create mode 100644 components/files/constrainedfilestream.cpp create mode 100644 components/files/constrainedfilestream.hpp diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp new file mode 100644 index 0000000000..404fddfcbc --- /dev/null +++ b/components/files/constrainedfilestream.cpp @@ -0,0 +1,107 @@ +#include "constrainedfilestream.hpp" + +#include + +#include "lowlevelfile.hpp" + +namespace Files +{ + + class ConstrainedFileStreamBuf : public std::streambuf + { + // somewhat arbitrary though 64KB buffers didn't seem to improve performance any + static const size_t sBufferSize = 4096; + + size_t mOrigin; + size_t mSize; + + LowLevelFile mFile; + + char mBuffer[sBufferSize]; + + public: + ConstrainedFileStreamBuf(const std::string &fname, size_t start, size_t length) + { + mFile.open (fname.c_str ()); + mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; + + if (start != 0) + mFile.seek(start); + + mOrigin = start; + } + + virtual int_type underflow() + { + if(gptr() == egptr()) + { + // Read in the next chunk of data, and set the read pointers on success + size_t got = mFile.read(mBuffer, sBufferSize); + // Failure will throw exception in LowLevelFile + /*if(got != -1) */ + setg(&mBuffer[0], &mBuffer[0], mBuffer+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + + return traits_type::to_int_type(*gptr()); + } + + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + // new file position, relative to mOrigin + size_t newPos; + switch (whence) + { + case std::ios_base::beg: + newPos = offset; + break; + case std::ios_base::cur: + newPos = (mFile.tell() - mOrigin) + offset; + break; + case std::ios_base::end: + newPos = mSize + offset; + break; + default: + return traits_type::eof(); + } + mFile.seek(mOrigin+newPos); + + // EOF handled by exception in LowLevelFile + + // Clear read pointers so underflow() gets called on the next read attempt. + setg(0, 0, 0); + + return newPos; + } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + if(pos >= (int)mSize) + return traits_type::eof(); + mFile.seek(mOrigin + pos); + + // Clear read pointers so underflow() gets called on the next read attempt. + setg(0, 0, 0); + return pos; + } + + }; + + ConstrainedFileStream::ConstrainedFileStream(const char *filename, size_t start, size_t length) + : std::istream(new ConstrainedFileStreamBuf(filename, start, length)) + { + + } + + ConstrainedFileStream::~ConstrainedFileStream() + { + delete rdbuf(); + } +} diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp new file mode 100644 index 0000000000..10fe223bc3 --- /dev/null +++ b/components/files/constrainedfilestream.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_CONSTRAINEDFILESTREAM_H +#define OPENMW_CONSTRAINEDFILESTREAM_H + +#include + +namespace Files +{ + +/// A file stream constrained to a specific region in the file, specified by the 'start' and 'length' parameters. +class ConstrainedFileStream : public std::istream +{ +public: + ConstrainedFileStream(const char *filename, + size_t start=0, size_t length=0xFFFFFFFF); + virtual ~ConstrainedFileStream(); +}; + +} + +#endif From 1124343e0d80610a41d98a9d83a3073136e67ee3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 16:05:28 +0100 Subject: [PATCH 0002/1812] Add BUILD_OPENMW switch, build will be broken in next commit --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a117d42d3..fb5583bb27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre pl option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools +option(BUILD_OPENMW "build OpenMW" ON) option(BUILD_BSATOOL "build BSA extractor" ON) option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) @@ -417,7 +418,9 @@ IF(NOT WIN32 AND NOT APPLE) SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") # Install binaries - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + IF(BUILD_OPENMW) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENMW) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) @@ -586,7 +589,9 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/openmw ) +if (BUILD_OPENMW) + add_subdirectory( apps/openmw ) +endif() if (BUILD_BSATOOL) add_subdirectory( apps/bsatool ) From d4dff6ed55bacaab82a1633aaf5cf3ddd8805f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 16:19:21 +0100 Subject: [PATCH 0003/1812] Port BSAFile to istream, remove OGRE bsa resource system --- CMakeLists.txt | 8 +- components/CMakeLists.txt | 2 +- components/bsa/bsa_archive.cpp | 385 --------------------- components/bsa/bsa_archive.hpp | 40 --- components/bsa/bsa_file.cpp | 7 +- components/bsa/bsa_file.hpp | 4 +- components/bsa/resources.cpp | 53 --- components/bsa/resources.hpp | 16 - components/files/constrainedfilestream.hpp | 10 + 9 files changed, 22 insertions(+), 503 deletions(-) delete mode 100644 components/bsa/bsa_archive.cpp delete mode 100644 components/bsa/bsa_archive.hpp delete mode 100644 components/bsa/resources.cpp delete mode 100644 components/bsa/resources.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fb5583bb27..a0cf56ab4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -570,10 +570,10 @@ if(WIN32) endif(WIN32) # Extern -add_subdirectory (extern/shiny) -add_subdirectory (extern/ogre-ffmpeg-videoplayer) -add_subdirectory (extern/oics) -add_subdirectory (extern/sdl4ogre) +#add_subdirectory (extern/shiny) +#add_subdirectory (extern/ogre-ffmpeg-videoplayer) +#add_subdirectory (extern/oics) +#add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a49e54dd3e..f6b1c8cba0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -79,7 +79,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - constrainedfiledatastream lowlevelfile + constrainedfiledatastream lowlevelfile constrainedfilestream ) add_component_dir (compiler diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp deleted file mode 100644 index 4f656f9c49..0000000000 --- a/components/bsa/bsa_archive.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (cpp_bsaarchive.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - 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 - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include "bsa_archive.hpp" - -#include - -#include -#include -#include -#include -#include -#include "bsa_file.hpp" - -#include "../files/constrainedfiledatastream.hpp" - -using namespace Ogre; - -static bool fsstrict = false; - -static char strict_normalize_char(char ch) -{ - return ch == '\\' ? '/' : ch; -} - -static char nonstrict_normalize_char(char ch) -{ - return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); -} - -template -static std::string normalize_path(T1 begin, T2 end) -{ - std::string normalized; - normalized.reserve(std::distance(begin, end)); - char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; - std::transform(begin, end, std::back_inserter(normalized), normalize_char); - return normalized; -} - -/// An OGRE Archive wrapping a BSAFile archive -class DirArchive: public Ogre::Archive -{ - typedef std::map index; - - index mIndex; - - index::const_iterator lookup_filename (std::string const & filename) const - { - std::string normalized = normalize_path (filename.begin (), filename.end ()); - return mIndex.find (normalized); - } - -public: - - DirArchive(const String& name) - : Archive(name, "Dir") - { - typedef boost::filesystem::recursive_directory_iterator directory_iterator; - - directory_iterator end; - - size_t prefix = name.size (); - - if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/') - ++prefix; - - for (directory_iterator i (name); i != end; ++i) - { - if(boost::filesystem::is_directory (*i)) - continue; - - std::string proper = i->path ().string (); - - std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); - - mIndex.insert (std::make_pair (searchable, proper)); - } - } - - bool isCaseSensitive() const { return fsstrict; } - - // The archive is loaded in the constructor, and never unloaded. - void load() {} - void unload() {} - - DataStreamPtr open(const String& filename, bool readonly = true) const - { - index::const_iterator i = lookup_filename (filename); - - if (i == mIndex.end ()) - { - std::ostringstream os; - os << "The file '" << filename << "' could not be found."; - throw std::runtime_error (os.str ()); - } - - return openConstrainedFileDataStream (i->second.c_str ()); - } - - StringVectorPtr list(bool recursive = true, bool dirs = false) - { - return find ("*", recursive, dirs); - } - - FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) - { - return findFileInfo ("*", recursive, dirs); - } - - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter) - { - if(Ogre::StringUtil::match(iter->first, normalizedPattern) || - (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) - ptr->push_back(iter->first); - } - return ptr; - } - - bool exists(const String& filename) - { - return lookup_filename(filename) != mIndex.end (); - } - - time_t getModifiedTime(const String&) { return 0; } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - index::const_iterator i = mIndex.find(normalizedPattern); - if(i != mIndex.end()) - { - std::string::size_type pt = i->first.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = i->first.substr(0, pt); - fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - else - { - for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter) - { - if(Ogre::StringUtil::match(iter->first, normalizedPattern) || - (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) - { - std::string::size_type pt = iter->first.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = iter->first.substr(0, pt); - fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - } - } - - return ptr; - } -}; - -class BSAArchive : public Archive -{ - Bsa::BSAFile arc; - - static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry) - { - return entry.name; - } - -public: - BSAArchive(const String& name) - : Archive(name, "BSA") - { arc.open(name); } - - bool isCaseSensitive() const { return false; } - - // The archive is loaded in the constructor, and never unloaded. - void load() {} - void unload() {} - - DataStreamPtr open(const String& filename, bool readonly = true) const - { - // Get a non-const reference to arc. This is a hack and it's all - // 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. - Bsa::BSAFile *narc = const_cast(&arc); - - // Open the file - return narc->getFile(filename.c_str()); - } - - bool exists(const String& filename) { - return arc.exists(filename.c_str()); - } - - time_t getModifiedTime(const String&) { return 0; } - - // This is never called as far as I can see. - StringVectorPtr list(bool recursive = true, bool dirs = false) - { - return find ("*", recursive, dirs); - } - - // Also never called. - FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) - { - return findFileInfo ("*", recursive, dirs); - } - - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - const Bsa::BSAFile::FileList &filelist = arc.getList(); - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter) - { - std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); - if(Ogre::StringUtil::match(ent, normalizedPattern) || - (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) - ptr->push_back(iter->name); - } - return ptr; - } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - const Bsa::BSAFile::FileList &filelist = arc.getList(); - - for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter) - { - std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); - if(Ogre::StringUtil::match(ent, normalizedPattern) || - (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) - { - std::string::size_type pt = ent.rfind('/'); - if(pt == std::string::npos) - pt = 0; - - FileInfo fi; - fi.archive = const_cast(this); - fi.path = std::string(iter->name, pt); - fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt)); - fi.compressedSize = fi.uncompressedSize = iter->fileSize; - - ptr->push_back(fi); - } - } - - return ptr; - } -}; - -// An archive factory for BSA archives -class BSAArchiveFactory : public ArchiveFactory -{ -public: - const String& getType() const - { - static String name = "BSA"; - return name; - } - - Archive *createInstance( const String& name ) - { - return new BSAArchive(name); - } - - virtual Archive* createInstance(const String& name, bool readOnly) - { - return new BSAArchive(name); - } - - void destroyInstance( Archive* arch) { delete arch; } -}; - -class DirArchiveFactory : public ArchiveFactory -{ -public: - const String& getType() const - { - static String name = "Dir"; - return name; - } - - Archive *createInstance( const String& name ) - { - return new DirArchive(name); - } - - virtual Archive* createInstance(const String& name, bool readOnly) - { - return new DirArchive(name); - } - - void destroyInstance( Archive* arch) { delete arch; } -}; - - -static bool init = false; -static bool init2 = false; - -static void insertBSAFactory() -{ - if(!init) - { - ArchiveManager::getSingleton().addArchiveFactory( new BSAArchiveFactory ); - init = true; - } -} - -static void insertDirFactory() -{ - if(!init2) - { - ArchiveManager::getSingleton().addArchiveFactory( new DirArchiveFactory ); - init2 = true; - } -} - - -namespace Bsa -{ - -// The function below is the only publicly exposed part of this file - -void addBSA(const std::string& name, const std::string& group) -{ - insertBSAFactory(); - ResourceGroupManager::getSingleton(). - addResourceLocation(name, "BSA", group, true); -} - -void addDir(const std::string& name, const bool& fs, const std::string& group) -{ - fsstrict = fs; - insertDirFactory(); - - ResourceGroupManager::getSingleton(). - addResourceLocation(name, "Dir", group, true); -} - -} diff --git a/components/bsa/bsa_archive.hpp b/components/bsa/bsa_archive.hpp deleted file mode 100644 index 7f9ebaae10..0000000000 --- a/components/bsa/bsa_archive.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (cpp_bsaarchive.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - 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 - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include -#include - -#ifndef BSA_BSA_ARCHIVE_H -#define BSA_BSA_ARCHIVE_H - -namespace Bsa -{ - -/// Add the given BSA file as an input archive in the Ogre resource -/// system. -void addBSA(const std::string& file, const std::string& group="General"); -void addDir(const std::string& file, const bool& fs, const std::string& group="General"); - -} - -#endif diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0958c8f0c2..bd6ea8075f 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -28,7 +28,7 @@ #include #include -#include "../files/constrainedfiledatastream.hpp" +#include "../files/constrainedfilestream.hpp" using namespace std; using namespace Bsa; @@ -168,7 +168,7 @@ void BSAFile::open(const string &file) readHeader(); } -Ogre::DataStreamPtr BSAFile::getFile(const char *file) +Files::IStreamPtr BSAFile::getFile(const char *file) { assert(file); int i = getIndex(file); @@ -176,5 +176,6 @@ Ogre::DataStreamPtr BSAFile::getFile(const char *file) fail("File not found: " + string(file)); const FileStruct &fs = files[i]; - return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize); + + return Files::openConstrainedFileStream (filename.c_str (), fs.offset, fs.fileSize); } diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 017adf1e31..3024cb610d 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -32,6 +32,8 @@ #include +#include + namespace Bsa { @@ -116,7 +118,7 @@ public: /** Open a file contained in the archive. Throws an exception if the file doesn't exist. */ - Ogre::DataStreamPtr getFile(const char *file); + Files::IStreamPtr getFile(const char *file); /// Get a list of all files const FileList &getList() const diff --git a/components/bsa/resources.cpp b/components/bsa/resources.cpp deleted file mode 100644 index d06b3b4852..0000000000 --- a/components/bsa/resources.cpp +++ /dev/null @@ -1,53 +0,0 @@ - -#include "resources.hpp" - -#include - -#include -#include - -#include "bsa_archive.hpp" - -void Bsa::registerResources (const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles, bool fsStrict) -{ - const Files::PathContainer& dataDirs = collections.getPaths(); - - int i=0; - - if (useLooseFiles) - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) - { - // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - std::string dataDirectory = iter->string(); - std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, fsStrict, groupName); - ++i; - } - - i=0; - for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) - { - if (collections.doesExist(*archive)) - { - // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(archives.size()-i, 8, '0'); - - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); - - const std::string archivePath = collections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, groupName); - ++i; - } - else - { - std::stringstream message; - message << "Archive '" << *archive << "' not found"; - throw std::runtime_error(message.str()); - } - } -} \ No newline at end of file diff --git a/components/bsa/resources.hpp b/components/bsa/resources.hpp deleted file mode 100644 index 8c3fb7bef8..0000000000 --- a/components/bsa/resources.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef BSA_BSA_RESOURCES_H -#define BSA_BSA_RESOURCES_H - -#include -#include - -#include "../files/collections.hpp" - -namespace Bsa -{ - void registerResources (const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles, bool fsStrict); - ///< Register resources directories and archives as OGRE resources groups -} - -#endif diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index 10fe223bc3..318a02294d 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -3,6 +3,8 @@ #include +#include + namespace Files { @@ -15,6 +17,14 @@ public: virtual ~ConstrainedFileStream(); }; +typedef boost::shared_ptr IStreamPtr; + +IStreamPtr openConstrainedFileStream(const char *filename, + size_t start=0, size_t length=0xFFFFFFFF) +{ + return IStreamPtr(new ConstrainedFileStream(filename, start, length)); +} + } #endif From 8c10d4badb59a8cd5aaf146551ea7b422275a43f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Feb 2015 17:08:55 +0100 Subject: [PATCH 0004/1812] NIF reader compiles without Ogre --- CMakeLists.txt | 3 ++ components/CMakeLists.txt | 22 ++++----- components/nif/controlled.hpp | 4 +- components/nif/controller.hpp | 4 +- components/nif/data.hpp | 20 ++++---- components/nif/effect.hpp | 6 +-- components/nif/niffile.cpp | 87 ++++++++++++++++++----------------- components/nif/niffile.hpp | 8 +++- components/nif/nifkey.hpp | 47 ++++++++++--------- components/nif/nifstream.cpp | 71 ++++++++++++++-------------- components/nif/nifstream.hpp | 37 ++++++++------- components/nif/niftypes.hpp | 21 +++++++-- components/nif/node.cpp | 58 ----------------------- components/nif/node.hpp | 22 ++------- components/nif/property.hpp | 12 +---- 15 files changed, 183 insertions(+), 239 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0cf56ab4e..cbe142fcc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,9 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB) +include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) + find_package(MyGUI REQUIRED) if (${MYGUI_VERSION} VERSION_LESS "3.2.1") message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f6b1c8cba0..ecaeb115b8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -31,24 +31,24 @@ add_component_dir (nifoverrides ) add_component_dir (bsa - bsa_archive bsa_file resources + bsa_file ) add_component_dir (nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream ) -add_component_dir (nifcache - nifcache - ) +#add_component_dir (nifcache +# nifcache +# ) -add_component_dir (nifogre - ogrenifloader skeleton material mesh particles controller - ) +#add_component_dir (nifogre +# ogrenifloader skeleton material mesh particles controller +# ) -add_component_dir (nifbullet - bulletnifloader - ) +#add_component_dir (nifbullet +# bulletnifloader +# ) add_component_dir (to_utf8 to_utf8 @@ -160,7 +160,7 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES}) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 815aa7d3f6..51890f0698 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -129,8 +129,8 @@ public: * 1 - Point (fixed origin) */ int mType; - Ogre::Vector3 mPosition; - Ogre::Vector3 mDirection; + osg::Vec3f mPosition; + osg::Vec3f mDirection; void read(NIFStream *nif) { diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 9ae527e5a0..718748c31e 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -33,7 +33,7 @@ class NiParticleSystemController : public Controller { public: struct Particle { - Ogre::Vector3 velocity; + osg::Vec3f velocity; float lifetime; float lifespan; float timestamp; @@ -64,7 +64,7 @@ public: }; int emitFlags; - Ogre::Vector3 offsetRandom; + osg::Vec3f offsetRandom; NodePtr emitter; diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d9de12fb54..db5a5643d4 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -33,10 +33,10 @@ namespace Nif class ShapeData : public Record { public: - std::vector vertices, normals; - std::vector colors; - std::vector< std::vector > uvlist; - Ogre::Vector3 center; + std::vector vertices, normals; + std::vector colors; + std::vector< std::vector > uvlist; + osg::Vec3f center; float radius; void read(NIFStream *nif) @@ -131,7 +131,7 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: - std::vector rotations; + std::vector rotations; void read(NIFStream *nif) { @@ -272,9 +272,9 @@ class NiSkinData : public Record public: struct BoneTrafo { - Ogre::Matrix3 rotation; // Rotation offset from bone? - Ogre::Vector3 trans; // Translation - float scale; // Probably scale (always 1) + Matrix3 rotation; // Rotation offset from bone? + osg::Vec3f trans; // Translation + float scale; // Scale }; struct VertWeight @@ -286,7 +286,7 @@ public: struct BoneInfo { BoneTrafo trafo; - Ogre::Vector4 unknown; + osg::Vec4f unknown; std::vector weights; }; @@ -327,7 +327,7 @@ struct NiMorphData : public Record { struct MorphData { FloatKeyMap mData; - std::vector mVertices; + std::vector mVertices; }; std::vector mMorphs; diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index cc1b0f41c1..679557e257 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -38,9 +38,9 @@ struct NiLight : Effect struct SLight { float dimmer; - Ogre::Vector3 ambient; - Ogre::Vector3 diffuse; - Ogre::Vector3 specular; + osg::Vec3f ambient; + osg::Vec3f diffuse; + osg::Vec3f specular; void read(NIFStream *nif) { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 4f3ee95cbe..f7d864198e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -2,16 +2,16 @@ #include "effect.hpp" #include - -#include +#include namespace Nif { /// Open a NIF stream. The name is used for error messages. -NIFFile::NIFFile(const std::string &name) +NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) + , mStream(stream) { parse(); } @@ -121,63 +121,68 @@ std::string NIFFile::printVersion(unsigned int version) version_out.full = version; - return Ogre::StringConverter::toString(version_out.quad[3]) - +"." + Ogre::StringConverter::toString(version_out.quad[2]) - +"." + Ogre::StringConverter::toString(version_out.quad[1]) - +"." + Ogre::StringConverter::toString(version_out.quad[0]); + std::stringstream stream; + stream << version_out.quad[3] << "." + << version_out.quad[2] << "." + << version_out.quad[1] << "." + << version_out.quad[0]; + return stream.str(); } void NIFFile::parse() { - NIFStream nif (this, Ogre::ResourceGroupManager::getSingleton().openResource(filename)); + NIFStream nif (this, mStream); - // Check the header string - std::string head = nif.getVersionString(); - if(head.compare(0, 22, "NetImmerse File Format") != 0) - fail("Invalid NIF header: " + head); + // Check the header string + std::string head = nif.getVersionString(); + if(head.compare(0, 22, "NetImmerse File Format") != 0) + fail("Invalid NIF header: " + head); - // Get BCD version - ver = nif.getUInt(); - if(ver != VER_MW) - fail("Unsupported NIF version: " + printVersion(ver)); - // Number of records - size_t recNum = nif.getInt(); - records.resize(recNum); + // Get BCD version + ver = nif.getUInt(); + if(ver != VER_MW) + fail("Unsupported NIF version: " + printVersion(ver)); + // Number of records + size_t recNum = nif.getInt(); + records.resize(recNum); - /* The format for 10.0.1.0 seems to be a bit different. After the + /* The format for 10.0.1.0 seems to be a bit different. After the header, it contains the number of records, r (int), just like 4.0.0.2, but following that it contains a short x, followed by x strings. Then again by r shorts, one for each record, giving which of the above strings to use to identify the record. After this follows two ints (zero?) and then the record data. However we do not support or plan to support other versions yet. - */ + */ - for(size_t i = 0;i < recNum;i++) + for(size_t i = 0;i < recNum;i++) { - Record *r = NULL; + Record *r = NULL; - std::string rec = nif.getString(); - if(rec.empty()) - fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank."); + std::string rec = nif.getString(); + if(rec.empty()) + { + std::stringstream error; + error << "Record number " << i << " out of " << recNum << " is blank."; + fail(error.str()); + } + std::map::const_iterator entry = factories.find(rec); - std::map::const_iterator entry = factories.find(rec); + if (entry != factories.end()) + { + r = entry->second.mCreate (); + r->recType = entry->second.mType; + } + else + fail("Unknown record type " + rec); - if (entry != factories.end()) - { - r = entry->second.mCreate (); - r->recType = entry->second.mType; - } - else - fail("Unknown record type " + rec); - - assert(r != NULL); - assert(r->recType != RC_MISSING); - r->recName = rec; - r->recIndex = i; - records[i] = r; - r->read(&nif); + assert(r != NULL); + assert(r->recType != RC_MISSING); + r->recName = rec; + r->recIndex = i; + records[i] = r; + r->read(&nif); } size_t rootNum = nif.getUInt(); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ceb9984fb8..9f08f3f1d9 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "record.hpp" namespace Nif @@ -42,6 +44,8 @@ class NIFFile ///\overload void operator = (NIFFile const &); + Files::IStreamPtr mStream; + public: /// Used if file parsing fails void fail(const std::string &msg) @@ -57,8 +61,8 @@ public: << "File: " << filename < - #include "nifstream.hpp" +#include +#include + namespace Nif { template struct KeyT { T mValue; + + // FIXME: Implement Quadratic and TBC interpolation + /* T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList 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 KeyMapT { @@ -92,7 +93,12 @@ struct KeyMapT { { //Don't try to read XYZ keys into the wrong part if ( count != 1 ) - nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); + { + std::stringstream error; + error << "XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: " + << count; + nif->file->fail(error.str()); + } } else if (0 == mInterpolationType) { @@ -100,7 +106,11 @@ struct KeyMapT { nif->file->fail("Interpolation type 0 doesn't work with keys"); } else - nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + { + std::stringstream error; + error << "Unhandled interpolation type: " << mInterpolationType; + nif->file->fail(error.str()); + } } private: @@ -109,31 +119,26 @@ private: key.mValue = (nif.*getValue)(); } - static void readQuadratic(NIFStream &nif, KeyT &key) - { - readValue(nif, key); - } - template static void readQuadratic(NIFStream &nif, KeyT &key) { readValue(nif, key); - key.mForwardValue = (nif.*getValue)(); - key.mBackwardValue = (nif.*getValue)(); + /*key.mForwardValue = */(nif.*getValue)(); + /*key.mBackwardValue = */(nif.*getValue)(); } static void readTBC(NIFStream &nif, KeyT &key) { readValue(nif, key); - key.mTension = nif.getFloat(); - key.mBias = nif.getFloat(); - key.mContinuity = nif.getFloat(); + /*key.mTension = */nif.getFloat(); + /*key.mBias = */nif.getFloat(); + /*key.mContinuity = */nif.getFloat(); } }; typedef KeyMapT FloatKeyMap; -typedef KeyMapT Vector3KeyMap; -typedef KeyMapT Vector4KeyMap; -typedef KeyMapT QuaternionKeyMap; +typedef KeyMapT Vector3KeyMap; +typedef KeyMapT Vector4KeyMap; +typedef KeyMapT QuaternionKeyMap; } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index e5699db7b9..628541933f 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -9,19 +9,19 @@ namespace Nif uint8_t NIFStream::read_byte() { uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; + inp->read((char*)&byte, 1); return byte; } uint16_t NIFStream::read_le16() { uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; + inp->read((char*)buffer, 2); return buffer[0] | (buffer[1]<<8); } uint32_t NIFStream::read_le32() { uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; + inp->read((char*)buffer, 4); return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); } float NIFStream::read_le32f() @@ -34,43 +34,45 @@ float NIFStream::read_le32f() } //Public functions -Ogre::Vector2 NIFStream::getVector2() +osg::Vec2f NIFStream::getVector2() { - float a[2]; + osg::Vec2f vec; for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Vector3 NIFStream::getVector3() +osg::Vec3f NIFStream::getVector3() { - float a[3]; + osg::Vec3f vec; for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Vector4 NIFStream::getVector4() +osg::Vec4f NIFStream::getVector4() { - float a[4]; + osg::Vec4f vec; for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); + vec._v[i] = getFloat(); + return vec; } -Ogre::Matrix3 NIFStream::getMatrix3() +Matrix3 NIFStream::getMatrix3() { - Ogre::Real a[3][3]; + Matrix3 mat; for(size_t i = 0;i < 3;i++) { for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + mat.mValues[i][j] = getFloat(); } - return Ogre::Matrix3(a); + return mat; } -Ogre::Quaternion NIFStream::getQuaternion() +osg::Quat NIFStream::getQuaternion() { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + osg::Quat quat; + quat.w() = getFloat(); + quat.x() = getFloat(); + quat.y() = getFloat(); + quat.z() = getFloat(); + return quat; } Transformation NIFStream::getTrafo() { @@ -83,16 +85,9 @@ Transformation NIFStream::getTrafo() std::string NIFStream::getString(size_t length) { - //Make sure we're not reading in too large of a string - unsigned int fileSize = inp->size(); - if(fileSize != 0 && fileSize < length) - file->fail("Attempted to read a string with " + Ogre::StringConverter::toString(length) + " characters , but file is only "+Ogre::StringConverter::toString(fileSize)+ " bytes!"); - std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) - throw std::runtime_error (": String length in NIF file "+ file->getFilename() +" does not match! Expected length: " - + Ogre::StringConverter::toString(length)); + inp->read(&str[0], length); return &str[0]; } @@ -103,7 +98,9 @@ std::string NIFStream::getString() } std::string NIFStream::getVersionString() { - return inp->getLine(); + std::string result; + std::getline(*inp, result); + return result; } void NIFStream::getShorts(std::vector &vec, size_t size) @@ -118,25 +115,25 @@ void NIFStream::getFloats(std::vector &vec, size_t size) for(size_t i = 0;i < vec.size();i++) vec[i] = getFloat(); } -void NIFStream::getVector2s(std::vector &vec, size_t size) +void NIFStream::getVector2s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector2(); } -void NIFStream::getVector3s(std::vector &vec, size_t size) +void NIFStream::getVector3s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector3(); } -void NIFStream::getVector4s(std::vector &vec, size_t size) +void NIFStream::getVector4s(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) vec[i] = getVector4(); } -void NIFStream::getQuaternions(std::vector &quat, size_t size) +void NIFStream::getQuaternions(std::vector &quat, size_t size) { quat.resize(size); for(size_t i = 0;i < quat.size();i++) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 6c5e83eebd..b732c83af2 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -5,14 +5,13 @@ #include #include +#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include #include "niftypes.hpp" @@ -24,7 +23,7 @@ class NIFFile; class NIFStream { /// Input stream - Ogre::DataStreamPtr inp; + Files::IStreamPtr inp; uint8_t read_byte(); uint16_t read_le16(); @@ -35,9 +34,9 @@ public: NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Files::IStreamPtr inp): file (file), inp (inp) {} - void skip(size_t size) { inp->skip(size); } + void skip(size_t size) { inp->ignore(size); } char getChar() { return read_byte(); } short getShort() { return read_le16(); } @@ -46,11 +45,11 @@ public: unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2(); - Ogre::Vector3 getVector3(); - Ogre::Vector4 getVector4(); - Ogre::Matrix3 getMatrix3(); - Ogre::Quaternion getQuaternion(); + osg::Vec2f getVector2(); + osg::Vec3f getVector3(); + osg::Vec4f getVector4(); + Matrix3 getMatrix3(); + osg::Quat getQuaternion(); Transformation getTrafo(); ///Read in a string of the given length @@ -62,10 +61,10 @@ public: void getShorts(std::vector &vec, size_t size); void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); + void getVector2s(std::vector &vec, size_t size); + void getVector3s(std::vector &vec, size_t size); + void getVector4s(std::vector &vec, size_t size); + void getQuaternions(std::vector &quat, size_t size); }; } diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 786c48b65e..864795afb5 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -24,24 +24,35 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP -#include -#include +#include // Common types used in NIF files namespace Nif { +struct Matrix3 +{ + float mValues[3][3]; + + Matrix3() + { + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mValues[i][j] = 0; + } +}; + struct Transformation { - Ogre::Vector3 pos; - Ogre::Matrix3 rotation; + osg::Vec3f pos; + Matrix3 rotation; float scale; static const Transformation& getIdentity() { static const Transformation identity = { - Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f + osg::Vec3f(), Matrix3(), 1.0f }; return identity; } diff --git a/components/nif/node.cpp b/components/nif/node.cpp index fb68da548d..b0c5d990e6 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -1,60 +1,2 @@ #include "node.hpp" -namespace Nif -{ - -void Node::getProperties(const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop, - const Nif::NiStencilProperty *&stencilprop) const -{ - if(parent) - parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - - for(size_t i = 0;i < props.length();i++) - { - // Entries may be empty - if(props[i].empty()) - continue; - - const Nif::Property *pr = props[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else if (pr->recType == Nif::RC_NiStencilProperty) - stencilprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName <getWorldTransform() * getLocalTransform(); - return getLocalTransform(); -} - -} diff --git a/components/nif/node.hpp b/components/nif/node.hpp index a26480d591..123b70cad9 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_COMPONENTS_NIF_NODE_HPP #define OPENMW_COMPONENTS_NIF_NODE_HPP -#include - #include "controlled.hpp" #include "extra.hpp" #include "data.hpp" @@ -26,14 +24,14 @@ public: // 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 + osg::Vec3f velocity; // Unused? Might be a run-time game state PropertyList props; // Bounding box info bool hasBounds; - Ogre::Vector3 boundPos; - Ogre::Matrix3 boundRot; - Ogre::Vector3 boundXYZ; // Box size + osg::Vec3f boundPos; + Matrix3 boundRot; + osg::Vec3f boundXYZ; // Box size void read(NIFStream *nif) { @@ -91,18 +89,6 @@ public: boneTrafo = &bi.trafo; boneIndex = ind; } - - void getProperties(const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop, - const Nif::NiStencilProperty *&stencilprop) const; - - Ogre::Matrix4 getLocalTransform() const; - Ogre::Matrix4 getWorldTransform() const; }; struct NiNode : Node diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 77f61d0684..52ee7f6e16 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -159,7 +159,7 @@ class NiFogProperty : public Property { public: float mFogDepth; - Ogre::Vector3 mColour; + osg::Vec3f mColour; void read(NIFStream *nif) @@ -194,7 +194,7 @@ struct StructPropT : Property struct S_MaterialProperty { // The vector components are R,G,B - Ogre::Vector3 ambient, diffuse, specular, emissive; + osg::Vec3f ambient, diffuse, specular, emissive; float glossiness, alpha; void read(NIFStream *nif) @@ -265,14 +265,6 @@ struct S_AlphaProperty 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. */ // Tested against when certain flags are set (see above.) From f6f37e02df0cb64817c8e59834b45c569fe5afb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 17:56:49 +0100 Subject: [PATCH 0005/1812] NIF Transformation redundancy fix and include fixes --- components/nif/data.hpp | 17 ++++++----------- components/nif/niftypes.hpp | 2 +- components/nif/node.hpp | 4 ++-- components/nif/property.hpp | 3 +++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index db5a5643d4..656d27628c 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -26,6 +26,8 @@ #include "base.hpp" +#include "niftypes.hpp" // Transformation + namespace Nif { @@ -270,13 +272,6 @@ public: class NiSkinData : public Record { public: - struct BoneTrafo - { - Matrix3 rotation; // Rotation offset from bone? - osg::Vec3f trans; // Translation - float scale; // Scale - }; - struct VertWeight { short vertex; @@ -285,18 +280,18 @@ public: struct BoneInfo { - BoneTrafo trafo; + Transformation trafo; osg::Vec4f unknown; std::vector weights; }; - BoneTrafo trafo; + Transformation trafo; std::vector bones; void read(NIFStream *nif) { trafo.rotation = nif->getMatrix3(); - trafo.trans = nif->getVector3(); + trafo.pos = nif->getVector3(); trafo.scale = nif->getFloat(); int boneNum = nif->getInt(); @@ -308,7 +303,7 @@ public: BoneInfo &bi = bones[i]; bi.trafo.rotation = nif->getMatrix3(); - bi.trafo.trans = nif->getVector3(); + bi.trafo.pos = nif->getVector3(); bi.trafo.scale = nif->getFloat(); bi.unknown = nif->getVector4(); diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 864795afb5..4f6998200f 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -39,7 +39,7 @@ struct Matrix3 { for (int i=0;i<3;++i) for (int j=0;j<3;++j) - mValues[i][j] = 0; + mValues[i][j] = (i==j) ? 1.f : 0.f; } }; diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 123b70cad9..7f94c0d05b 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -68,7 +68,7 @@ public: NiNode *parent; // Bone transformation. If set, node is a part of a skeleton. - const NiSkinData::BoneTrafo *boneTrafo; + const Transformation *boneTrafo; // Bone weight info, from NiSkinData const NiSkinData::BoneInfo *boneInfo; @@ -77,7 +77,7 @@ public: // boneTrafo is set it is the root bone in the skeleton. short boneIndex; - void makeRootBone(const NiSkinData::BoneTrafo *tr) + void makeRootBone(const Transformation *tr) { boneTrafo = tr; boneIndex = -1; diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 52ee7f6e16..610f5427ab 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -26,6 +26,9 @@ #include "base.hpp" +#include "controlled.hpp" +#include "data.hpp" + namespace Nif { From 68bce7825e4731b77d598ece1700762099f31637 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 17:57:18 +0100 Subject: [PATCH 0006/1812] Multiple definition fix --- components/files/constrainedfilestream.cpp | 7 +++++++ components/files/constrainedfilestream.hpp | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 404fddfcbc..fddfa7e523 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -104,4 +104,11 @@ namespace Files { delete rdbuf(); } + + + IStreamPtr openConstrainedFileStream(const char *filename, + size_t start, size_t length) + { + return IStreamPtr(new ConstrainedFileStream(filename, start, length)); + } } diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index 318a02294d..069ceec587 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -19,11 +19,7 @@ public: typedef boost::shared_ptr IStreamPtr; -IStreamPtr openConstrainedFileStream(const char *filename, - size_t start=0, size_t length=0xFFFFFFFF) -{ - return IStreamPtr(new ConstrainedFileStream(filename, start, length)); -} +IStreamPtr openConstrainedFileStream(const char *filename, size_t start=0, size_t length=0xFFFFFFFF); } From 8f0ab7d09fcc8f6fe52733b435a15f4f4b5ea234 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:12:05 +0100 Subject: [PATCH 0007/1812] ESM component no longer relies on Ogre DataStreams --- components/esm/esmreader.cpp | 44 +++++++++++++--------- components/esm/esmreader.hpp | 17 ++++----- components/esm/loadscpt.cpp | 2 + components/files/constrainedfilestream.cpp | 20 ++++++---- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index bbe475ff74..2762a1fc95 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -16,7 +16,7 @@ using namespace Misc; ESM_Context ESMReader::getContext() { // Update the file position before returning - mCtx.filePos = mEsm->tell(); + mCtx.filePos = mEsm->tellg(); return mCtx; } @@ -44,12 +44,12 @@ void ESMReader::restoreContext(const ESM_Context &rc) mCtx = rc; // Make sure we seek to the right place - mEsm->seek(mCtx.filePos); + mEsm->seekg(mCtx.filePos); } void ESMReader::close() { - mEsm.setNull(); + mEsm.reset(); mCtx.filename.clear(); mCtx.leftFile = 0; mCtx.leftRec = 0; @@ -59,15 +59,22 @@ void ESMReader::close() mCtx.subName.val = 0; } -void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) +void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) { close(); mEsm = _esm; mCtx.filename = name; - mCtx.leftFile = mEsm->size(); + mEsm->seekg(0, mEsm->end); + mCtx.leftFile = mEsm->tellg(); + mEsm->seekg(0, mEsm->beg); } -void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) +void ESMReader::openRaw(const std::string& filename) +{ + openRaw(Files::openConstrainedFileStream(filename.c_str()), filename); +} + +void ESMReader::open(Files::IStreamPtr _esm, const std::string &name) { openRaw(_esm, name); @@ -81,12 +88,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(const std::string &file) { - open (openConstrainedFileDataStream (file.c_str ()), file); -} - -void ESMReader::openRaw(const std::string &file) -{ - openRaw (openConstrainedFileDataStream (file.c_str ()), file); + open (Files::openConstrainedFileStream (file.c_str ()), file); } int64_t ESMReader::getHNLong(const char *name) @@ -296,9 +298,7 @@ void ESMReader::getExact(void*x, int size) { try { - int t = mEsm->read(x, size); - if (t != size) - fail("Read error"); + mEsm->read((char*)x, size); } catch (std::exception& e) { @@ -340,8 +340,8 @@ 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.isNull()) - ss << "\n Offset: 0x" << hex << mEsm->tell(); + if (mEsm.get()) + ss << "\n Offset: 0x" << hex << mEsm->tellg(); throw std::runtime_error(ss.str()); } @@ -350,4 +350,14 @@ void ESMReader::setEncoder(ToUTF8::Utf8Encoder* encoder) mEncoder = encoder; } +size_t ESMReader::getFileOffset() +{ + return mEsm->tellg(); +} + +void ESMReader::skip(int bytes) +{ + mEsm->seekg(getFileOffset()+bytes); +} + } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index ebbc935f6f..31fc3e32df 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include @@ -63,20 +63,18 @@ public: /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(Ogre::DataStreamPtr _esm, const std::string &name); + void openRaw(Files::IStreamPtr _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(Ogre::DataStreamPtr _esm, const std::string &name); + void open(Files::IStreamPtr _esm, const std::string &name); void open(const std::string &file); - void openRaw(const std::string &file); + void openRaw(const std::string &filename); - /// Get the file size. Make sure that the file has been opened! - size_t getFileSize() { return mEsm->size(); } /// Get the current position in the file. Make sure that the file has been opened! - size_t getFileOffset() { return mEsm->tell(); } + size_t getFileOffset(); // This is a quick hack for multiple esm/esp files. Each plugin introduces its own // terrain palette, but ESMReader does not pass a reference to the correct plugin @@ -252,8 +250,7 @@ public: // them from native encoding to UTF8 in the process. std::string getString(int size); - void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } - uint64_t getOffset() { return mEsm->tell(); } + void skip(int bytes); /// Used for error handling void fail(const std::string &msg); @@ -265,7 +262,7 @@ public: unsigned int getRecordFlags() { return mRecordFlags; } private: - Ogre::DataStreamPtr mEsm; + Files::IStreamPtr mEsm; ESM_Context mCtx; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2df8e66cee..d9eb7290ce 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -4,6 +4,8 @@ #include "esmwriter.hpp" #include "defs.hpp" +#include + namespace ESM { diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index fddfa7e523..23eab20881 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,6 +1,7 @@ #include "constrainedfilestream.hpp" #include +#include #include "lowlevelfile.hpp" @@ -28,6 +29,8 @@ namespace Files if (start != 0) mFile.seek(start); + setg(0,0,0); + mOrigin = start; } @@ -35,11 +38,11 @@ namespace Files { if(gptr() == egptr()) { + size_t toRead = std::min((mOrigin+mSize)-(mFile.tell()), sBufferSize); // Read in the next chunk of data, and set the read pointers on success - size_t got = mFile.read(mBuffer, sBufferSize); // Failure will throw exception in LowLevelFile - /*if(got != -1) */ - setg(&mBuffer[0], &mBuffer[0], mBuffer+got); + size_t got = mFile.read(mBuffer, toRead); + setg(&mBuffer[0], &mBuffer[0], &mBuffer[0]+got); } if(gptr() == egptr()) return traits_type::eof(); @@ -60,7 +63,7 @@ namespace Files newPos = offset; break; case std::ios_base::cur: - newPos = (mFile.tell() - mOrigin) + offset; + newPos = (mFile.tell() - mOrigin - (egptr() - gptr())) + offset; break; case std::ios_base::end: newPos = mSize + offset; @@ -68,9 +71,11 @@ namespace Files default: return traits_type::eof(); } - mFile.seek(mOrigin+newPos); - // EOF handled by exception in LowLevelFile + if (newPos > mSize) + return traits_type::eof(); + + mFile.seek(mOrigin+newPos); // Clear read pointers so underflow() gets called on the next read attempt. setg(0, 0, 0); @@ -83,8 +88,9 @@ namespace Files if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) return traits_type::eof(); - if(pos >= (int)mSize) + if ((size_t)pos > mSize) return traits_type::eof(); + mFile.seek(mOrigin + pos); // Clear read pointers so underflow() gets called on the next read attempt. From 227c7bb55f7c4e8896d15450d8efc8362bd5c795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:14:13 +0100 Subject: [PATCH 0008/1812] esmtool works again --- apps/esmtool/esmtool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 98e18521e0..3347aaf349 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -284,7 +285,7 @@ void printRaw(ESM::ESMReader &esm) esm.getRecHeader(); while(esm.hasMoreSubs()) { - uint64_t offs = esm.getOffset(); + size_t offs = esm.getFileOffset(); esm.getSubName(); esm.skipHSub(); n = esm.retSubName(); From da690c91b34ed5cede12242b0e20a7d60dffa634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 14:19:00 +0100 Subject: [PATCH 0009/1812] Delete the old Ogre DataStream class --- components/CMakeLists.txt | 2 +- components/esm/esmreader.cpp | 3 +- .../files/constrainedfiledatastream.cpp | 182 ------------------ .../files/constrainedfiledatastream.hpp | 8 - 4 files changed, 2 insertions(+), 193 deletions(-) delete mode 100644 components/files/constrainedfiledatastream.cpp delete mode 100644 components/files/constrainedfiledatastream.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ecaeb115b8..43fca28e88 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -79,7 +79,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - constrainedfiledatastream lowlevelfile constrainedfilestream + lowlevelfile constrainedfilestream ) add_component_dir (compiler diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2762a1fc95..933d890994 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,7 +1,6 @@ #include "esmreader.hpp" -#include -#include "../files/constrainedfiledatastream.hpp" +#include namespace ESM { diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp deleted file mode 100644 index d4d7c231a4..0000000000 --- a/components/files/constrainedfiledatastream.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "constrainedfiledatastream.hpp" -#include "lowlevelfile.hpp" - -#include -#include - -#include - -namespace { - -class ConstrainedDataStream : public Ogre::DataStream { -public: - - static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any - static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call - - ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) - : Ogre::DataStream(fname) - { - mFile.open (fname.c_str ()); - mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; - - mPos = 0; - mOrigin = start; - mExtent = start + mSize; - - mBufferOrigin = 0; - mBufferExtent = 0; - } - - - size_t read(void* buf, size_t count) - { - try - { - assert (mPos <= mSize); - - uint8_t * out = reinterpret_cast (buf); - - size_t posBeg = mOrigin + mPos; - size_t posEnd = posBeg + count; - - if (posEnd > mExtent) - posEnd = mExtent; - - size_t posCur = posBeg; - - while (posCur != posEnd) - { - size_t readLeft = posEnd - posCur; - - if (posCur < mBufferOrigin || posCur >= mBufferExtent) - { - if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent)) - { - assert (mFile.tell () == mBufferExtent); - - if (posCur != mBufferExtent) - mFile.seek (posCur); - - posCur += mFile.read (out, readLeft); - - mBufferOrigin = mBufferExtent = posCur; - - mPos = posCur - mOrigin; - - return posCur - posBeg; - } - else - { - size_t newBufferOrigin; - - if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize)) - newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0); - else - newBufferOrigin = posCur; - - fill (newBufferOrigin); - } - } - - size_t xfer = std::min (readLeft, mBufferExtent - posCur); - - memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer); - - posCur += xfer; - out += xfer; - } - - count = posEnd - posBeg; - mPos += count; - return count; - } - catch (std::exception& e) - { - std::stringstream error; - error << "Failed to read '" << mName << "': " << e.what(); - throw std::runtime_error(error.str()); - } - } - - void skip(long count) - { - assert (mPos <= mSize); - - if((count >= 0 && (size_t)count <= mSize-mPos) || - (count < 0 && (size_t)-count <= mPos)) - mPos += count; - } - - void seek(size_t pos) - { - assert (mPos <= mSize); - - if (pos < mSize) - mPos = pos; - } - - virtual size_t tell() const - { - assert (mPos <= mSize); - - return mPos; - } - - virtual bool eof() const - { - assert (mPos <= mSize); - - return mPos == mSize; - } - - virtual void close() - { - mFile.close(); - } - -private: - - void fill (size_t newOrigin) - { - assert (mFile.tell () == mBufferExtent); - - size_t newExtent = newOrigin + sBufferSize; - - if (newExtent > mExtent) - newExtent = mExtent; - - size_t oldExtent = mBufferExtent; - - if (newOrigin != oldExtent) - mFile.seek (newOrigin); - - mBufferOrigin = mBufferExtent = newOrigin; - - size_t amountRequested = newExtent - newOrigin; - - size_t amountRead = mFile.read (mBuffer, amountRequested); - - if (amountRead != amountRequested) - throw std::runtime_error ("An unexpected condition occurred while reading from a file."); - - mBufferExtent = newExtent; - } - - LowLevelFile mFile; - - size_t mOrigin; - size_t mExtent; - size_t mPos; - - uint8_t mBuffer [sBufferSize]; - size_t mBufferOrigin; - size_t mBufferExtent; -}; - -} // end of unnamed namespace - -Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length) -{ - return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); -} diff --git a/components/files/constrainedfiledatastream.hpp b/components/files/constrainedfiledatastream.hpp deleted file mode 100644 index 367defcbcb..0000000000 --- a/components/files/constrainedfiledatastream.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP -#define COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP - -#include - -Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset = 0, size_t length = 0xFFFFFFFF); - -#endif // COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP From 6b36e55a4e78df0a7e996bd8dfa55895ce78e15e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 19:17:03 +0100 Subject: [PATCH 0010/1812] NIF reader cleanup: move definitions to cpp file --- components/nif/base.hpp | 22 +--- components/nif/controlled.hpp | 78 ++----------- components/nif/controller.hpp | 182 +++-------------------------- components/nif/data.cpp | 209 +++++++++++++++++++++++++++++++++ components/nif/data.hpp | 210 +++------------------------------- components/nif/effect.hpp | 52 +-------- components/nif/extra.hpp | 35 +----- components/nif/nifkey.hpp | 4 + components/nif/property.hpp | 109 ++---------------- components/nif/record.hpp | 6 - 10 files changed, 274 insertions(+), 633 deletions(-) diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 30c652b64b..4b2e40dec0 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -32,26 +32,8 @@ public: float timeStart, timeStop; ControlledPtr target; - void read(NIFStream *nif) - { - next.read(nif); - - flags = nif->getUShort(); - - frequency = nif->getFloat(); - phase = nif->getFloat(); - timeStart = nif->getFloat(); - timeStop = nif->getFloat(); - - target.read(nif); - } - - void post(NIFFile *nif) - { - Record::post(nif); - next.post(nif); - target.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; /// Anything that has a controller diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 51890f0698..ac75c35086 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -62,31 +62,8 @@ public: */ int alpha; - void read(NIFStream *nif) - { - Named::read(nif); - - external = !!nif->getChar(); - if(external) - filename = nif->getString(); - else - { - nif->getChar(); // always 1 - data.read(nif); - } - - pixel = nif->getInt(); - mipmap = nif->getInt(); - alpha = nif->getInt(); - - nif->getChar(); // always 1 - } - - void post(NIFFile *nif) - { - Named::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiParticleGrowFade : public Controlled @@ -95,12 +72,7 @@ public: float growTime; float fadeTime; - void read(NIFStream *nif) - { - Controlled::read(nif); - growTime = nif->getFloat(); - fadeTime = nif->getFloat(); - } + void read(NIFStream *nif); }; class NiParticleColorModifier : public Controlled @@ -108,17 +80,8 @@ class NiParticleColorModifier : public Controlled public: NiColorDataPtr data; - void read(NIFStream *nif) - { - Controlled::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controlled::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiGravity : public Controlled @@ -132,45 +95,20 @@ public: osg::Vec3f mPosition; osg::Vec3f mDirection; - void read(NIFStream *nif) - { - Controlled::read(nif); - - /*unknown*/nif->getFloat(); - mForce = nif->getFloat(); - mType = nif->getUInt(); - mPosition = nif->getVector3(); - mDirection = nif->getVector3(); - } + void read(NIFStream *nif); }; // NiPinaColada class NiPlanarCollider : public Controlled { public: - void read(NIFStream *nif) - { - Controlled::read(nif); - - // (I think) 4 floats + 4 vectors - nif->skip(4*16); - } + void read(NIFStream *nif); }; class NiParticleRotation : public Controlled { public: - void read(NIFStream *nif) - { - Controlled::read(nif); - - /* - byte (0 or 1) - float (1) - float*3 - */ - nif->skip(17); - } + void read(NIFStream *nif); }; diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 718748c31e..73344e77bf 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -74,66 +74,8 @@ public: ExtraPtr extra; - void read(NIFStream *nif) - { - Controller::read(nif); - - velocity = nif->getFloat(); - velocityRandom = nif->getFloat(); - verticalDir = nif->getFloat(); - verticalAngle = nif->getFloat(); - horizontalDir = nif->getFloat(); - horizontalAngle = nif->getFloat(); - /*normal?*/ nif->getVector3(); - /*color?*/ nif->getVector4(); - size = nif->getFloat(); - startTime = nif->getFloat(); - stopTime = nif->getFloat(); - nif->getChar(); - emitRate = nif->getFloat(); - lifetime = nif->getFloat(); - lifetimeRandom = nif->getFloat(); - - emitFlags = nif->getUShort(); - offsetRandom = nif->getVector3(); - - emitter.read(nif); - - /* Unknown Short, 0? - * Unknown Float, 1.0? - * Unknown Int, 1? - * Unknown Int, 0? - * Unknown Short, 0? - */ - nif->skip(16); - - numParticles = nif->getUShort(); - activeCount = nif->getUShort(); - - particles.resize(numParticles); - for(size_t i = 0;i < particles.size();i++) - { - particles[i].velocity = nif->getVector3(); - nif->getVector3(); /* unknown */ - particles[i].lifetime = nif->getFloat(); - particles[i].lifespan = nif->getFloat(); - particles[i].timestamp = nif->getFloat(); - nif->getUShort(); /* unknown */ - particles[i].vertex = nif->getUShort(); - } - - nif->getUInt(); /* -1? */ - extra.read(nif); - nif->getUInt(); /* -1? */ - nif->getChar(); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - emitter.post(nif); - extra.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; typedef NiParticleSystemController NiBSPArrayController; @@ -142,17 +84,8 @@ class NiMaterialColorController : public Controller public: NiPosDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiPathController : public Controller @@ -161,27 +94,8 @@ public: NiPosDataPtr posData; NiFloatDataPtr floatData; - void read(NIFStream *nif) - { - Controller::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); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiUVController : public Controller @@ -189,19 +103,8 @@ class NiUVController : public Controller public: NiUVDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - - nif->getUShort(); // always 0 - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiKeyframeController : public Controller @@ -209,17 +112,8 @@ class NiKeyframeController : public Controller public: NiKeyframeDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiAlphaController : public Controller @@ -227,17 +121,8 @@ class NiAlphaController : public Controller public: NiFloatDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiGeomMorpherController : public Controller @@ -245,18 +130,8 @@ class NiGeomMorpherController : public Controller public: NiMorphDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - nif->getChar(); // always 0 - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiVisController : public Controller @@ -264,17 +139,8 @@ class NiVisController : public Controller public: NiVisDataPtr data; - void read(NIFStream *nif) - { - Controller::read(nif); - data.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - data.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiFlipController : public Controller @@ -284,20 +150,8 @@ public: float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources NiSourceTextureList mSources; - void read(NIFStream *nif) - { - Controller::read(nif); - mTexSlot = nif->getUInt(); - /*unknown=*/nif->getUInt();/*0?*/ - mDelta = nif->getFloat(); - mSources.read(nif); - } - - void post(NIFFile *nif) - { - Controller::post(nif); - mSources.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; } // Namespace diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 4248b93d2f..c4de1e1bfa 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -3,6 +3,13 @@ namespace Nif { +void NiSkinInstance::read(NIFStream *nif) +{ + data.read(nif); + root.read(nif); + bones.read(nif); +} + void NiSkinInstance::post(NIFFile *nif) { data.post(nif); @@ -26,4 +33,206 @@ void NiSkinInstance::post(NIFFile *nif) } } +void ShapeData::read(NIFStream *nif) +{ + int verts = nif->getUShort(); + + if(nif->getInt()) + nif->getVector3s(vertices, verts); + + if(nif->getInt()) + nif->getVector3s(normals, verts); + + center = nif->getVector3(); + radius = nif->getFloat(); + + if(nif->getInt()) + nif->getVector4s(colors, verts); + + // 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; + + if(nif->getInt()) + { + uvlist.resize(uvs); + for(int i = 0;i < uvs;i++) + nif->getVector2s(uvlist[i], verts); + } +} + +void NiTriShapeData::read(NIFStream *nif) +{ + ShapeData::read(nif); + + /*int tris =*/ nif->getUShort(); + + // 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->getUShort(); + for(int i=0;i < verts;i++) + { + // Number of vertices matching vertex 'i' + int num = nif->getUShort(); + nif->skip(num * sizeof(short)); + } +} + +void NiAutoNormalParticlesData::read(NIFStream *nif) +{ + ShapeData::read(nif); + + // Should always match the number of vertices + numParticles = nif->getUShort(); + + particleRadius = nif->getFloat(); + activeCount = nif->getUShort(); + + if(nif->getInt()) + { + // Particle sizes + nif->getFloats(sizes, vertices.size()); + } +} + +void NiRotatingParticlesData::read(NIFStream *nif) +{ + NiAutoNormalParticlesData::read(nif); + + if(nif->getInt()) + { + // Rotation quaternions. + nif->getQuaternions(rotations, vertices.size()); + } +} + +void NiPosData::read(NIFStream *nif) +{ + mKeyList.read(nif); +} + +void NiUVData::read(NIFStream *nif) +{ + for(int i = 0;i < 4;i++) + mKeyList[i].read(nif); +} + +void NiFloatData::read(NIFStream *nif) +{ + mKeyList.read(nif); +} + +void NiPixelData::read(NIFStream *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 + + bpp = nif->getInt(); + + // Unknown + nif->skip(12); + + mips = 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(); + } + + // Skip the data + unsigned int dataSize = nif->getInt(); + nif->skip(dataSize); +} + +void NiColorData::read(NIFStream *nif) +{ + mKeyMap.read(nif); +} + +void NiVisData::read(NIFStream *nif) +{ + int count = nif->getInt(); + mVis.resize(count); + for(size_t i = 0;i < mVis.size();i++) + { + mVis[i].time = nif->getFloat(); + mVis[i].isSet = nif->getChar(); + } +} + +void NiSkinData::read(NIFStream *nif) +{ + trafo.rotation = nif->getMatrix3(); + trafo.pos = nif->getVector3(); + trafo.scale = nif->getFloat(); + + int boneNum = nif->getInt(); + nif->getInt(); // -1 + + bones.resize(boneNum); + for(int i=0;igetMatrix3(); + bi.trafo.pos = 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(); + } + } +} + +void NiMorphData::read(NIFStream *nif) +{ + int morphCount = nif->getInt(); + int vertCount = nif->getInt(); + /*relative targets?*/nif->getChar(); + + mMorphs.resize(morphCount); + for(int i = 0;i < morphCount;i++) + { + mMorphs[i].mData.read(nif, true); + nif->getVector3s(mMorphs[i].mVertices, vertCount); + } +} + +void NiKeyframeData::read(NIFStream *nif) +{ + mRotations.read(nif); + if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) + { + //Chomp unused float + nif->getFloat(); + mXRotations.read(nif, true); + mYRotations.read(nif, true); + mZRotations.read(nif, true); + } + mTranslations.read(nif); + mScales.read(nif); +} + } // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 656d27628c..3b12448314 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -41,34 +41,7 @@ public: osg::Vec3f center; float radius; - void read(NIFStream *nif) - { - int verts = nif->getUShort(); - - if(nif->getInt()) - nif->getVector3s(vertices, verts); - - if(nif->getInt()) - nif->getVector3s(normals, verts); - - center = nif->getVector3(); - radius = nif->getFloat(); - - if(nif->getInt()) - nif->getVector4s(colors, verts); - - // 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; - - if(nif->getInt()) - { - uvlist.resize(uvs); - for(int i = 0;i < uvs;i++) - nif->getVector2s(uvlist[i], verts); - } - } + void read(NIFStream *nif); }; class NiTriShapeData : public ShapeData @@ -77,28 +50,7 @@ public: // Triangles, three vertex indices per triangle std::vector triangles; - void read(NIFStream *nif) - { - ShapeData::read(nif); - - /*int tris =*/ nif->getUShort(); - - // 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->getUShort(); - for(int i=0;i < verts;i++) - { - // Number of vertices matching vertex 'i' - int num = nif->getUShort(); - nif->skip(num * sizeof(short)); - } - } + void read(NIFStream *nif); }; class NiAutoNormalParticlesData : public ShapeData @@ -112,22 +64,7 @@ public: std::vector sizes; - void read(NIFStream *nif) - { - ShapeData::read(nif); - - // Should always match the number of vertices - numParticles = nif->getUShort(); - - particleRadius = nif->getFloat(); - activeCount = nif->getUShort(); - - if(nif->getInt()) - { - // Particle sizes - nif->getFloats(sizes, vertices.size()); - } - } + void read(NIFStream *nif); }; class NiRotatingParticlesData : public NiAutoNormalParticlesData @@ -135,16 +72,7 @@ class NiRotatingParticlesData : public NiAutoNormalParticlesData public: std::vector rotations; - void read(NIFStream *nif) - { - NiAutoNormalParticlesData::read(nif); - - if(nif->getInt()) - { - // Rotation quaternions. - nif->getQuaternions(rotations, vertices.size()); - } - } + void read(NIFStream *nif); }; class NiPosData : public Record @@ -152,10 +80,7 @@ class NiPosData : public Record public: Vector3KeyMap mKeyList; - void read(NIFStream *nif) - { - mKeyList.read(nif); - } + void read(NIFStream *nif); }; class NiUVData : public Record @@ -163,11 +88,7 @@ class NiUVData : public Record public: FloatKeyMap mKeyList[4]; - void read(NIFStream *nif) - { - for(int i = 0;i < 4;i++) - mKeyList[i].read(nif); - } + void read(NIFStream *nif); }; class NiFloatData : public Record @@ -175,10 +96,7 @@ class NiFloatData : public Record public: FloatKeyMap mKeyList; - void read(NIFStream *nif) - { - mKeyList.read(nif); - } + void read(NIFStream *nif); }; class NiPixelData : public Record @@ -187,37 +105,7 @@ public: unsigned int rmask, gmask, bmask, amask; int bpp, mips; - void read(NIFStream *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 - - bpp = nif->getInt(); - - // Unknown - nif->skip(12); - - mips = 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(); - } - - // Skip the data - unsigned int dataSize = nif->getInt(); - nif->skip(dataSize); - } + void read(NIFStream *nif); }; class NiColorData : public Record @@ -225,10 +113,7 @@ class NiColorData : public Record public: Vector4KeyMap mKeyMap; - void read(NIFStream *nif) - { - mKeyMap.read(nif); - } + void read(NIFStream *nif); }; class NiVisData : public Record @@ -240,16 +125,7 @@ public: }; std::vector mVis; - void read(NIFStream *nif) - { - int count = nif->getInt(); - mVis.resize(count); - for(size_t i = 0;i < mVis.size();i++) - { - mVis[i].time = nif->getFloat(); - mVis[i].isSet = nif->getChar(); - } - } + void read(NIFStream *nif); }; class NiSkinInstance : public Record @@ -259,13 +135,7 @@ public: NodePtr root; NodeList bones; - void read(NIFStream *nif) - { - data.read(nif); - root.read(nif); - bones.read(nif); - } - + void read(NIFStream *nif); void post(NIFFile *nif); }; @@ -288,34 +158,7 @@ public: Transformation trafo; std::vector bones; - void read(NIFStream *nif) - { - trafo.rotation = nif->getMatrix3(); - trafo.pos = nif->getVector3(); - trafo.scale = nif->getFloat(); - - int boneNum = nif->getInt(); - nif->getInt(); // -1 - - bones.resize(boneNum); - for(int i=0;igetMatrix3(); - bi.trafo.pos = 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(); - } - } - } + void read(NIFStream *nif); }; struct NiMorphData : public Record @@ -326,19 +169,7 @@ struct NiMorphData : public Record }; std::vector mMorphs; - void read(NIFStream *nif) - { - int morphCount = nif->getInt(); - int vertCount = nif->getInt(); - /*relative targets?*/nif->getChar(); - - mMorphs.resize(morphCount); - for(int i = 0;i < morphCount;i++) - { - mMorphs[i].mData.read(nif, true); - nif->getVector3s(mMorphs[i].mVertices, vertCount); - } - } + void read(NIFStream *nif); }; @@ -353,20 +184,7 @@ struct NiKeyframeData : public Record Vector3KeyMap mTranslations; FloatKeyMap mScales; - void read(NIFStream *nif) - { - mRotations.read(nif); - if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) - { - //Chomp unused float - nif->getFloat(); - mXRotations.read(nif, true); - mYRotations.read(nif, true); - mZRotations.read(nif, true); - } - mTranslations.read(nif); - mScales.read(nif); - } + void read(NIFStream *nif); }; } // Namespace diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 679557e257..fae1cd7f58 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -42,63 +42,19 @@ struct NiLight : Effect osg::Vec3f diffuse; osg::Vec3f specular; - void read(NIFStream *nif) - { - dimmer = nif->getFloat(); - ambient = nif->getVector3(); - diffuse = nif->getVector3(); - specular = nif->getVector3(); - } + void read(NIFStream *nif); }; SLight light; - void read(NIFStream *nif) - { - Effect::read(nif); - - nif->getInt(); // 1 - nif->getInt(); // 1? - light.read(nif); - } + void read(NIFStream *nif); }; struct NiTextureEffect : Effect { NiSourceTexturePtr texture; - void read(NIFStream *nif) - { - Effect::read(nif); - - 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); - - texture.read(nif); - - /* - 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); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; } // Namespace diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 2913c62b0b..1e5a8616de 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -32,17 +32,7 @@ namespace Nif class NiVertWeightsExtraData : public Extra { public: - void read(NIFStream *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->getUShort(); - - nif->skip(s * sizeof(float)); // vertex weights I guess - } + void read(NIFStream *nif); }; class NiTextKeyExtraData : public Extra @@ -55,20 +45,7 @@ public: }; std::vector list; - void read(NIFStream *nif) - { - Extra::read(nif); - - nif->getInt(); // 0 - - int keynum = nif->getInt(); - list.resize(keynum); - for(int i=0; igetFloat(); - list[i].text = nif->getString(); - } - } + void read(NIFStream *nif); }; class NiStringExtraData : public Extra @@ -80,13 +57,7 @@ public: */ std::string string; - void read(NIFStream *nif) - { - Extra::read(nif); - - nif->getInt(); // size of string + 4. Really useful... - string = nif->getString(); - } + void read(NIFStream *nif); }; } // Namespace diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index b8b01513bd..549ea3eb38 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -24,6 +24,10 @@ struct KeyT { float mContinuity; // Only for TBC interpolation */ }; +typedef KeyT FloatKey; +typedef KeyT Vector3Key; +typedef KeyT Vector4Key; +typedef KeyT QuaternionKey; template struct KeyMapT { diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 610f5427ab..b06044e9f0 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -26,9 +26,6 @@ #include "base.hpp" -#include "controlled.hpp" -#include "data.hpp" - namespace Nif { @@ -38,11 +35,7 @@ public: // The meaning of these depends on the actual property type. int flags; - void read(NIFStream *nif) - { - Named::read(nif); - flags = nif->getUShort(); - } + void read(NIFStream *nif); }; class NiTexturingProperty : public Property @@ -70,26 +63,8 @@ public: int clamp, uvSet, filter; short unknown2; - void read(NIFStream *nif) - { - inUse = !!nif->getInt(); - if(!inUse) return; - - texture.read(nif); - clamp = nif->getInt(); - filter = nif->getInt(); - uvSet = nif->getInt(); - - // I have no idea, but I think these are actually two - // PS2-specific shorts (ps2L and ps2K), followed by an unknown - // short. - nif->skip(6); - } - - void post(NIFFile *nif) - { - texture.post(nif); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; /* Apply mode: @@ -120,42 +95,14 @@ public: GlossTexture = 3, GlowTexture = 4, BumpTexture = 5, - DecalTexture = 6 + DecalTexture = 6, + NumTextures = 7 // Sentry value }; Texture textures[7]; - void read(NIFStream *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); - } + void read(NIFStream *nif); + void post(NIFFile *nif); }; class NiFogProperty : public Property @@ -164,14 +111,7 @@ public: float mFogDepth; osg::Vec3f mColour; - - void read(NIFStream *nif) - { - Property::read(nif); - - mFogDepth = nif->getFloat(); - mColour = nif->getVector3(); - } + void read(NIFStream *nif); }; // These contain no other data than the 'flags' field in Property @@ -200,15 +140,7 @@ struct S_MaterialProperty osg::Vec3f ambient, diffuse, specular, emissive; float glossiness, alpha; - void read(NIFStream *nif) - { - ambient = nif->getVector3(); - diffuse = nif->getVector3(); - specular = nif->getVector3(); - emissive = nif->getVector3(); - glossiness = nif->getFloat(); - alpha = nif->getFloat(); - } + void read(NIFStream *nif); }; struct S_VertexColorProperty @@ -224,11 +156,7 @@ struct S_VertexColorProperty */ int vertmode, lightmode; - void read(NIFStream *nif) - { - vertmode = nif->getInt(); - lightmode = nif->getInt(); - } + void read(NIFStream *nif); }; struct S_AlphaProperty @@ -273,10 +201,7 @@ struct S_AlphaProperty // Tested against when certain flags are set (see above.) unsigned char threshold; - void read(NIFStream *nif) - { - threshold = nif->getChar(); - } + void read(NIFStream *nif); }; /* @@ -322,17 +247,7 @@ struct S_StencilProperty */ int drawMode; - void read(NIFStream *nif) - { - enabled = nif->getChar(); - compareFunc = nif->getInt(); - stencilRef = nif->getUInt(); - stencilMask = nif->getUInt(); - failAction = nif->getInt(); - zFailAction = nif->getInt(); - zPassAction = nif->getInt(); - drawMode = nif->getInt(); - } + void read(NIFStream *nif); }; class NiAlphaProperty : public StructPropT { }; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 07d7540f85..1022802cc4 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -110,12 +110,6 @@ struct Record 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); - */ }; } // Namespace From 8e01d8cb19a9136470c86ba02d9f3b8b883753c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:06:10 +0100 Subject: [PATCH 0011/1812] Add OSG nifloader, currently supports geometry, materials, basic texturing, skinning, morphing, and most controllers. --- CMakeLists.txt | 4 +- apps/nifosgtest/CMakeLists.txt | 7 + apps/nifosgtest/test.cpp | 100 ++++ components/CMakeLists.txt | 4 + components/nif/controlled.cpp | 88 ++++ components/nif/controller.cpp | 203 +++++++++ components/nif/effect.cpp | 61 +++ components/nif/extra.cpp | 43 ++ components/nif/property.cpp | 111 +++++ components/nifosg/controller.cpp | 275 +++++++++++ components/nifosg/controller.hpp | 214 +++++++++ components/nifosg/nifloader.cpp | 759 +++++++++++++++++++++++++++++++ components/nifosg/nifloader.hpp | 84 ++++ 13 files changed, 1952 insertions(+), 1 deletion(-) create mode 100644 apps/nifosgtest/CMakeLists.txt create mode 100644 apps/nifosgtest/test.cpp create mode 100644 components/nif/controlled.cpp create mode 100644 components/nif/controller.cpp create mode 100644 components/nif/effect.cpp create mode 100644 components/nif/extra.cpp create mode 100644 components/nif/property.cpp create mode 100644 components/nifosg/controller.cpp create mode 100644 components/nifosg/controller.hpp create mode 100644 components/nifosg/nifloader.cpp create mode 100644 components/nifosg/nifloader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cbe142fcc2..d5b37a05bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) @@ -592,6 +592,8 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools +add_subdirectory( apps/nifosgtest ) + if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt new file mode 100644 index 0000000000..265577d989 --- /dev/null +++ b/apps/nifosgtest/CMakeLists.txt @@ -0,0 +1,7 @@ +set (FILES + test.cpp +) + +add_executable (test ${FILES}) + +target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp new file mode 100644 index 0000000000..fc82059fc7 --- /dev/null +++ b/apps/nifosgtest/test.cpp @@ -0,0 +1,100 @@ +#include + +#include +#include + +#include + +#include + +#include +#include + +#include + +// EventHandler to toggle wireframe when 'w' key is pressed +class EventHandler : public osgGA::GUIEventHandler +{ +public: + EventHandler(osg::Node* node) + : mWireframe(false) + , mNode(node) + { + + } + + virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) + { + switch (adapter.getEventType()) + { + case osgGA::GUIEventAdapter::KEYDOWN: + if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) + { + mWireframe = !mWireframe; + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + return true; + } + default: + break; + } + return false; + } + +private: + bool mWireframe; + osg::Node* mNode; +}; + +int main(int argc, char** argv) +{ + if (argc < 3) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + Bsa::BSAFile bsa; + bsa.open(argv[1]); + + Nif::NIFFilePtr nif(new Nif::NIFFile(bsa.getFile(argv[2]), std::string(argv[2]))); + + osgViewer::Viewer viewer; + + osg::ref_ptr root(new osg::Group()); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + // To prevent lighting issues with scaled meshes + root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + osg::Group* newNode = new osg::Group; + NifOsg::Loader loader; + loader.resourceManager = &bsa; + loader.loadAsSkeleton(nif, newNode); + + //osgDB::writeNodeFile(*newNode, "out.osg"); + + for (int x=0; x<1;++x) + { + root->addChild(newNode); + } + + viewer.setSceneData(root); + + viewer.setUpViewInWindow(0, 0, 800, 600); + viewer.realize(); + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); + viewer.addEventHandler(new EventHandler(root)); + + while (!viewer.done()) + { + viewer.frame(); + + for (unsigned int i=0; igetChar(); + if(external) + filename = nif->getString(); + else + { + nif->getChar(); // always 1 + data.read(nif); + } + + pixel = nif->getInt(); + mipmap = nif->getInt(); + alpha = nif->getInt(); + + nif->getChar(); // always 1 + } + + void NiSourceTexture::post(NIFFile *nif) + { + Named::post(nif); + data.post(nif); + } + + void NiParticleGrowFade::read(NIFStream *nif) + { + Controlled::read(nif); + growTime = nif->getFloat(); + fadeTime = nif->getFloat(); + } + + void NiParticleColorModifier::read(NIFStream *nif) + { + Controlled::read(nif); + data.read(nif); + } + + void NiParticleColorModifier::post(NIFFile *nif) + { + Controlled::post(nif); + data.post(nif); + } + + void NiGravity::read(NIFStream *nif) + { + Controlled::read(nif); + + /*unknown*/nif->getFloat(); + mForce = nif->getFloat(); + mType = nif->getUInt(); + mPosition = nif->getVector3(); + mDirection = nif->getVector3(); + } + + void NiPlanarCollider::read(NIFStream *nif) + { + Controlled::read(nif); + + // (I think) 4 floats + 4 vectors + nif->skip(4*16); + } + + void NiParticleRotation::read(NIFStream *nif) + { + Controlled::read(nif); + + /* + byte (0 or 1) + float (1) + float*3 + */ + nif->skip(17); + } + + + + + +} diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp new file mode 100644 index 0000000000..376a1fe123 --- /dev/null +++ b/components/nif/controller.cpp @@ -0,0 +1,203 @@ +#include "controller.hpp" + +#include "node.hpp" +#include "data.hpp" + +namespace Nif +{ + + void Controller::read(NIFStream *nif) + { + next.read(nif); + + flags = nif->getUShort(); + + frequency = nif->getFloat(); + phase = nif->getFloat(); + timeStart = nif->getFloat(); + timeStop = nif->getFloat(); + + target.read(nif); + } + + void Controller::post(NIFFile *nif) + { + Record::post(nif); + next.post(nif); + target.post(nif); + } + + void NiParticleSystemController::read(NIFStream *nif) + { + Controller::read(nif); + + velocity = nif->getFloat(); + velocityRandom = nif->getFloat(); + verticalDir = nif->getFloat(); + verticalAngle = nif->getFloat(); + horizontalDir = nif->getFloat(); + horizontalAngle = nif->getFloat(); + /*normal?*/ nif->getVector3(); + /*color?*/ nif->getVector4(); + size = nif->getFloat(); + startTime = nif->getFloat(); + stopTime = nif->getFloat(); + nif->getChar(); + emitRate = nif->getFloat(); + lifetime = nif->getFloat(); + lifetimeRandom = nif->getFloat(); + + emitFlags = nif->getUShort(); + offsetRandom = nif->getVector3(); + + emitter.read(nif); + + /* Unknown Short, 0? + * Unknown Float, 1.0? + * Unknown Int, 1? + * Unknown Int, 0? + * Unknown Short, 0? + */ + nif->skip(16); + + numParticles = nif->getUShort(); + activeCount = nif->getUShort(); + + particles.resize(numParticles); + for(size_t i = 0;i < particles.size();i++) + { + particles[i].velocity = nif->getVector3(); + nif->getVector3(); /* unknown */ + particles[i].lifetime = nif->getFloat(); + particles[i].lifespan = nif->getFloat(); + particles[i].timestamp = nif->getFloat(); + nif->getUShort(); /* unknown */ + particles[i].vertex = nif->getUShort(); + } + + nif->getUInt(); /* -1? */ + extra.read(nif); + nif->getUInt(); /* -1? */ + nif->getChar(); + } + + void NiParticleSystemController::post(NIFFile *nif) + { + Controller::post(nif); + emitter.post(nif); + extra.post(nif); + } + + void NiMaterialColorController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiMaterialColorController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiPathController::read(NIFStream *nif) + { + Controller::read(nif); + + /* + int = 1 + 2xfloat + short = 0 or 1 + */ + nif->skip(14); + posData.read(nif); + floatData.read(nif); + } + + void NiPathController::post(NIFFile *nif) + { + Controller::post(nif); + + posData.post(nif); + floatData.post(nif); + } + + void NiUVController::read(NIFStream *nif) + { + Controller::read(nif); + + nif->getUShort(); // always 0 + data.read(nif); + } + + void NiUVController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiKeyframeController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiKeyframeController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiAlphaController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiAlphaController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiGeomMorpherController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + nif->getChar(); // always 0 + } + + void NiGeomMorpherController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiVisController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiVisController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + + void NiFlipController::read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void NiFlipController::post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } + +} diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp new file mode 100644 index 0000000000..41dcb09de9 --- /dev/null +++ b/components/nif/effect.cpp @@ -0,0 +1,61 @@ +#include "effect.hpp" + +#include "node.hpp" + +namespace Nif +{ + +void NiLight::SLight::read(NIFStream *nif) +{ + dimmer = nif->getFloat(); + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); +} + +void NiLight::read(NIFStream *nif) +{ + Effect::read(nif); + + nif->getInt(); // 1 + nif->getInt(); // 1? + light.read(nif); +} + +void NiTextureEffect::read(NIFStream *nif) +{ + Effect::read(nif); + + 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); + + texture.read(nif); + + /* + byte = 0 + vector4 = [1,0,0,0] + short = 0 + short = -75 + short = 0 + */ + nif->skip(23); +} + +void NiTextureEffect::post(NIFFile *nif) +{ + Effect::post(nif); + texture.post(nif); +} + + + +} diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp new file mode 100644 index 0000000000..b7e2216688 --- /dev/null +++ b/components/nif/extra.cpp @@ -0,0 +1,43 @@ +#include "extra.hpp" + +namespace Nif +{ + +void NiStringExtraData::read(NIFStream *nif) +{ + Extra::read(nif); + + nif->getInt(); // size of string + 4. Really useful... + string = nif->getString(); +} + +void NiTextKeyExtraData::read(NIFStream *nif) +{ + Extra::read(nif); + + nif->getInt(); // 0 + + int keynum = nif->getInt(); + list.resize(keynum); + for(int i=0; igetFloat(); + list[i].text = nif->getString(); + } +} + +void NiVertWeightsExtraData::read(NIFStream *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->getUShort(); + + nif->skip(s * sizeof(float)); // vertex weights I guess +} + + + +} diff --git a/components/nif/property.cpp b/components/nif/property.cpp new file mode 100644 index 0000000000..47c6d35b31 --- /dev/null +++ b/components/nif/property.cpp @@ -0,0 +1,111 @@ +#include "property.hpp" + +#include "data.hpp" +#include "controlled.hpp" + +namespace Nif +{ + +void Property::read(NIFStream *nif) +{ + Named::read(nif); + flags = nif->getUShort(); +} + +void NiTexturingProperty::Texture::read(NIFStream *nif) +{ + inUse = !!nif->getInt(); + if(!inUse) return; + + texture.read(nif); + clamp = nif->getInt(); + filter = nif->getInt(); + uvSet = nif->getInt(); + + // I have no idea, but I think these are actually two + // PS2-specific shorts (ps2L and ps2K), followed by an unknown + // short. + nif->skip(6); +} + +void NiTexturingProperty::Texture::post(NIFFile *nif) +{ + texture.post(nif); +} + +void NiTexturingProperty::read(NIFStream *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 NiTexturingProperty::post(NIFFile *nif) +{ + Property::post(nif); + for(int i = 0;i < 7;i++) + textures[i].post(nif); +} + +void NiFogProperty::read(NIFStream *nif) +{ + Property::read(nif); + + mFogDepth = nif->getFloat(); + mColour = nif->getVector3(); +} + +void S_MaterialProperty::read(NIFStream *nif) +{ + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); + emissive = nif->getVector3(); + glossiness = nif->getFloat(); + alpha = nif->getFloat(); +} + +void S_VertexColorProperty::read(NIFStream *nif) +{ + vertmode = nif->getInt(); + lightmode = nif->getInt(); +} + +void S_AlphaProperty::read(NIFStream *nif) +{ + threshold = nif->getChar(); +} + +void S_StencilProperty::read(NIFStream *nif) +{ + enabled = nif->getChar(); + compareFunc = nif->getInt(); + stencilRef = nif->getUInt(); + stencilMask = nif->getUInt(); + failAction = nif->getInt(); + zFailAction = nif->getInt(); + zPassAction = nif->getInt(); + drawMode = nif->getInt(); +} + + + +} diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp new file mode 100644 index 0000000000..4e600c3a18 --- /dev/null +++ b/components/nifosg/controller.cpp @@ -0,0 +1,275 @@ +#include "controller.hpp" + +#include +#include +#include + +#include + +namespace NifOsg +{ + +float ValueInterpolator::interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def) const +{ + if (keys.size() == 0) + return def; + + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::FloatKey* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::FloatKeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::FloatKey* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +osg::Vec3f ValueInterpolator::interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::Vector3KeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) + : mDeltaInput(deltaInput) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + , mDeltaCount(0.f) +{ + if(mDeltaInput) + mDeltaCount = mPhase; +} + +float ControllerFunction::calculate(float value) +{ + if(mDeltaInput) + { + if (mStopTime - mStartTime == 0.f) + return 0.f; + + mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + + value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); + return value; +} + +osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::QuaternionKey* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::QuaternionKeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::QuaternionKey* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + + osg::Quat v1 = aLastKey->mValue; + osg::Quat v2 = aKey->mValue; + // don't take the long path + if (v1.x()*v2.x() + v1.y()*v2.y() + v1.z()*v2.z() + v1.w()*v2.w() < 0) // dotProduct(v1,v2) + v1 = -v1; + + osg::Quat result; + result.slerp(a, v1, v2); + return result; + } + else + return keys.rbegin()->second.mValue; +} + +osg::Quat KeyframeController::Value::getXYZRotation(float time) const +{ + float xrot = interpKey(mXRotations->mKeys, time); + float yrot = interpKey(mYRotations->mKeys, time); + float zrot = interpKey(mZRotations->mKeys, time); + osg::Quat xr(xrot, osg::Vec3f(1,0,0)); + osg::Quat yr(yrot, osg::Vec3f(0,1,0)); + osg::Quat zr(zrot, osg::Vec3f(0,0,1)); + return (zr*yr*xr); +} + +KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale) + : NodeTargetValue(target) + , mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) + , mTranslations(&data->mTranslations) + , mScales(&data->mScales) + , mNif(nif) + , mInitialQuat(initialQuat) + , mInitialScale(initialScale) +{ } + +osg::Vec3f KeyframeController::Value::getTranslation(float time) const +{ + if(mTranslations->mKeys.size() > 0) + return interpKey(mTranslations->mKeys, time); + osg::MatrixTransform* trans = static_cast(mNode); + return trans->getMatrix().getTrans(); +} + +void KeyframeController::Value::setValue(float time) +{ + osg::MatrixTransform* trans = static_cast(mNode); + osg::Matrix mat = trans->getMatrix(); + + if(mRotations->mKeys.size() > 0) + mat.setRotate(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mat.setRotate(getXYZRotation(time)); + else + mat.setRotate(mInitialQuat); + + // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) + float scale = mInitialScale; + if(mScales->mKeys.size() > 0) + scale = interpKey(mScales->mKeys, time); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(i,j) *= scale; + + if(mTranslations->mKeys.size() > 0) + mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); +} + +Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) + : mSource(src) + , mDestValue(dest) + , mFunction(function) +{ + +} + +void Controller::update() +{ + if (mSource.get()) + { + mDestValue->setValue(mFunction->calculate(mSource->getValue())); + } +} + +GeomMorpherController::Value::Value(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) + : mGeom(geom) + , mMorphs(morphData->mMorphs) +{ + +} + +void GeomMorpherController::Value::setValue(float time) +{ + if (mMorphs.size() <= 1) + return; + int i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, time); + val = std::max(0.f, std::min(1.f, val)); + + mGeom->setWeight(i, val); + } +} + +UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) + : mStateSet(target) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + , mTextureUnits(textureUnits) +{ +} + +void UVController::Value::setValue(float value) +{ + float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); + float uScale = interpKey(mUScale.mKeys, value, 1.0f); + float vScale = interpKey(mVScale.mKeys, value, 1.0f); + + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); + mat.setTrans(uTrans, vTrans, 0); + + osg::TexMat* texMat = new osg::TexMat; + texMat->setMatrix(mat); + + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + { + mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + } +} + +bool VisController::Value::calculate(float time) const +{ + if(mData.size() == 0) + return true; + + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > time) + return mData[i-1].isSet; + } + return mData.back().isSet; +} + +void VisController::Value::setValue(float time) +{ + bool vis = calculate(time); + mNode->setNodeMask(vis ? ~0 : 0); +} + + +} diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp new file mode 100644 index 0000000000..e45bc7feab --- /dev/null +++ b/components/nifosg/controller.hpp @@ -0,0 +1,214 @@ +#ifndef COMPONENTS_NIFOSG_CONTROLLER_H +#define COMPONENTS_NIFOSG_CONTROLLER_H + +#include +#include +#include +#include + +#include + +#include + +#include //UVController + +#include + + +namespace osg +{ + class Node; + class StateSet; +} + +namespace osgAnimation +{ + class MorphGeometry; +} + +namespace NifOsg +{ + + // FIXME: Should not be here. We might also want to use this for non-NIF model formats + class ValueInterpolator + { + protected: + float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const; + + osg::Vec3f interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const; + }; + + // FIXME: Should not be here. We might also want to use this for non-NIF model formats + class ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + bool mDeltaInput; + float mDeltaCount; + public: + float mStopTime; + + public: + ControllerFunction(const Nif::Controller *ctrl, bool deltaInput); + + float calculate(float value); + }; + typedef ControllerFunction DefaultFunction; + + class ControllerSource + { + public: + virtual float getValue() const = 0; + }; + + // FIXME: Should return a dt instead of time + class FrameTimeSource : public ControllerSource + { + public: + + virtual float getValue() const + { + return mTimer.time_s(); + } + + private: + osg::Timer mTimer; + }; + + class ControllerValue + { + public: + virtual void setValue(float value) = 0; + }; + + class Controller + { + public: + Controller (boost::shared_ptr src, boost::shared_ptr dest, + boost::shared_ptr function); + + virtual void update(); + + boost::shared_ptr mSource; + boost::shared_ptr mDestValue; + + // The source value gets passed through this function before it's passed on to the DestValue. + boost::shared_ptr mFunction; + }; + + // FIXME: Should be with other general extensions. + class NodeTargetValue : public ControllerValue + { + protected: + osg::Node *mNode; + + public: + NodeTargetValue(osg::Node *target) : mNode(target) + { } + + virtual osg::Vec3f getTranslation(float value) const = 0; + + osg::Node *getNode() const + { return mNode; } + }; + + class GeomMorpherController + { + public: + class Value : public ControllerValue, public ValueInterpolator + { + public: + // FIXME: don't copy the morph data? + Value(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + + virtual void setValue(float time); + + private: + osgAnimation::MorphGeometry* mGeom; + std::vector mMorphs; + }; + }; + + class KeyframeController + { + public: + class Value : public NodeTargetValue, public ValueInterpolator + { + private: + const Nif::QuaternionKeyMap* mRotations; + const Nif::FloatKeyMap* mXRotations; + const Nif::FloatKeyMap* mYRotations; + const Nif::FloatKeyMap* mZRotations; + const Nif::Vector3KeyMap* mTranslations; + const Nif::FloatKeyMap* mScales; + Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + + osg::Quat mInitialQuat; + float mInitialScale; + + using ValueInterpolator::interpKey; + + + osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + + osg::Quat getXYZRotation(float time) const; + + public: + /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. + Value(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale); + + virtual osg::Vec3f getTranslation(float time) const; + + virtual void setValue(float time); + }; + }; + + class UVController + { + public: + class Value : public ControllerValue, ValueInterpolator + { + private: + osg::StateSet* mStateSet; + Nif::FloatKeyMap mUTrans; + Nif::FloatKeyMap mVTrans; + Nif::FloatKeyMap mUScale; + Nif::FloatKeyMap mVScale; + std::set mTextureUnits; + + public: + Value(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); + + virtual void setValue(float value); + }; + }; + + class VisController + { + public: + class Value : public NodeTargetValue + { + private: + std::vector mData; + + bool calculate(float time) const; + + public: + Value(osg::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) + , mData(data->mVis) + { } + + virtual osg::Vec3f getTranslation(float time) const + { return osg::Vec3f(); } + + virtual void setValue(float time); + }; + }; + +} + +#endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp new file mode 100644 index 0000000000..2eb57a4f86 --- /dev/null +++ b/components/nifosg/nifloader.cpp @@ -0,0 +1,759 @@ +#include "nifloader.hpp" + +#include +#include +#include +#include +#include + +// resource +#include +#include +#include +#include + +// skel +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) + { + osg::Matrixf transform; + transform.setTrans(nifTrafo.pos); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + transform(j,i) = nifTrafo.rotation.mValues[i][j] * nifTrafo.scale; // NB column/row major difference + + return transform; + } + + osg::Matrixf getWorldTransform(const Nif::Node* node) + { + if(node->parent != NULL) + return toMatrix(node->trafo) * getWorldTransform(node->parent); + return toMatrix(node->trafo); + } + + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) + { + switch(mode) + { + case 0: return osg::BlendFunc::ONE; + case 1: return osg::BlendFunc::ZERO; + case 2: return osg::BlendFunc::SRC_COLOR; + case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; + case 4: return osg::BlendFunc::DST_COLOR; + case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; + case 6: return osg::BlendFunc::SRC_ALPHA; + case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; + case 8: return osg::BlendFunc::DST_ALPHA; + case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; + case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; + default: + std::cerr<< "Unexpected blend mode: "<< mode << std::endl; + return osg::BlendFunc::SRC_ALPHA; + } + } + + osg::AlphaFunc::ComparisonFunction getTestMode(int mode) + { + switch (mode) + { + case 0: return osg::AlphaFunc::ALWAYS; + case 1: return osg::AlphaFunc::LESS; + case 2: return osg::AlphaFunc::EQUAL; + case 3: return osg::AlphaFunc::LEQUAL; + case 4: return osg::AlphaFunc::GREATER; + case 5: return osg::AlphaFunc::NOTEQUAL; + case 6: return osg::AlphaFunc::GEQUAL; + case 7: return osg::AlphaFunc::NEVER; + default: + std::cerr << "Unexpected blend mode: " << mode << std::endl; + return osg::AlphaFunc::LEQUAL; + } + } + + // Collect all properties affecting the given node that should be applied to an osg::Material. + void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) + { + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i recType) + { + case Nif::RC_NiMaterialProperty: + case Nif::RC_NiVertexColorProperty: + case Nif::RC_NiSpecularProperty: + out.push_back(props[i].getPtr()); + break; + default: + break; + } + } + } + if (nifNode->parent) + collectMaterialProperties(nifNode->parent, out); + } + + void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties) + { + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + // FIXME: color mode should be disabled if the TriShape has no vertex colors + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } + + // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. + class UpdateBone : public osg::NodeCallback + { + public: + // Callback method called by the NodeVisitor when visiting a node. + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osgAnimation::Bone* b = dynamic_cast(node); + if (!b) + { + OSG_WARN << "Warning: UpdateBone set on non-Bone object." << std::endl; + return; + } + + osgAnimation::Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); + } + traverse(node,nv); + } + }; + + // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space + // on the MatrixTransform that the NodeCallback is attached to. This is used so we can + // attach skinned meshes to their actual parent node, while still having the skinning + // work in skeleton space as expected. + class InvertBoneMatrix : public osg::NodeCallback + { + public: + InvertBoneMatrix(osg::Node* skelRootNode) + : mSkelRoot(skelRootNode) + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::NodePath::iterator found = std::find(path.begin(), path.end(), mSkelRoot); + if (found != path.end()) + { + path.erase(path.begin(),found+1); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + } + traverse(node,nv); + } + private: + osg::Node* mSkelRoot; + }; + + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + { + osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; + morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); + // NIF format doesn't specify morphed normals + morphGeom->setMorphNormals(false); + + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + // Note we are not interested in morph 0, which just contains the original vertices + for (unsigned int i = 1; i < morphs.size(); ++i) + { + osg::ref_ptr morphTarget = new osg::Geometry; + morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphGeom->addMorphTarget(morphTarget, 0.f); + } + return morphGeom; + } +} + +namespace NifOsg +{ + + void Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + { + mNif = nif; + + if (nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } + + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + { + nif->warn("First root was not a node, but a " + r->recName); + return; + } + + mRootNode = parentNode; + handleNode(nifNode, parentNode, false, std::map()); + } + + void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + { + mNif = nif; + + if (nif->numRoots() < 1) + { + nif->warn("Found no root nodes"); + return; + } + + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + { + nif->warn("First root was not a node, but a " + r->recName); + return; + } + + mRootNode = parentNode; + + osgAnimation::Skeleton* skel = new osgAnimation::Skeleton; + mSkeleton = skel; + mRootNode->addChild(mSkeleton); + + handleNode(nifNode, mSkeleton, true, std::map()); + } + + void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures) + { + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i value, int animflags) + { + // FIXME animflags currently not passed to this function + //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + boost::shared_ptr src(new FrameTimeSource); // if autoPlay + + boost::shared_ptr function (new ControllerFunction(ctrl + , 0/*autoPlay*/)); + //scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); + + mControllers.push_back(Controller(src, value, function)); + } + + void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures) + { + osg::ref_ptr transformNode; + if (createSkeleton) + { + osgAnimation::Bone* bone = new osgAnimation::Bone; + transformNode = bone; + bone->setMatrix(toMatrix(nifNode->trafo)); + bone->setName(nifNode->name); + bone->setUpdateCallback(new UpdateBone); + bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); + } + else + { + transformNode = new osg::MatrixTransform; + transformNode->setMatrix(toMatrix(nifNode->trafo)); + } + + // Hide collision shapes, but don't skip the subgraph + // We still need to animate the hidden bones so the physics system can access them + // FIXME: skip creation of the TriShapes + if (nifNode->recType == Nif::RC_RootCollisionNode) + transformNode->setNodeMask(0); + + // We could probably skip hidden nodes entirely if they don't have a VisController that + // might make them visible later + if (nifNode->flags & Nif::NiNode::Flag_Hidden) + transformNode->setNodeMask(0); + + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + + applyNodeProperties(nifNode, transformNode, boundTextures); + + if (nifNode->recType == Nif::RC_NiTriShape) + { + const Nif::NiTriShape* triShape = static_cast(nifNode); + if (!createSkeleton || triShape->skin.empty()) + handleTriShape(triShape, transformNode, boundTextures); + else + handleSkinnedTriShape(triShape, transformNode, boundTextures); + + if (!nifNode->controller.empty()) + handleMeshControllers(nifNode, transformNode, boundTextures); + } + + if (!nifNode->controller.empty()) + handleNodeControllers(nifNode, transformNode); + + const Nif::NiNode *ninode = dynamic_cast(nifNode); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();++i) + { + if(!children[i].empty()) + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures); + } + } + } + + void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures) + { + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); + std::set texUnits; + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + texUnits.insert(it->first); + boost::shared_ptr dest(new UVController::Value(transformNode->getOrCreateStateSet() + , uvctrl->data.getPtr(), texUnits)); + createController(uvctrl, dest, 0); + } + } + } + + void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode) + { + bool seenKeyframeCtrl = false; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + if (seenKeyframeCtrl) + { + std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; + continue; + } + boost::shared_ptr dest(new KeyframeController::Value(transformNode, mNif, key->data.getPtr(), + transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + createController(key, dest, 0); + seenKeyframeCtrl = true; + } + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new VisController::Value(transformNode, visctrl->data.getPtr())); + createController(visctrl, dest, 0); + } + } + } + + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) + { + const Nif::NiTriShapeData* data = triShape->data.getPtr(); + + const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); + if (skin) + { + // 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. + osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); + osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + + const Nif::NiSkinData *skinData = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); + + mat = mat * getWorldTransform(bones[b].getPtr()); + + const std::vector &weights = skinData->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; + (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); + if(newNormals->size() > index) + { + osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); + normal = (normal * mat) * weight; + (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); + } + } + } + // Interpolating normalized normals doesn't necessarily give you a normalized result + // Currently we're using GL_NORMALIZE, so this isn't needed + //for (unsigned int i=0;isize();++i) + // (*newNormals)[i].normalize(); + + geometry->setVertexArray(newVerts); + if (!data->normals.empty()) + geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); + } + else + { + geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); + if (!data->normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); + } + + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + { + int textureStage = it->first; + int uvSet = it->second; + if (uvSet >= (int)data->uvlist.size()) + { + // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently + //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + continue; + } + + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + } + + // FIXME: material ColorMode should be disabled if the TriShape has no vertex colors + if (!data->colors.empty()) + geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); + + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, + data->triangles.size(), + (unsigned short*)&data->triangles[0])); + } + + void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) + { + osg::ref_ptr geometry; + if(!triShape->controller.empty()) + { + Nif::ControllerPtr ctrl = triShape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + boost::shared_ptr value( + new GeomMorpherController::Value(static_cast(geometry.get()), + static_cast(ctrl.getPtr())->data.getPtr())); + createController(ctrl.getPtr(), value, 0); + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + + if (!geometry.get()) + geometry = new osg::Geometry; + triShapeToGeometry(triShape, geometry.get(), boundTextures); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry.get()); + + parentNode->addChild(geode.get()); + } + + void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures) + { + osg::ref_ptr geometry (new osg::Geometry); + triShapeToGeometry(triShape, geometry.get(), boundTextures); + + osg::ref_ptr rig(new osgAnimation::RigGeometry); + rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones + // For more accuracy the skinning should be relative to the parent of the first skinned bone, + // rather than the root bone. + osg::BoundingBox box = geometry->getBound(); + box.expandBy(box._min-(box._max-box._min)/2); + box.expandBy(box._max+(box._max-box._min)/2); + rig->setInitialBound(box); + + const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + + // Assign bone weights + osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + std::string boneName = bones[i].getPtr()->name; + + osgAnimation::VertexInfluence influence; + influence.setName(boneName); + const std::vector &weights = data->bones[i].weights; + influence.reserve(weights.size()); + for(size_t j = 0;j < weights.size();j++) + { + osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.push_back(indexWeight); + } + + map->insert(std::make_pair(boneName, influence)); + } + rig->setInfluenceMap(map.get()); + + osg::ref_ptr trans(new osg::MatrixTransform); + trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(rig.get()); + + trans->addChild(geode.get()); + parentNode->addChild(trans.get()); + } + + void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + osg::Node *node, std::map& boundTextures) + { + osg::StateSet* stateset = node->getOrCreateStateSet(); + + switch (property->recType) + { + case Nif::RC_NiStencilProperty: + { + const Nif::NiStencilProperty* stencilprop = static_cast(property); + osg::FrontFace* frontFace = new osg::FrontFace; + switch (stencilprop->data.drawMode) + { + case 1: + frontFace->setMode(osg::FrontFace::CLOCKWISE); + break; + case 0: + case 2: + default: + frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); + break; + } + + stateset->setAttribute(frontFace, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + // Stencil settings not enabled yet, not sure if the original engine is actually using them, + // since they might conflict with Morrowind's stencil shadows. + /* + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + + stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + */ + } + case Nif::RC_NiWireframeProperty: + { + const Nif::NiWireframeProperty* wireprop = static_cast(property); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL + : osg::PolygonMode::LINE); + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + break; + } + case Nif::RC_NiZBufferProperty: + { + const Nif::NiZBufferProperty* zprop = static_cast(property); + // VER_MW doesn't support a DepthFunction according to NifSkope + osg::Depth* depth = new osg::Depth; + depth->setWriteMask((zprop->flags>>1)&1); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + break; + } + // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed + case Nif::RC_NiMaterialProperty: + case Nif::RC_NiVertexColorProperty: + case Nif::RC_NiSpecularProperty: + { + // TODO: handle these in handleTriShape so we know whether vertex colors are available + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + updateMaterialProperties(stateset, materialProps); + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) + { + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) + { + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + } + } + else + { + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } + + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + break; + } + case Nif::RC_NiTexturingProperty: + { + const Nif::NiTexturingProperty* texprop = static_cast(property); + for (int i=0; itextures[i].inUse) + { + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; + if(tex.texture.empty()) + { + std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + continue; + } + const Nif::NiSourceTexture *st = tex.texture.getPtr(); + std::string filename (st->filename); + Misc::StringUtils::toLower(filename); + filename = "textures\\" + filename; + size_t found = filename.find(".tga"); + if (found == std::string::npos) + found = filename.find(".bmp"); + if (found != std::string::npos) + filename.replace(found, 4, ".dds"); + + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osg::Image* image = result.getImage(); + osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setImage(image); + + unsigned int clamp = static_cast(tex.clamp); + int wrapT = (clamp) & 0x1; + int wrapS = (clamp >> 1) & 0x1; + + texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); + texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + + boundTextures[i] = tex.uvSet; + } + else if (boundTextures.find(i) != boundTextures.end()) + { + stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); + boundTextures.erase(i); + } + } + break; + } + case Nif::RC_NiDitherProperty: + { + stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + break; + } + default: + std::cerr << "Unhandled " << property->recName << std::endl; + break; + } + } +} diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp new file mode 100644 index 0000000000..a089f76518 --- /dev/null +++ b/components/nifosg/nifloader.hpp @@ -0,0 +1,84 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_LOADER +#define OPENMW_COMPONENTS_NIFOSG_LOADER + +#include + +#include // NIFFilePtr + +#include + +#include "controller.hpp" + +namespace osg +{ + class Geometry; +} +namespace osgAnimation +{ + class Bone; +} + +namespace Nif +{ + class Node; + class NiTriShape; + class Property; +} +namespace Bsa +{ + class BSAFile; +} + +namespace NifOsg +{ + + /// The main class responsible for loading NIF files into an OSG-Scenegraph. + class Loader + { + public: + /// @param node The parent of the root node for the created NIF file. + void load(Nif::NIFFilePtr file, osg::Group* parentNode); + + void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + + // FIXME replace with resource system + Bsa::BSAFile* resourceManager; + + // FIXME move + std::vector mControllers; + + private: + + /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. + void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures); + + void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures); + + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + + void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, + osg::Node* node, std::map& boundTextures); + + // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + + // Fills the vertex data for the given TriShape into the given Geometry. + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures); + + // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. + void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + + // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. + void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + + void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); + + Nif::NIFFilePtr mNif; + + osg::Group* mRootNode; + osg::Group* mSkeleton; + }; + +} + +#endif From 6c63bab8e48a7e376f78462e2d73a08dac868975 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:08:15 +0100 Subject: [PATCH 0012/1812] Change Nif::Property flags to unsigned --- components/nif/property.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index b06044e9f0..2633b16c59 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -33,7 +33,7 @@ class Property : public Named { public: // The meaning of these depends on the actual property type. - int flags; + unsigned int flags; void read(NIFStream *nif); }; From 74dfb23e7bb4063324b7ea643a136b1cf3421dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:16:37 +0100 Subject: [PATCH 0013/1812] Handle material properties in trishapeToGeometry --- components/nifosg/nifloader.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2eb57a4f86..b895f8e137 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,12 +113,11 @@ namespace collectMaterialProperties(nifNode->parent, out); } - void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties) + void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; - // FIXME: color mode should be disabled if the TriShape has no vertex colors - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; @@ -145,6 +144,8 @@ namespace case Nif::RC_NiVertexColorProperty: { const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; switch (vertprop->flags) { case 0: @@ -504,13 +505,20 @@ namespace NifOsg geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); } - // FIXME: material ColorMode should be disabled if the TriShape has no vertex colors if (!data->colors.empty()) geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), (unsigned short*)&data->triangles[0])); + + // osg::Material properties are handled here for two reasons: + // - if there are no vertex colors, we need to disable colorMode. + // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them + // above the actual renderable would be tedious. + std::vector materialProps; + collectMaterialProperties(triShape, materialProps); + updateMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) @@ -653,9 +661,6 @@ namespace NifOsg case Nif::RC_NiSpecularProperty: { // TODO: handle these in handleTriShape so we know whether vertex colors are available - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - updateMaterialProperties(stateset, materialProps); break; } case Nif::RC_NiAlphaProperty: From 3839d6f777d629ed8d330f07d43ff4681cbcb328 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:21:19 +0100 Subject: [PATCH 0014/1812] Simplify controller classes --- components/nifosg/controller.cpp | 22 +++--- components/nifosg/controller.hpp | 128 ++++++++++++++----------------- components/nifosg/nifloader.cpp | 8 +- 3 files changed, 71 insertions(+), 87 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4e600c3a18..086e679d67 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -92,7 +92,7 @@ float ControllerFunction::calculate(float value) return value; } -osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) +osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { if(time <= keys.begin()->first) return keys.begin()->second.mValue; @@ -125,7 +125,7 @@ osg::Quat KeyframeController::Value::interpKey(const Nif::QuaternionKeyMap::MapT return keys.rbegin()->second.mValue; } -osg::Quat KeyframeController::Value::getXYZRotation(float time) const +osg::Quat KeyframeControllerValue::getXYZRotation(float time) const { float xrot = interpKey(mXRotations->mKeys, time); float yrot = interpKey(mYRotations->mKeys, time); @@ -136,7 +136,7 @@ osg::Quat KeyframeController::Value::getXYZRotation(float time) const return (zr*yr*xr); } -KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, +KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, osg::Quat initialQuat, float initialScale) : NodeTargetValue(target) , mRotations(&data->mRotations) @@ -150,7 +150,7 @@ KeyframeController::Value::Value(osg::Node *target, const Nif::NIFFilePtr &nif, , mInitialScale(initialScale) { } -osg::Vec3f KeyframeController::Value::getTranslation(float time) const +osg::Vec3f KeyframeControllerValue::getTranslation(float time) const { if(mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); @@ -158,7 +158,7 @@ osg::Vec3f KeyframeController::Value::getTranslation(float time) const return trans->getMatrix().getTrans(); } -void KeyframeController::Value::setValue(float time) +void KeyframeControllerValue::setValue(float time) { osg::MatrixTransform* trans = static_cast(mNode); osg::Matrix mat = trans->getMatrix(); @@ -200,14 +200,14 @@ void Controller::update() } } -GeomMorpherController::Value::Value(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) +GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) : mGeom(geom) , mMorphs(morphData->mMorphs) { } -void GeomMorpherController::Value::setValue(float time) +void GeomMorpherControllerValue::setValue(float time) { if (mMorphs.size() <= 1) return; @@ -223,7 +223,7 @@ void GeomMorpherController::Value::setValue(float time) } } -UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) +UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) : mStateSet(target) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -233,7 +233,7 @@ UVController::Value::Value(osg::StateSet *target, const Nif::NiUVData *data, std { } -void UVController::Value::setValue(float value) +void UVControllerValue::setValue(float value) { float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); @@ -252,7 +252,7 @@ void UVController::Value::setValue(float value) } } -bool VisController::Value::calculate(float time) const +bool VisControllerValue::calculate(float time) const { if(mData.size() == 0) return true; @@ -265,7 +265,7 @@ bool VisController::Value::calculate(float time) const return mData.back().isSet; } -void VisController::Value::setValue(float time) +void VisControllerValue::setValue(float time) { bool vis = calculate(time); mNode->setNodeMask(vis ? ~0 : 0); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e45bc7feab..d916f894f5 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -114,99 +114,83 @@ namespace NifOsg { return mNode; } }; - class GeomMorpherController + class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator { public: - class Value : public ControllerValue, public ValueInterpolator - { - public: - // FIXME: don't copy the morph data? - Value(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + // FIXME: don't copy the morph data? + GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); - virtual void setValue(float time); + virtual void setValue(float time); - private: - osgAnimation::MorphGeometry* mGeom; - std::vector mMorphs; - }; + private: + osgAnimation::MorphGeometry* mGeom; + std::vector mMorphs; }; - class KeyframeController + class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator { + private: + const Nif::QuaternionKeyMap* mRotations; + const Nif::FloatKeyMap* mXRotations; + const Nif::FloatKeyMap* mYRotations; + const Nif::FloatKeyMap* mZRotations; + const Nif::Vector3KeyMap* mTranslations; + const Nif::FloatKeyMap* mScales; + Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + + osg::Quat mInitialQuat; + float mInitialScale; + + using ValueInterpolator::interpKey; + + + osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + + osg::Quat getXYZRotation(float time) const; + public: - class Value : public NodeTargetValue, public ValueInterpolator - { - private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. + KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale); - osg::Quat mInitialQuat; - float mInitialScale; + virtual osg::Vec3f getTranslation(float time) const; - using ValueInterpolator::interpKey; - - - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); - - osg::Quat getXYZRotation(float time) const; - - public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - Value(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale); - - virtual osg::Vec3f getTranslation(float time) const; - - virtual void setValue(float time); - }; + virtual void setValue(float time); }; - class UVController + class UVControllerValue : public ControllerValue, ValueInterpolator { + private: + osg::StateSet* mStateSet; + Nif::FloatKeyMap mUTrans; + Nif::FloatKeyMap mVTrans; + Nif::FloatKeyMap mUScale; + Nif::FloatKeyMap mVScale; + std::set mTextureUnits; + public: - class Value : public ControllerValue, ValueInterpolator - { - private: - osg::StateSet* mStateSet; - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; - std::set mTextureUnits; + UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - public: - Value(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); - }; + virtual void setValue(float value); }; - class VisController + class VisControllerValue : public NodeTargetValue { + private: + std::vector mData; + + bool calculate(float time) const; + public: - class Value : public NodeTargetValue - { - private: - std::vector mData; + VisControllerValue(osg::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) + , mData(data->mVis) + { } - bool calculate(float time) const; + virtual osg::Vec3f getTranslation(float time) const + { return osg::Vec3f(); } - public: - Value(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } - - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } - - virtual void setValue(float time); - }; + virtual void setValue(float time); }; } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b895f8e137..abeb17b6f5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -400,7 +400,7 @@ namespace NifOsg std::set texUnits; for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) texUnits.insert(it->first); - boost::shared_ptr dest(new UVController::Value(transformNode->getOrCreateStateSet() + boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() , uvctrl->data.getPtr(), texUnits)); createController(uvctrl, dest, 0); } @@ -422,7 +422,7 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - boost::shared_ptr dest(new KeyframeController::Value(transformNode, mNif, key->data.getPtr(), + boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); createController(key, dest, 0); @@ -432,7 +432,7 @@ namespace NifOsg else if (ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new VisController::Value(transformNode, visctrl->data.getPtr())); + boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); createController(visctrl, dest, 0); } } @@ -532,7 +532,7 @@ namespace NifOsg { geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); boost::shared_ptr value( - new GeomMorpherController::Value(static_cast(geometry.get()), + new GeomMorpherControllerValue(static_cast(geometry.get()), static_cast(ctrl.getPtr())->data.getPtr())); createController(ctrl.getPtr(), value, 0); break; From c54ee16748390b3bb0775b0508be6135ecf357b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:44:01 +0100 Subject: [PATCH 0015/1812] Add AlphaController and MaterialColorController --- components/nifosg/controller.cpp | 39 +++++++++ components/nifosg/controller.hpp | 24 ++++++ components/nifosg/nifloader.cpp | 137 ++++++++++++++++++------------- components/nifosg/nifloader.hpp | 4 + 4 files changed, 148 insertions(+), 56 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 086e679d67..8ac7f004c5 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -2,8 +2,11 @@ #include #include +#include #include +#include + #include namespace NifOsg @@ -271,5 +274,41 @@ void VisControllerValue::setValue(float time) mNode->setNodeMask(vis ? ~0 : 0); } +AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) + : mTarget(target) + , mData(data->mKeyList) +{ +} + +void AlphaControllerValue::setValue(float time) +{ + float value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + +MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) + : mTarget(target), mData(data->mKeyList) +{ + +} + +void MaterialColorControllerValue::setValue(float time) +{ + osg::Vec3f value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d916f894f5..af09bda64f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -193,6 +193,30 @@ namespace NifOsg virtual void setValue(float time); }; + class AlphaControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::FloatKeyMap mData; + + public: + AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + + virtual void setValue(float time); + }; + + class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::Vector3KeyMap mData; + + public: + MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index abeb17b6f5..ebc4911c8b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,61 +113,6 @@ namespace collectMaterialProperties(nifNode->parent, out); } - void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) - { - int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; - mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) - { - const Nif::Property* property = *it; - switch (property->recType) - { - case Nif::RC_NiSpecularProperty: - { - specFlags = property->flags; - break; - } - case Nif::RC_NiMaterialProperty: - { - const Nif::NiMaterialProperty* matprop = static_cast(property); - - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); - mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); - - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); - mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); - - break; - } - case Nif::RC_NiVertexColorProperty: - { - const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) - { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; - } - } - } - } - - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); - - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); - } - // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. class UpdateBone : public osg::NodeCallback { @@ -438,6 +383,27 @@ namespace NifOsg } } + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + { + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiAlphaController) + { + const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); + createController(alphactrl, dest, 0); + } + else if (ctrl->recType == Nif::RC_NiMaterialColorController) + { + const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); + createController(matctrl, dest, 0); + } + else + std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + } + } + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -518,7 +484,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - updateMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) @@ -761,4 +727,63 @@ namespace NifOsg break; } } + + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + { + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); + // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + if (!matprop->controller.empty()) + handleMaterialControllers(matprop, stateset); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index a089f76518..3b2443eb9b 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -56,6 +56,8 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures); @@ -71,6 +73,8 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); Nif::NIFFilePtr mNif; From 6c8613ae356df1642991ab19ec8433c2d723dbe1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 23:21:56 +0100 Subject: [PATCH 0016/1812] Add DarkTexture and DetailTexture --- components/nifosg/nifloader.cpp | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ebc4911c8b..1355788883 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include @@ -668,10 +670,17 @@ namespace NifOsg const Nif::NiTexturingProperty* texprop = static_cast(property); for (int i=0; itextures[i].inUse) { + if (i != Nif::NiTexturingProperty::BaseTexture + && i != Nif::NiTexturingProperty::GlowTexture + && i != Nif::NiTexturingProperty::DarkTexture + && i != Nif::NiTexturingProperty::DetailTexture) + { + std::cerr << "Warning: unhandled texture stage " << i << std::endl; + continue; + } + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; if(tex.texture.empty()) { @@ -679,6 +688,11 @@ namespace NifOsg continue; } const Nif::NiSourceTexture *st = tex.texture.getPtr(); + if (!st->external) + { + std::cerr << "Warning: unhandled internal texture " << std::endl; + continue; + } std::string filename (st->filename); Misc::StringUtils::toLower(filename); filename = "textures\\" + filename; @@ -706,6 +720,37 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + if (i == Nif::NiTexturingProperty::GlowTexture) + { + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::ADD); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DarkTexture) + { + // untested + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DetailTexture) + { + // untested + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setScale_RGB(2.f); + texEnv->setCombine_Alpha(GL_MODULATE); + texEnv->setOperand0_Alpha(GL_SRC_ALPHA); + texEnv->setOperand1_Alpha(GL_SRC_ALPHA); + texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource1_Alpha(GL_TEXTURE); + texEnv->setCombine_RGB(GL_MODULATE); + texEnv->setOperand0_RGB(GL_SRC_COLOR); + texEnv->setOperand1_RGB(GL_SRC_COLOR); + texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource1_RGB(GL_TEXTURE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + boundTextures[i] = tex.uvSet; } else if (boundTextures.find(i) != boundTextures.end()) From 2a92fb57f72f8934b961adf3efd46bc8bbe85036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 00:02:10 +0100 Subject: [PATCH 0017/1812] Add FlipController --- components/nifosg/controller.cpp | 21 ++++++ components/nifosg/controller.hpp | 19 ++++++ components/nifosg/nifloader.cpp | 107 ++++++++++++++++++++++--------- components/nifosg/nifloader.hpp | 23 ++++--- 4 files changed, 130 insertions(+), 40 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 8ac7f004c5..041036e5bb 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -310,5 +311,25 @@ void MaterialColorControllerValue::setValue(float time) mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } +FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, + std::vector > textures) + : mTexSlot(ctrl->mTexSlot) + , mDelta(ctrl->mDelta) + , mTextures(textures) + , mTarget(target) +{ +} + +void FlipControllerValue::setValue(float time) +{ + if (mDelta == 0) + return; + int curTexture = int(time / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); + if (!tex) + return; + tex->setImage(mTextures[curTexture].get()); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index af09bda64f..421f00277d 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -12,6 +12,10 @@ #include //UVController +// FlipController +#include +#include + #include @@ -217,6 +221,21 @@ namespace NifOsg virtual void setValue(float time); }; + // untested + class FlipControllerValue : public ControllerValue + { + private: + osg::StateSet* mTarget; + int mTexSlot; + float mDelta; + std::vector > mTextures; + + public: + FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1355788883..34c2f0ce00 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -220,7 +220,7 @@ namespace NifOsg } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map()); + handleNode(nifNode, parentNode, false, std::map(), 0); } void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) @@ -249,16 +249,16 @@ namespace NifOsg mSkeleton = skel; mRootNode->addChild(mSkeleton); - handleNode(nifNode, mSkeleton, true, std::map()); + handleNode(nifNode, mSkeleton, true, std::map(), 0); } - void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures) + void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i boundTextures) + std::map boundTextures, int animflags, bool collisionNode) { osg::ref_ptr transformNode; if (createSkeleton) @@ -294,11 +294,16 @@ namespace NifOsg transformNode->setMatrix(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) + animflags |= nifNode->flags; + // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them - // FIXME: skip creation of the TriShapes if (nifNode->recType == Nif::RC_RootCollisionNode) + { + collisionNode = true; transformNode->setNodeMask(0); + } // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later @@ -308,22 +313,22 @@ namespace NifOsg // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures); + applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape) + if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures); + handleTriShape(triShape, transformNode, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, boundTextures); + handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures); + handleMeshControllers(nifNode, transformNode, boundTextures, animflags); } if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode); + handleNodeControllers(nifNode, transformNode, animflags); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -332,12 +337,12 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, collisionNode); } } } - void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures) + void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -349,12 +354,12 @@ namespace NifOsg texUnits.insert(it->first); boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, 0); + createController(uvctrl, dest, animflags); } } } - void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode) + void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -372,7 +377,7 @@ namespace NifOsg boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); - createController(key, dest, 0); + createController(key, dest, animflags); seenKeyframeCtrl = true; } } @@ -380,12 +385,12 @@ namespace NifOsg { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, 0); + createController(visctrl, dest, animflags); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -393,20 +398,59 @@ namespace NifOsg { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, 0); + createController(alphactrl, dest, animflags); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, 0); + createController(matctrl, dest, animflags); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + { + for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiFlipController) + { + const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); + std::vector > textures; + for (unsigned int i=0; imSources.length(); ++i) + { + Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; + if (st.empty()) + continue; + + // FIXME: replace by ResourceHelpers + std::string filename (st->filename); + Misc::StringUtils::toLower(filename); + filename = "textures\\" + filename; + size_t found = filename.find(".tga"); + if (found == std::string::npos) + found = filename.find(".bmp"); + if (found != std::string::npos) + filename.replace(found, 4, ".dds"); + + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + textures.push_back(osg::ref_ptr(result.getImage())); + } + boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); + createController(flipctrl, dest, animflags); + } + else + std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + } + } + + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -486,10 +530,10 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); } - void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) + void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -510,7 +554,7 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry.get()); @@ -518,10 +562,10 @@ namespace NifOsg parentNode->addChild(geode.get()); } - void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures) + void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -569,7 +613,7 @@ namespace NifOsg } void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures) + osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -693,6 +737,8 @@ namespace NifOsg std::cerr << "Warning: unhandled internal texture " << std::endl; continue; } + + // FIXME: replace by ResourceHelpers std::string filename (st->filename); Misc::StringUtils::toLower(filename); filename = "textures\\" + filename; @@ -758,6 +804,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } + handleTextureControllers(texprop, stateset, animflags); } break; } @@ -773,7 +820,7 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; @@ -801,7 +848,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset); + handleMaterialControllers(matprop, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 3b2443eb9b..7f4aa7ea42 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -50,30 +50,33 @@ namespace NifOsg private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures); + void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures, int animflags, bool collisionNode=false); - void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures); + void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + + void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, - osg::Node* node, std::map& boundTextures); + osg::Node* node, std::map& boundTextures, int animflags); // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. - void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); From 8d64f2081ed8ddb9251a4865fece9e011e9dd161 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 01:25:31 +0100 Subject: [PATCH 0018/1812] Add particle system state loading --- CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 118 ++++++++++++++++++++++++++++---- components/nifosg/nifloader.hpp | 7 +- 3 files changed, 111 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5b37a05bb..1059b1c3ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 34c2f0ce00..feffe2cba1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -18,6 +18,10 @@ #include #include +// particle +#include +#include + #include #include #include @@ -177,6 +181,17 @@ namespace osg::Node* mSkelRoot; }; + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state + class ParticleAgeSetter : public osgParticle::Particle + { + public: + ParticleAgeSetter(float age) + : Particle() + { + _t0 = age; + } + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; @@ -220,7 +235,7 @@ namespace NifOsg } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map(), 0); + handleNode(nifNode, parentNode, false, std::map(), 0, 0); } void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) @@ -249,7 +264,7 @@ namespace NifOsg mSkeleton = skel; mRootNode->addChild(mSkeleton); - handleNode(nifNode, mSkeleton, true, std::map(), 0); + handleNode(nifNode, mSkeleton, true, std::map(), 0, 0); } void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) @@ -276,7 +291,7 @@ namespace NifOsg } void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, bool collisionNode) + std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; if (createSkeleton) @@ -327,6 +342,9 @@ namespace NifOsg handleMeshControllers(nifNode, transformNode, boundTextures, animflags); } + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, particleflags, animflags); + if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -337,7 +355,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, collisionNode); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); } } } @@ -346,6 +364,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); @@ -364,6 +384,8 @@ namespace NifOsg bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); @@ -394,6 +416,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); @@ -415,6 +439,8 @@ namespace NifOsg { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; if (ctrl->recType == Nif::RC_NiFlipController) { const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); @@ -450,6 +476,71 @@ namespace NifOsg } } + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int particleflags, int animflags) + { + osg::ref_ptr partsys (new osgParticle::ParticleSystem); + + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(nifNode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else if(nifNode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else + return; + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + return; + + int i=0; + for (std::vector::const_iterator it = partctrl->particles.begin(); + iactiveCount && it != partctrl->particles.end(); ++it, ++i) + { + const Nif::NiParticleSystemController::Particle& particle = *it; + + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifespan - particle.lifetime)); + + osgParticle::Particle* created = partsys->createParticle(&particletemplate); + created->setLifeTime(500);//std::max(0.f, particle.lifespan)); + created->setVelocity(particle.velocity); + created->setPosition(particledata->vertices.at(particle.vertex)); + + osg::Vec4f partcolor (1.f,1.f,1.f,1.f); + if (particle.vertex < int(particledata->colors.size())) + partcolor = particledata->colors.at(particle.vertex); + + float size = particledata->sizes.at(particle.vertex) * partctrl->size; + + created->setSizeRange(osgParticle::rangef(size, size)); + } + + osg::NodeVisitor visitor; + partsys->update(0.f, visitor); + partsys->setFrozen(true); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags); + + partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + parentNode->addChild(geode); + + osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); + } + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -554,18 +645,18 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); + triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry.get()); + geode->addDrawable(geometry); - parentNode->addChild(geode.get()); + parentNode->addChild(geode); } void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); + triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -600,16 +691,16 @@ namespace NifOsg map->insert(std::make_pair(boneName, influence)); } - rig->setInfluenceMap(map.get()); + rig->setInfluenceMap(map); osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(rig.get()); + geode->addDrawable(rig); - trans->addChild(geode.get()); - parentNode->addChild(trans.get()); + trans->addChild(geode); + parentNode->addChild(trans); } void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, @@ -820,7 +911,8 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags) + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + bool hasVertexColors, int animflags) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7f4aa7ea42..0535aa838f 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -51,7 +51,7 @@ namespace NifOsg /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, bool collisionNode=false); + std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); @@ -64,6 +64,8 @@ namespace NifOsg void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); + void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int particleflags, int animflags); + // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); @@ -76,7 +78,8 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + bool hasVertexColors, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); From 7e684853fcaff8f3b7de39e941eaf26c00dae652 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Feb 2015 21:20:07 +0100 Subject: [PATCH 0019/1812] Add StatsHandler for profiling (S key) --- apps/nifosgtest/test.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index fc82059fc7..668bda373d 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -13,10 +14,10 @@ #include // EventHandler to toggle wireframe when 'w' key is pressed -class EventHandler : public osgGA::GUIEventHandler +class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - EventHandler(osg::Node* node) + WireframeKeyHandler(osg::Node* node) : mWireframe(false) , mNode(node) { @@ -70,12 +71,17 @@ int main(int argc, char** argv) // To prevent lighting issues with scaled meshes root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + //osgDB::writeNodeFile(*newNode, "out.osg"); + + std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &bsa; loader.loadAsSkeleton(nif, newNode); - //osgDB::writeNodeFile(*newNode, "out.osg"); + for (unsigned int i=0; i Date: Fri, 27 Feb 2015 19:58:43 +0100 Subject: [PATCH 0020/1812] Fix compile error --- components/files/constrainedfilestream.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 23eab20881..3e5d0c245e 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -5,13 +5,16 @@ #include "lowlevelfile.hpp" +namespace +{ +// somewhat arbitrary though 64KB buffers didn't seem to improve performance any +const size_t sBufferSize = 4096; +} + namespace Files { - class ConstrainedFileStreamBuf : public std::streambuf { - // somewhat arbitrary though 64KB buffers didn't seem to improve performance any - static const size_t sBufferSize = 4096; size_t mOrigin; size_t mSize; From 2eedb3acece4db39da6d56dd905d2c4353e3ae0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Feb 2015 20:22:43 +0100 Subject: [PATCH 0021/1812] Include fix --- apps/openmw/mwgui/review.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1bcd2d31aa..023f23815c 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,5 +1,7 @@ #include "review.hpp" +#include + #include #include #include From 31a0bbcb23101bbf3b916bc1f5100e6c4f31bf65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Mar 2015 18:53:56 +0100 Subject: [PATCH 0022/1812] Seems to fix wireframe crashes --- apps/nifosgtest/test.cpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 668bda373d..16d1d58a36 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -17,9 +17,8 @@ class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - WireframeKeyHandler(osg::Node* node) + WireframeKeyHandler() : mWireframe(false) - , mNode(node) { } @@ -32,12 +31,7 @@ public: if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) { mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + // applying state from an event handler doesn't appear to be safe, so do it in the frame update return true; } default: @@ -46,9 +40,13 @@ public: return false; } + bool getWireframe() const + { + return mWireframe; + } + private: bool mWireframe; - osg::Node* mNode; }; int main(int argc, char** argv) @@ -93,11 +91,28 @@ int main(int argc, char** argv) viewer.setUpViewInWindow(0, 0, 800, 600); viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); + + WireframeKeyHandler* keyHandler = new WireframeKeyHandler; + + viewer.addEventHandler(keyHandler); viewer.addEventHandler(new osgViewer::StatsHandler); + bool wireframe = false; + while (!viewer.done()) { + + if (wireframe != keyHandler->getWireframe()) + { + wireframe = keyHandler->getWireframe(); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + wireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + root->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, wireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + } + viewer.frame(); for (unsigned int i=0; i Date: Tue, 17 Mar 2015 21:59:39 +0100 Subject: [PATCH 0023/1812] Add virtual file system (VFS) replacing the low level parts of the old resource system --- apps/nifosgtest/test.cpp | 12 +++-- components/CMakeLists.txt | 4 ++ components/bsa/bsa_file.cpp | 5 ++ components/bsa/bsa_file.hpp | 2 + components/nifosg/nifloader.cpp | 4 +- components/nifosg/nifloader.hpp | 9 ++-- components/vfs/archive.hpp | 30 +++++++++++ components/vfs/bsaarchive.cpp | 43 ++++++++++++++++ components/vfs/bsaarchive.hpp | 32 ++++++++++++ components/vfs/filesystemarchive.cpp | 65 ++++++++++++++++++++++++ components/vfs/filesystemarchive.hpp | 40 +++++++++++++++ components/vfs/manager.cpp | 76 ++++++++++++++++++++++++++++ components/vfs/manager.hpp | 52 +++++++++++++++++++ 13 files changed, 362 insertions(+), 12 deletions(-) create mode 100644 components/vfs/archive.hpp create mode 100644 components/vfs/bsaarchive.cpp create mode 100644 components/vfs/bsaarchive.hpp create mode 100644 components/vfs/filesystemarchive.cpp create mode 100644 components/vfs/filesystemarchive.hpp create mode 100644 components/vfs/manager.cpp create mode 100644 components/vfs/manager.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 16d1d58a36..ef2ddd6b4b 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -6,6 +6,9 @@ #include +#include +#include + #include #include @@ -57,10 +60,11 @@ int main(int argc, char** argv) return 1; } - Bsa::BSAFile bsa; - bsa.open(argv[1]); + VFS::Manager resourceMgr (false); + resourceMgr.addArchive(new VFS::BsaArchive(argv[1])); + resourceMgr.buildIndex(); - Nif::NIFFilePtr nif(new Nif::NIFFile(bsa.getFile(argv[2]), std::string(argv[2]))); + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[2]), std::string(argv[2]))); osgViewer::Viewer viewer; @@ -75,7 +79,7 @@ int main(int argc, char** argv) std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; - loader.resourceManager = &bsa; + loader.resourceManager = &resourceMgr; loader.loadAsSkeleton(nif, newNode); for (unsigned int i=0; ioffset, file->fileSize); +} diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 3024cb610d..8a7576f923 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -120,6 +120,8 @@ public: */ Files::IStreamPtr getFile(const char *file); + Files::IStreamPtr getFile(const FileStruct* file); + /// Get a list of all files const FileList &getList() const { return files; } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index feffe2cba1..88c944e146 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -465,7 +465,7 @@ namespace NifOsg osgDB::Options* opts = new osgDB::Options; opts->setOptionString("dds_dxt1_detect_rgba"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); textures.push_back(osg::ref_ptr(result.getImage())); } boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); @@ -843,7 +843,7 @@ namespace NifOsg osgDB::Options* opts = new osgDB::Options; opts->setOptionString("dds_dxt1_detect_rgba"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; texture2d->setImage(image); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 0535aa838f..e521015257 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -5,6 +5,8 @@ #include // NIFFilePtr +#include + #include #include "controller.hpp" @@ -24,10 +26,6 @@ namespace Nif class NiTriShape; class Property; } -namespace Bsa -{ - class BSAFile; -} namespace NifOsg { @@ -41,8 +39,7 @@ namespace NifOsg void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - // FIXME replace with resource system - Bsa::BSAFile* resourceManager; + VFS::Manager* resourceManager; // FIXME move std::vector mControllers; diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp new file mode 100644 index 0000000000..b36c7117b0 --- /dev/null +++ b/components/vfs/archive.hpp @@ -0,0 +1,30 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_ARCHIVE_H +#define OPENMW_COMPONENTS_RESOURCE_ARCHIVE_H + +#include + +#include + +namespace VFS +{ + + class File + { + public: + virtual ~File() {} + + virtual Files::IStreamPtr open() = 0; + }; + + class Archive + { + public: + virtual ~Archive() {} + + /// List all resources contained in this archive, and run the resource names through the given normalize function. + virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; + }; + +} + +#endif diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp new file mode 100644 index 0000000000..a527a6ad92 --- /dev/null +++ b/components/vfs/bsaarchive.cpp @@ -0,0 +1,43 @@ +#include "bsaarchive.hpp" + +namespace VFS +{ + + +BsaArchive::BsaArchive(const std::string &filename) +{ + mFile.open(filename); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } +} + +void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) +{ + for (std::vector::iterator it = mResources.begin(); it != mResources.end(); ++it) + { + std::string ent = it->mInfo->name; + std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function); + + out[ent] = &*it; + } +} + +// ------------------------------------------------------------------------------ + +BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) + : mInfo(info) + , mFile(bsa) +{ + +} + +Files::IStreamPtr BsaArchiveFile::open() +{ + return mFile->getFile(mInfo); +} + +} diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp new file mode 100644 index 0000000000..9617469470 --- /dev/null +++ b/components/vfs/bsaarchive.hpp @@ -0,0 +1,32 @@ +#include "archive.hpp" + +#include + +namespace VFS +{ + + class BsaArchiveFile : public File + { + public: + BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, Bsa::BSAFile* bsa); + + virtual Files::IStreamPtr open(); + + const Bsa::BSAFile::FileStruct* mInfo; + Bsa::BSAFile* mFile; + }; + + class BsaArchive : public Archive + { + public: + BsaArchive(const std::string& filename); + + virtual void listResources(std::map& out, char (*normalize_function) (char)); + + private: + Bsa::BSAFile mFile; + + std::vector mResources; + }; + +} diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp new file mode 100644 index 0000000000..ad5150a441 --- /dev/null +++ b/components/vfs/filesystemarchive.cpp @@ -0,0 +1,65 @@ +#include "filesystemarchive.hpp" + +#include + +namespace VFS +{ + + FileSystemArchive::FileSystemArchive(const std::string &path) + : mBuiltIndex(false) + , mPath(path) + { + + } + + void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) + { + if (!mBuiltIndex) + { + typedef boost::filesystem::recursive_directory_iterator directory_iterator; + + directory_iterator end; + + size_t prefix = mPath.size (); + + if (mPath.size () > 0 && mPath [prefix - 1] != '\\' && mPath [prefix - 1] != '/') + ++prefix; + + for (directory_iterator i (mPath); i != end; ++i) + { + if(boost::filesystem::is_directory (*i)) + continue; + + std::string proper = i->path ().string (); + + FileSystemArchiveFile file(proper); + + std::string searchable; + + std::transform(proper.begin() + prefix, proper.end(), std::back_inserter(searchable), normalize_function); + + mIndex.insert (std::make_pair (searchable, file)); + } + + mBuiltIndex = true; + } + + for (index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) + { + out[it->first] = &it->second; + } + } + + // ---------------------------------------------------------------------------------- + + FileSystemArchiveFile::FileSystemArchiveFile(const std::string &path) + : mPath(path) + { + } + + Files::IStreamPtr FileSystemArchiveFile::open() + { + return Files::openConstrainedFileStream(mPath.c_str()); + } + +} diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp new file mode 100644 index 0000000000..6c8e1b82bb --- /dev/null +++ b/components/vfs/filesystemarchive.hpp @@ -0,0 +1,40 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H +#define OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H + +#include "archive.hpp" + +namespace VFS +{ + + class FileSystemArchiveFile : public File + { + public: + FileSystemArchiveFile(const std::string& path); + + virtual Files::IStreamPtr open(); + + private: + std::string mPath; + + }; + + class FileSystemArchive : public Archive + { + public: + FileSystemArchive(const std::string& path); + + virtual void listResources(std::map& out, char (*normalize_function) (char)); + + + private: + typedef std::map index; + index mIndex; + + bool mBuiltIndex; + std::string mPath; + + }; + +} + +#endif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp new file mode 100644 index 0000000000..82f4cd7bef --- /dev/null +++ b/components/vfs/manager.cpp @@ -0,0 +1,76 @@ +#include "manager.hpp" + +#include + +#include "archive.hpp" + +namespace +{ + + char strict_normalize_char(char ch) + { + return ch == '\\' ? '/' : ch; + } + + char nonstrict_normalize_char(char ch) + { + return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); + } + + void normalize_path(std::string& path, bool strict) + { + char (*normalize_char)(char) = strict ? &strict_normalize_char : &nonstrict_normalize_char; + std::transform(path.begin(), path.end(), path.begin(), normalize_char); + } + +} + +namespace VFS +{ + + Manager::Manager(bool strict) + : mStrict(strict) + { + + } + + Manager::~Manager() + { + for (std::vector::iterator it = mArchives.begin(); it != mArchives.end(); ++it) + delete *it; + mArchives.clear(); + } + + void Manager::addArchive(Archive *archive) + { + mArchives.push_back(archive); + } + + void Manager::buildIndex() + { + mIndex.clear(); + + for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) + (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); + } + + Files::IStreamPtr Manager::get(const std::string &name) const + { + std::string normalized = name; + normalize_path(normalized, mStrict); + + std::map::const_iterator found = mIndex.find(normalized); + if (found == mIndex.end()) + throw std::runtime_error("Resource '" + name + "' not found"); + return found->second->open(); + } + + bool Manager::exists(const std::string &name) const + { + std::string normalized = name; + normalize_path(normalized, mStrict); + + return mIndex.find(normalized) != mIndex.end(); + } + +} diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp new file mode 100644 index 0000000000..31538cc996 --- /dev/null +++ b/components/vfs/manager.hpp @@ -0,0 +1,52 @@ +#ifndef OPENMW_COMPONENTS_RESOURCEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCEMANAGER_H + +#include + +#include +#include + +namespace VFS +{ + + class Archive; + class File; + + /// @brief The main class responsible for loading files from a virtual file system. + /// @par Various archive types (e.g. directories on the filesystem, or compressed archives) + /// can be registered, and will be merged into a single file tree. If the same filename is + /// contained in multiple archives, the last added archive will have priority. + class Manager + { + public: + /// @param strict Use strict path handling? If enabled, no case folding will + /// be done, but slash/backslash conversions are always done. + Manager(bool strict); + + ~Manager(); + + /// Register the given archive. All files contained in it will be added to the index on the next buildIndex() call. + /// @note Takes ownership of the given pointer. + void addArchive(Archive* archive); + + /// Build the file index. Should be called when all archives have been registered. + void buildIndex(); + + /// Does a file with this name exist? + bool exists(const std::string& name) const; + + /// Retrieve a file by name. + /// @note Throws an exception if the file can not be found. + Files::IStreamPtr get(const std::string& name) const; + + private: + bool mStrict; + + std::vector mArchives; + + std::map mIndex; + }; + +} + +#endif From f843e1253880d551e84504f1c6a184dd1e950815 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Mar 2015 22:34:30 +0100 Subject: [PATCH 0024/1812] Add world space particle systems, will need more changes when emitters are added --- apps/nifosgtest/test.cpp | 1 - components/nifosg/nifloader.cpp | 47 ++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index ef2ddd6b4b..05ed2408e6 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -11,7 +11,6 @@ #include -#include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 88c944e146..a1fcbcbc9a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -192,11 +192,37 @@ namespace } }; + // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform + // that the callback is attached to. Used for certain particle systems, + // so that the particles do not move with the node they are attached to. + class InverseWorldMatrix : public osg::NodeCallback + { + public: + InverseWorldMatrix() + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + traverse(node,nv); + } + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // NIF format doesn't specify morphed normals + // No normals available in the MorphData morphGeom->setMorphNormals(false); const std::vector& morphs = morpher->data.getPtr()->mMorphs; @@ -499,6 +525,10 @@ namespace NifOsg if (!partctrl) return; + osg::Matrix particletransform; + if (!(particleflags & Nif::NiNode::ParticleFlag_LocalSpace)) + particletransform = getWorldTransform(nifNode); + int i=0; for (std::vector::const_iterator it = partctrl->particles.begin(); iactiveCount && it != partctrl->particles.end(); ++it, ++i) @@ -509,8 +539,8 @@ namespace NifOsg osgParticle::Particle* created = partsys->createParticle(&particletemplate); created->setLifeTime(500);//std::max(0.f, particle.lifespan)); - created->setVelocity(particle.velocity); - created->setPosition(particledata->vertices.at(particle.vertex)); + created->setVelocity(particle.velocity * particletransform); + created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); if (particle.vertex < int(particledata->colors.size())) @@ -534,7 +564,16 @@ namespace NifOsg partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - parentNode->addChild(geode); + + if (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + parentNode->addChild(geode); + else + { + osg::MatrixTransform* trans = new osg::MatrixTransform; + trans->setUpdateCallback(new InverseWorldMatrix); + trans->addChild(geode); + parentNode->addChild(trans); + } osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; updater->addParticleSystem(partsys); From 7c1386b62b5ca7c1aad362b98f8ff865f11007db Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Mar 2015 20:12:44 +0100 Subject: [PATCH 0025/1812] Read BSA and data dirs from openmw.cfg --- apps/nifosgtest/test.cpp | 44 +++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 05ed2408e6..7f9649e2e2 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -8,6 +8,9 @@ #include #include +#include + +#include #include @@ -53,17 +56,48 @@ private: int main(int argc, char** argv) { - if (argc < 3) + if (argc < 2) { - std::cout << "Usage: " << argv[0] << " " << std::endl; + std::cout << "Usage: " << argv[0] << " " << std::endl; return 1; } - VFS::Manager resourceMgr (false); - resourceMgr.addArchive(new VFS::BsaArchive(argv[1])); + Files::ConfigurationManager cfgMgr; + boost::program_options::options_description desc(""); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("fallback-archive", boost::program_options::value >()-> + default_value(std::vector(), "fallback-archive")->multitoken()); + + boost::program_options::variables_map variables; + cfgMgr.readConfiguration(variables, desc); + + std::vector archives = variables["fallback-archive"].as >(); + bool fsStrict = variables["fs-strict"].as(); + Files::PathContainer dataDirs; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + cfgMgr.processPaths(dataDirs); + + VFS::Manager resourceMgr (fsStrict); + Files::Collections collections (dataDirs, !fsStrict); + + for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) + { + std::string filepath = collections.getPath(*it).string(); + resourceMgr.addArchive(new VFS::BsaArchive(filepath)); + } + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); + } + resourceMgr.buildIndex(); - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[2]), std::string(argv[2]))); + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); osgViewer::Viewer viewer; From 0b4e7e59bc57978598df8e71d5b9f43a10a3fc6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 00:35:05 +0100 Subject: [PATCH 0026/1812] Revert "Seems to fix wireframe crashes" This reverts commit 31a0bbcb23101bbf3b916bc1f5100e6c4f31bf65. Better fix coming up --- apps/nifosgtest/test.cpp | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9649e2e2..4593217c84 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -22,8 +22,9 @@ class WireframeKeyHandler : public osgGA::GUIEventHandler { public: - WireframeKeyHandler() + WireframeKeyHandler(osg::Node* node) : mWireframe(false) + , mNode(node) { } @@ -36,7 +37,12 @@ public: if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) { mWireframe = !mWireframe; - // applying state from an event handler doesn't appear to be safe, so do it in the frame update + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); + mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); return true; } default: @@ -45,13 +51,9 @@ public: return false; } - bool getWireframe() const - { - return mWireframe; - } - private: bool mWireframe; + osg::Node* mNode; }; int main(int argc, char** argv) @@ -128,28 +130,11 @@ int main(int argc, char** argv) viewer.setUpViewInWindow(0, 0, 800, 600); viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - - WireframeKeyHandler* keyHandler = new WireframeKeyHandler; - - viewer.addEventHandler(keyHandler); + viewer.addEventHandler(new WireframeKeyHandler(root)); viewer.addEventHandler(new osgViewer::StatsHandler); - bool wireframe = false; - while (!viewer.done()) { - - if (wireframe != keyHandler->getWireframe()) - { - wireframe = keyHandler->getWireframe(); - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - wireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - root->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, wireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - } - viewer.frame(); for (unsigned int i=0; i Date: Thu, 19 Mar 2015 00:37:33 +0100 Subject: [PATCH 0027/1812] Better fix for wireframe crashes --- apps/nifosgtest/test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 4593217c84..1c34afbc47 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -131,6 +131,11 @@ int main(int argc, char** argv) viewer.realize(); viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); + + // We're going to change this from the event callback, set the variance to DYNAMIC so that + // we don't interfere with the draw thread. + root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); + viewer.addEventHandler(new osgViewer::StatsHandler); while (!viewer.done()) From 79c2138e53a6f62739db0260358f189bee45e130 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 01:45:01 +0100 Subject: [PATCH 0028/1812] Port ResourceHelpers to new VFS --- components/esmterrain/storage.cpp | 3 ++- components/misc/resourcehelpers.cpp | 42 +++++++++++++++-------------- components/misc/resourcehelpers.hpp | 17 +++++++----- components/nifosg/nifloader.cpp | 21 +++------------ 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index d4a0a0df2c..84a7ef5680 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -282,7 +282,8 @@ namespace ESMTerrain const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); //TODO this is needed due to MWs messed up texture handling - std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); + assert(0 && "no vfs here yet"); + std::string texture = ltex->mTexture; //Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); return texture; } diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index dc08b352a6..0c2635752d 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -1,8 +1,10 @@ #include "resourcehelpers.hpp" +#include + #include -#include +#include namespace { @@ -29,8 +31,8 @@ namespace bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) { - Ogre::String::size_type pos = path.rfind('.'); - if(pos != Ogre::String::npos && path.compare(pos, path.length() - pos, ".dds") != 0) + std::string::size_type pos = path.rfind('.'); + if(pos != std::string::npos && path.compare(pos, path.length() - pos, ".dds") != 0) { path.replace(pos, path.length(), ".dds"); return true; @@ -38,7 +40,7 @@ bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) return false; } -std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath) +std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath, const VFS::Manager* vfs) { /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all @@ -64,65 +66,65 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev // since we know all (GOTY edition or less) textures end // in .dds, we change the extension bool changedToDds = changeExtensionToDds(correctedPath); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) + if (vfs->exists(correctedPath)) return correctedPath; // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) - if (changedToDds && Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(origExt)) + if (changedToDds && vfs->exists(origExt)) return origExt; // fall back to a resource in the top level directory if it exists std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + if (vfs->exists(fallback)) return fallback; if (changedToDds) { fallback = topLevelDirectory + "\\" + getBasename(origExt); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + if (vfs->exists(fallback)) return fallback; } return correctedPath; } -std::string Misc::ResourceHelpers::correctTexturePath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctTexturePath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "textures"; - return correctResourcePath(dir, resPath); + return correctResourcePath(dir, resPath, vfs); } -std::string Misc::ResourceHelpers::correctIconPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctIconPath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "icons"; - return correctResourcePath(dir, resPath); + return correctResourcePath(dir, resPath, vfs); } -std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, const VFS::Manager* vfs) { static const std::string dir = "bookart"; - std::string image = correctResourcePath(dir, resPath); + std::string image = correctResourcePath(dir, resPath, vfs); return image; } -std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, int width, int height) +std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs) { - std::string image = correctBookartPath(resPath); + std::string image = correctBookartPath(resPath, vfs); // Apparently a bug with some morrowind versions, they reference the image without the size suffix. // So if the image isn't found, try appending the size. - if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(image)) + if (!vfs->exists(image)) { std::stringstream str; str << image.substr(0, image.rfind('.')) << "_" << width << "_" << height << image.substr(image.rfind('.')); - image = Misc::ResourceHelpers::correctBookartPath(str.str()); + image = Misc::ResourceHelpers::correctBookartPath(str.str(), vfs); } return image; } -std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath) +std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs) { std::string mdlname = resPath; std::string::size_type p = mdlname.rfind('\\'); @@ -132,7 +134,7 @@ std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resP mdlname.insert(mdlname.begin()+p+1, 'x'); else mdlname.insert(mdlname.begin(), 'x'); - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) + if(!vfs->exists(mdlname)) { return resPath; } diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 2ce3dce1e9..1763f77773 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -3,18 +3,23 @@ #include +namespace VFS +{ + class Manager; +} + namespace Misc { namespace ResourceHelpers { bool changeExtensionToDds(std::string &path); - std::string correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath); - std::string correctTexturePath(const std::string &resPath); - std::string correctIconPath(const std::string &resPath); - std::string correctBookartPath(const std::string &resPath); - std::string correctBookartPath(const std::string &resPath, int width, int height); + std::string correctResourcePath(const std::string &topLevelDirectory, const std::string &resPath, const VFS::Manager* vfs); + std::string correctTexturePath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctIconPath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctBookartPath(const std::string &resPath, const VFS::Manager* vfs); + std::string correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs); /// Uses "xfoo.nif" instead of "foo.nif" if available - std::string correctActorModelPath(const std::string &resPath); + std::string correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs); } } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a1fcbcbc9a..1220bb258a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // skel #include @@ -477,15 +478,7 @@ namespace NifOsg if (st.empty()) continue; - // FIXME: replace by ResourceHelpers - std::string filename (st->filename); - Misc::StringUtils::toLower(filename); - filename = "textures\\" + filename; - size_t found = filename.find(".tga"); - if (found == std::string::npos) - found = filename.find(".bmp"); - if (found != std::string::npos) - filename.replace(found, 4, ".dds"); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); // tx_creature_werewolf.dds isn't loading in the correct format without this option osgDB::Options* opts = new osgDB::Options; @@ -868,15 +861,7 @@ namespace NifOsg continue; } - // FIXME: replace by ResourceHelpers - std::string filename (st->filename); - Misc::StringUtils::toLower(filename); - filename = "textures\\" + filename; - size_t found = filename.find(".tga"); - if (found == std::string::npos) - found = filename.find(".bmp"); - if (found != std::string::npos) - filename.replace(found, 4, ".dds"); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); // tx_creature_werewolf.dds isn't loading in the correct format without this option osgDB::Options* opts = new osgDB::Options; From f8422c3ed493ad42bf68f6f6493bbecf8e5cc3aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 03:01:11 +0100 Subject: [PATCH 0029/1812] Particles mostly completed, still need to attach emitters to the correct node and handle NiBSPArrayController --- apps/nifosgtest/test.cpp | 9 +- components/CMakeLists.txt | 2 +- components/nif/nifkey.hpp | 2 + components/nifosg/controller.cpp | 13 +++ components/nifosg/controller.hpp | 18 +++ components/nifosg/nifloader.cpp | 164 ++++++++++++++++++-------- components/nifosg/nifloader.hpp | 2 +- components/nifosg/particle.cpp | 192 +++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 137 ++++++++++++++++++++++ 9 files changed, 488 insertions(+), 51 deletions(-) create mode 100644 components/nifosg/particle.cpp create mode 100644 components/nifosg/particle.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 1c34afbc47..7f9a7ce3f4 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -120,9 +121,13 @@ int main(int argc, char** argv) for (unsigned int i=0; iaddChild(trans); + for (int x=0; x<1;++x) { - root->addChild(newNode); + //root->addChild(newNode); + trans->addChild(newNode); } viewer.setSceneData(root); @@ -140,6 +145,8 @@ int main(int argc, char** argv) while (!viewer.done()) { + //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); + viewer.frame(); for (unsigned int i=0; i #include +#include "niffile.hpp" + namespace Nif { diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 041036e5bb..f6841ee619 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,8 +4,11 @@ #include #include #include + #include +#include + #include #include @@ -331,5 +334,15 @@ void FlipControllerValue::setValue(float time) tex->setImage(mTextures[curTexture].get()); } +ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl) + : mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +{ +} + +void ParticleSystemControllerValue::setValue(float time) +{ + mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 421f00277d..e82f49ec8b 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -25,6 +25,11 @@ namespace osg class StateSet; } +namespace osgParticle +{ + class Emitter; +} + namespace osgAnimation { class MorphGeometry; @@ -236,6 +241,19 @@ namespace NifOsg virtual void setValue(float time); }; + class ParticleSystemControllerValue : public ControllerValue + { + public: + ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl); + + virtual void setValue(float time); + + private: + osgParticle::Emitter* mEmitter; + float mEmitStart; + float mEmitStop; + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1220bb258a..5cdaf13ce4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -22,6 +22,11 @@ // particle #include #include +#include +#include +#include +#include +#include #include #include @@ -36,6 +41,8 @@ #include +#include "particle.hpp" + namespace { osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) @@ -124,6 +131,14 @@ namespace class UpdateBone : public osg::NodeCallback { public: + UpdateBone() {} + UpdateBone(const UpdateBone& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateBone) + // Callback method called by the NodeVisitor when visiting a node. void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -157,6 +172,7 @@ namespace : mSkelRoot(skelRootNode) { } + // TODO: add copy constructor void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -179,46 +195,11 @@ namespace traverse(node,nv); } private: + + // TODO: keeping this pointer will break when copying the scene graph; maybe retrieve it while visiting if it's NULL? osg::Node* mSkelRoot; }; - // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state - class ParticleAgeSetter : public osgParticle::Particle - { - public: - ParticleAgeSetter(float age) - : Particle() - { - _t0 = age; - } - }; - - // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform - // that the callback is attached to. Used for certain particle systems, - // so that the particles do not move with the node they are attached to. - class InverseWorldMatrix : public osg::NodeCallback - { - public: - InverseWorldMatrix() - { - } - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osg::NodePath path = nv->getNodePath(); - path.pop_back(); - - osg::MatrixTransform* trans = dynamic_cast(node); - - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); - } - traverse(node,nv); - } - }; - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; @@ -338,6 +319,8 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; + if (nifNode->recType == Nif::RC_NiBSParticleNode) + particleflags |= nifNode->flags; // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them @@ -370,7 +353,7 @@ namespace NifOsg } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, particleflags, animflags); + handleParticleSystem(nifNode, transformNode, animflags, particleflags); if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -495,9 +478,10 @@ namespace NifOsg } } - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int particleflags, int animflags) + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new osgParticle::ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -507,6 +491,8 @@ namespace NifOsg else return; + // TODO: add special handling for NiBSPArrayController + const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -516,10 +502,18 @@ namespace NifOsg partctrl = static_cast(ctrl.getPtr()); } if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; return; + } + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + + // TODO: also take into account the transform by placement in the scene osg::Matrix particletransform; - if (!(particleflags & Nif::NiNode::ParticleFlag_LocalSpace)) + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) particletransform = getWorldTransform(nifNode); int i=0; @@ -528,11 +522,12 @@ namespace NifOsg { const Nif::NiParticleSystemController::Particle& particle = *it; - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifespan - particle.lifetime)); + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); osgParticle::Particle* created = partsys->createParticle(&particletemplate); - created->setLifeTime(500);//std::max(0.f, particle.lifespan)); - created->setVelocity(particle.velocity * particletransform); + created->setLifeTime(std::max(0.f, particle.lifespan)); + osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; + created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); @@ -544,10 +539,81 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } - osg::NodeVisitor visitor; - partsys->update(0.f, visitor); - partsys->setFrozen(true); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + // ---- emitter + + osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter; + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + + osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; + if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) + counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); + else + counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); + + emitter->setCounter(counter); + + ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f, + partctrl->horizontalDir, partctrl->horizontalAngle, + partctrl->verticalDir, partctrl->verticalAngle, + partctrl->lifetime, partctrl->lifetimeRandom); + emitter->setShooter(shooter); + + osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; + placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); + placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); + placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); + + emitter->setPlacer(placer); + + // TODO: attach to the emitter node + // Note: we also assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + parentNode->addChild(emitter); + + createController(partctrl, boost::shared_ptr(new ParticleSystemControllerValue(emitter, partctrl)), animflags); + + // ----------- affector (must be after emitters in the scene graph) + osgParticle::ModularProgram* program = new osgParticle::ModularProgram; + program->setParticleSystem(partsys); + program->setReferenceFrame(rf); + parentNode->addChild(program); + for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) + { + if (e->recType == Nif::RC_NiParticleGrowFade) + { + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity* gr = static_cast(e.getPtr()); + GravityAffector* affector = new GravityAffector(gr); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + ParticleColorAffector* affector = new ParticleColorAffector(clrdata); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement? + } + else + std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + } + + // ----------- std::vector materialProps; collectMaterialProperties(nifNode, materialProps); @@ -558,7 +624,7 @@ namespace NifOsg osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - if (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); else { @@ -568,6 +634,7 @@ namespace NifOsg parentNode->addChild(trans); } + // particle system updater (after the emitters and affectors in the scene graph) osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; updater->addParticleSystem(partsys); parentNode->addChild(updater); @@ -870,6 +937,7 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setUnRefImageDataAfterApply(true); texture2d->setImage(image); unsigned int clamp = static_cast(tex.clamp); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index e521015257..5a0c901c1a 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -61,7 +61,7 @@ namespace NifOsg void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); - void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int particleflags, int animflags); + void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int animflags, int particleflags); // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp new file mode 100644 index 0000000000..3fcc02bcff --- /dev/null +++ b/components/nifosg/particle.cpp @@ -0,0 +1,192 @@ +#include "particle.hpp" + +#include + +#include + +#include + +namespace NifOsg +{ + +void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::NodePath path = nv->getNodePath(); + path.pop_back(); + + osg::MatrixTransform* trans = dynamic_cast(node); + + osg::Matrix worldMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(worldMat)); + } + traverse(node,nv); +} + +ParticleShooter::ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, float lifetime, float lifetimeRandom) + : mMinSpeed(minSpeed), mMaxSpeed(maxSpeed), mHorizontalDir(horizontalDir) + , mHorizontalAngle(horizontalAngle), mVerticalDir(verticalDir), mVerticalAngle(verticalAngle) + , mLifetime(lifetime), mLifetimeRandom(lifetimeRandom) +{ +} + +ParticleShooter::ParticleShooter() + : mMinSpeed(0.f), mMaxSpeed(0.f), mHorizontalDir(0.f) + , mHorizontalAngle(0.f), mVerticalDir(0.f), mVerticalAngle(0.f) + , mLifetime(0.f), mLifetimeRandom(0.f) +{ +} + +ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) +{ + *this = copy; +} + +void ParticleShooter::shoot(osgParticle::Particle *particle) const +{ + // NOTE: We do not use mDirection/mAngle for the initial direction. + float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(1,0,0)) + // ^ Vec3f(0,1,0) according to nifskope, TODO: test in mw + * osg::Vec3f(0,0,1); + + float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); + particle->setVelocity(dir * vel); + + // Not supposed to set this here, but there doesn't seem to be a better way of doing it + particle->setLifeTime(mLifetime + mLifetimeRandom * std::rand() / static_cast(RAND_MAX)); +} + +GrowFadeAffector::GrowFadeAffector(float growTime, float fadeTime) + : mGrowTime(growTime) + , mFadeTime(fadeTime) + , mCachedDefaultSize(0.f) +{ +} + +GrowFadeAffector::GrowFadeAffector() + : mGrowTime(0.f) + , mFadeTime(0.f) + , mCachedDefaultSize(0.f) +{ + +} + +GrowFadeAffector::GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +void GrowFadeAffector::beginOperate(osgParticle::Program *program) +{ + mCachedDefaultSize = program->getParticleSystem()->getDefaultParticleTemplate().getSizeRange().minimum; +} + +void GrowFadeAffector::operate(osgParticle::Particle* particle, double /* dt */) +{ + float size = mCachedDefaultSize; + if (particle->getAge() < mGrowTime && mGrowTime != 0.f) + size *= particle->getAge() / mGrowTime; + if (particle->getLifeTime() - particle->getAge() < mFadeTime && mFadeTime != 0.f) + size *= (particle->getLifeTime() - particle->getAge()) / mFadeTime; + particle->setSizeRange(osgParticle::rangef(size, size)); +} + +ParticleColorAffector::ParticleColorAffector(const Nif::NiColorData *clrdata) + : mData(*clrdata) +{ +} + +ParticleColorAffector::ParticleColorAffector() +{ + +} + +ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +osg::Vec4f ParticleColorAffector::interpolate(const float time, const Nif::Vector4KeyMap::MapType &keys) +{ + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + Nif::Vector4KeyMap::MapType::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + Nif::Vector4KeyMap::MapType::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; +} + +void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) +{ + float time = static_cast(particle->getAge()/particle->getLifeTime()); + osg::Vec4f color = interpolate(time, mData.mKeyMap.mKeys); + + particle->setColorRange(osgParticle::rangev4(color, color)); +} + +GravityAffector::GravityAffector(const Nif::NiGravity *gravity) + : mForce(gravity->mForce) + , mType(static_cast(gravity->mType)) + , mPosition(gravity->mPosition) + , mDirection(gravity->mDirection) +{ +} + +GravityAffector::GravityAffector() + : mForce(0), mType(Type_Wind) +{ + +} + +GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) +{ + *this = copy; +} + +void GravityAffector::beginOperate(osgParticle::Program* program) +{ + bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); + if (mType == Type_Wind) + mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + else // Type_Point + mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; +} + +void GravityAffector::operate(osgParticle::Particle *particle, double dt) +{ + switch (mType) + { + case Type_Wind: + particle->addVelocity(mCachedWorldPositionDirection * mForce * dt); + break; + case Type_Point: + { + osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); + diff.normalize(); + particle->addVelocity(diff * mForce * dt); + break; + } + } +} + +} diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp new file mode 100644 index 0000000000..0336d3392b --- /dev/null +++ b/components/nifosg/particle.hpp @@ -0,0 +1,137 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_PARTICLE_H +#define OPENMW_COMPONENTS_NIFOSG_PARTICLE_H + +#include +#include +#include + +#include + +#include +#include + +namespace Nif +{ + class NiGravity; +} + +namespace NifOsg +{ + + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state + class ParticleAgeSetter : public osgParticle::Particle + { + public: + ParticleAgeSetter(float age) + : Particle() + { + _t0 = age; + } + }; + + // Node callback used to set the inverse of the parent's world matrix on the MatrixTransform + // that the callback is attached to. Used for certain particle systems, + // so that the particles do not move with the node they are attached to. + class InverseWorldMatrix : public osg::NodeCallback + { + public: + InverseWorldMatrix() + { + } + InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) + : osg::NodeCallback(), osg::Object() + { + } + + META_Object(NifOsg, InverseWorldMatrix) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + }; + + class ParticleShooter : public osgParticle::Shooter + { + public: + ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, + float lifetime, float lifetimeRandom); + ParticleShooter(); + ParticleShooter(const Shooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, ParticleShooter) + + virtual void shoot(osgParticle::Particle* particle) const; + + private: + float mMinSpeed; + float mMaxSpeed; + float mHorizontalDir; + float mHorizontalAngle; + float mVerticalDir; + float mVerticalAngle; + float mLifetime; + float mLifetimeRandom; + }; + + class GrowFadeAffector : public osgParticle::Operator + { + public: + GrowFadeAffector(float growTime, float fadeTime); + GrowFadeAffector(); + GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, GrowFadeAffector) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + float mGrowTime; + float mFadeTime; + + float mCachedDefaultSize; + }; + + class ParticleColorAffector : public osgParticle::Operator + { + public: + ParticleColorAffector(const Nif::NiColorData* clrdata); + ParticleColorAffector(); + ParticleColorAffector(const ParticleColorAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, ParticleColorAffector) + + // TODO: very similar to vec3 version, refactor to a template + osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys); + + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + Nif::NiColorData mData; + }; + + class GravityAffector : public osgParticle::Operator + { + public: + GravityAffector(const Nif::NiGravity* gravity); + GravityAffector(); + GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(NifOsg, GravityAffector) + + virtual void operate(osgParticle::Particle* particle, double dt); + virtual void beginOperate(osgParticle::Program *); + + private: + float mForce; + enum ForceType { + Type_Wind, + Type_Point + }; + ForceType mType; + osg::Vec3f mPosition; + osg::Vec3f mDirection; + osg::Vec3f mCachedWorldPositionDirection; + }; + +} + +#endif From 00ab47418865d5aba482af96f291ae77dc29b161 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 16:22:01 +0100 Subject: [PATCH 0030/1812] More work on copy constructors --- components/nifosg/controller.hpp | 2 ++ components/nifosg/nifloader.cpp | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e82f49ec8b..cc176e76e6 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -111,6 +111,8 @@ namespace NifOsg class NodeTargetValue : public ControllerValue { protected: + // TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later + // instead, controllers can be a Node added as child of their target osg::Node *mNode; public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5cdaf13ce4..a92baee790 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -168,11 +168,12 @@ namespace class InvertBoneMatrix : public osg::NodeCallback { public: - InvertBoneMatrix(osg::Node* skelRootNode) - : mSkelRoot(skelRootNode) - { - } - // TODO: add copy constructor + InvertBoneMatrix() {} + + InvertBoneMatrix(const InvertBoneMatrix& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) {} + + META_Object(NifOsg, InvertBoneMatrix) void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -183,21 +184,20 @@ namespace osg::MatrixTransform* trans = dynamic_cast(node); - osg::NodePath::iterator found = std::find(path.begin(), path.end(), mSkelRoot); - if (found != path.end()) + for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - path.erase(path.begin(),found+1); - - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); + if (dynamic_cast(*it)) + { + path.erase(path.begin(), it+1); + // the bone's transform in skeleton space + osg::Matrix boneMat = osg::computeLocalToWorld( path ); + trans->setMatrix(osg::Matrix::inverse(boneMat)); + break; + } } } traverse(node,nv); } - private: - - // TODO: keeping this pointer will break when copying the scene graph; maybe retrieve it while visiting if it's NULL? - osg::Node* mSkelRoot; }; osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -793,7 +793,7 @@ namespace NifOsg rig->setInfluenceMap(map); osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix(mSkeleton)); + trans->setUpdateCallback(new InvertBoneMatrix()); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); From ab3c28eb96e0cc6b11562641792a9eda8c960757 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:00:16 +0100 Subject: [PATCH 0031/1812] Use template function for interpolation --- components/nifosg/controller.cpp | 51 -------------------------------- components/nifosg/controller.hpp | 28 ++++++++++++++++-- components/nifosg/particle.cpp | 31 ++----------------- components/nifosg/particle.hpp | 4 ++- 4 files changed, 32 insertions(+), 82 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index f6841ee619..bbb2f57fe6 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -16,57 +16,6 @@ namespace NifOsg { -float ValueInterpolator::interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def) const -{ - if (keys.size() == 0) - return def; - - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::FloatKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::FloatKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::FloatKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - -osg::Vec3f ValueInterpolator::interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::KeyT* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector3KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) : mDeltaInput(deltaInput) , mFrequency(ctrl->frequency) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index cc176e76e6..c92a778165 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -42,9 +42,33 @@ namespace NifOsg class ValueInterpolator { protected: - float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const; + template + T interpKey (const std::map< float, Nif::KeyT >& keys, float time, T defaultValue = T()) const + { + if (keys.size() == 0) + return defaultValue; - osg::Vec3f interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const; + if(time <= keys.begin()->first) + return keys.begin()->second.mValue; + + typename std::map< float, Nif::KeyT >::const_iterator it = keys.lower_bound(time); + if (it != keys.end()) + { + float aTime = it->first; + const Nif::KeyT* aKey = &it->second; + + assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function + + typename std::map< float, Nif::KeyT >::const_iterator last = --it; + float aLastTime = last->first; + const Nif::KeyT* aLastKey = &last->second; + + float a = (time - aLastTime) / (aTime - aLastTime); + return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + } + else + return keys.rbegin()->second.mValue; + } }; // FIXME: Should not be here. We might also want to use this for non-NIF model formats diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 3fcc02bcff..58501763b2 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -45,11 +45,10 @@ ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::Co void ParticleShooter::shoot(osgParticle::Particle *particle) const { - // NOTE: We do not use mDirection/mAngle for the initial direction. float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(1,0,0)) - // ^ Vec3f(0,1,0) according to nifskope, TODO: test in mw + float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); + osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); @@ -111,34 +110,10 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, *this = copy; } -osg::Vec4f ParticleColorAffector::interpolate(const float time, const Nif::Vector4KeyMap::MapType &keys) -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector4KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::KeyT* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector4KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; -} - void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpolate(time, mData.mKeyMap.mKeys); + osg::Vec4f color = interpKey(mData.mKeyMap.mKeys, time, osg::Vec4f(1,1,1,1)); particle->setColorRange(osgParticle::rangev4(color, color)); } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 0336d3392b..13010fbac9 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -10,6 +10,8 @@ #include #include +#include "controller.hpp" // ValueInterpolator + namespace Nif { class NiGravity; @@ -90,7 +92,7 @@ namespace NifOsg float mCachedDefaultSize; }; - class ParticleColorAffector : public osgParticle::Operator + class ParticleColorAffector : public osgParticle::Operator, public ValueInterpolator { public: ParticleColorAffector(const Nif::NiColorData* clrdata); From 49c2da27b386a9f4cecfe36cff5039f3be17a227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:21:15 +0100 Subject: [PATCH 0032/1812] OpenCS compiles and runs again (no rendering) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 122 +----------------- apps/opencs/editor.hpp | 17 +-- apps/opencs/main.cpp | 12 +- apps/opencs/model/settings/usersettings.cpp | 4 +- apps/opencs/model/world/resources.cpp | 4 +- apps/opencs/view/render/object.cpp | 4 +- apps/opencs/view/render/overlaymask.cpp | 52 -------- apps/opencs/view/render/overlaymask.hpp | 42 ------ apps/opencs/view/render/overlaysystem.cpp | 34 ----- apps/opencs/view/render/overlaysystem.hpp | 26 ---- .../view/render/pagedworldspacewidget.cpp | 7 +- .../view/render/pagedworldspacewidget.hpp | 1 - apps/opencs/view/render/scenewidget.cpp | 8 -- apps/opencs/view/render/scenewidget.hpp | 2 - apps/opencs/view/world/physicssystem.cpp | 5 +- apps/opencs/view/world/subviews.cpp | 2 +- components/CMakeLists.txt | 3 +- libs/openengine/bullet/physic.cpp | 2 + 19 files changed, 30 insertions(+), 319 deletions(-) delete mode 100644 apps/opencs/view/render/overlaymask.cpp delete mode 100644 apps/opencs/view/render/overlaymask.hpp delete mode 100644 apps/opencs/view/render/overlaysystem.cpp delete mode 100644 apps/opencs/view/render/overlaysystem.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5ff..3548c175a4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate + lightingbright object cell terrainstorage textoverlay mousestate ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1d31c83969..92fd40492c 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -16,13 +16,12 @@ #include #include -#include #include "model/doc/document.hpp" #include "model/world/data.hpp" -CS::Editor::Editor (OgreInit::OgreInit& ogreInit) -: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), +CS::Editor::Editor () +: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock() { @@ -33,14 +32,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); mSettings.setModel (CSMSettings::UserSettings::instance()); - ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); + //NifOgre::Loader::setShowMarkers(true); - NifOgre::Loader::setShowMarkers(true); - - mOverlaySystem.reset (new CSVRender::OverlaySystem); - - Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, - mFsStrict); + //Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, + // mFsStrict); mDocumentManager.listResources(); @@ -324,113 +319,10 @@ int CS::Editor::run() return QApplication::exec(); } -std::auto_ptr CS::Editor::setupGraphics() -{ - std::string renderer = -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - "Direct3D9 Rendering Subsystem"; -#else - "OpenGL Rendering Subsystem"; -#endif - std::string renderSystem = mUserSettings.setting("Video/render system", renderer.c_str()).toStdString(); - - Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName(renderSystem)); - - // Initialise Ogre::OverlaySystem after Ogre::Root but before initialisation - mOverlaySystem.get(); - - Ogre::Root::getSingleton().initialise(false); - - // Create a hidden background window to keep resources - Ogre::NameValuePairList params; - params.insert(std::make_pair("title", "")); - - std::string antialiasing = mUserSettings.settingValue("Video/antialiasing").toStdString(); - if(antialiasing == "MSAA 16") antialiasing = "16"; - else if(antialiasing == "MSAA 8") antialiasing = "8"; - else if(antialiasing == "MSAA 4") antialiasing = "4"; - else if(antialiasing == "MSAA 2") antialiasing = "2"; - else antialiasing = "0"; - params.insert(std::make_pair("FSAA", antialiasing)); - - params.insert(std::make_pair("vsync", "false")); - params.insert(std::make_pair("hidden", "true")); -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - params.insert(std::make_pair("macAPI", "cocoa")); -#endif - // NOTE: fullscreen mode not supported (doesn't really make sense for opencs) - Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms); - hiddenWindow->setActive(false); - - sh::OgrePlatform* platform = - new sh::OgrePlatform ("General", (mResources / "materials").string()); - // for font used in overlays - Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), - "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); + //Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), + // "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - if (!boost::filesystem::exists (mCfgMgr.getCachePath())) - boost::filesystem::create_directories (mCfgMgr.getCachePath()); - - platform->setCacheFolder (mCfgMgr.getCachePath().string()); - - std::auto_ptr factory (new sh::Factory (platform)); - - QString shLang = mUserSettings.settingValue("General/shader mode"); - QString rend = renderSystem.c_str(); - bool openGL = rend.contains(QRegExp("^OpenGL", Qt::CaseInsensitive)); - bool glES = rend.contains(QRegExp("^OpenGL ES", Qt::CaseInsensitive)); - - // force shader language based on render system - if(shLang == "" - || (openGL && shLang == "hlsl") - || (!openGL && shLang == "glsl") - || (glES && shLang != "glsles")) - { - shLang = openGL ? (glES ? "glsles" : "glsl") : "hlsl"; - //no group means "General" group in the "ini" file standard - mUserSettings.setDefinitions("shader mode", (QStringList() << shLang)); - } - enum sh::Language lang; - if(shLang == "glsl") lang = sh::Language_GLSL; - else if(shLang == "glsles") lang = sh::Language_GLSLES; - else if(shLang == "hlsl") lang = sh::Language_HLSL; - else lang = sh::Language_CG; - - factory->setCurrentLanguage (lang); - factory->setWriteSourceCache (true); - factory->setReadSourceCache (true); - factory->setReadMicrocodeCache (true); - factory->setWriteMicrocodeCache (true); - - factory->loadAllFiles(); - - bool shaders = mUserSettings.setting("3d-render/shaders", QString("true")) == "true" ? true : false; - sh::Factory::getInstance ().setShadersEnabled (shaders); - - std::string fog = mUserSettings.setting("Shader/fog", QString("true")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("fog", fog); - - - std::string shadows = mUserSettings.setting("Shader/shadows", QString("false")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("shadows", shadows); - - std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString(); - sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm); - - std::string render_refraction = mUserSettings.setting("Shader/render_refraction", QString("false")).toStdString(); - sh::Factory::getInstance ().setGlobalSetting ("render_refraction", render_refraction); - - // internal setting - may be switched on or off by the use of shader configurations - sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); - - std::string num_lights = mUserSettings.setting("3d-render-adv/num_lights", QString("8")).toStdString(); - sh::Factory::getInstance ().setGlobalSetting ("num_lights", num_lights); - - /// \todo add more configurable shiny settings - - return factory; -} void CS::Editor::documentAdded (CSMDoc::Document *document) { diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 273f0825b8..da4d639858 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -11,16 +11,12 @@ #include #include -#include - #ifndef Q_MOC_RUN #include #endif #include -#include - #include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" @@ -30,12 +26,6 @@ #include "view/doc/newgame.hpp" #include "view/settings/dialog.hpp" -#include "view/render/overlaysystem.hpp" - -namespace OgreInit -{ - class OgreInit; -} namespace CS { @@ -43,10 +33,8 @@ namespace CS { Q_OBJECT - Nif::Cache mNifCache; Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; - std::auto_ptr mOverlaySystem; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; @@ -71,7 +59,7 @@ namespace CS public: - Editor (OgreInit::OgreInit& ogreInit); + Editor (); ~Editor (); bool makeIPCServer(); @@ -80,9 +68,6 @@ namespace CS int run(); ///< \return error status - std::auto_ptr setupGraphics(); - ///< The returned factory must persist at least as long as *this. - private slots: void createGame(); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index b11561c135..eb5dcc64e6 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -9,10 +9,6 @@ #include #include -#include - -#include - #include "model/world/universalid.hpp" #ifdef Q_OS_MAC @@ -53,10 +49,6 @@ int main(int argc, char *argv[]) qRegisterMetaType ("std::string"); qRegisterMetaType ("CSMWorld::UniversalId"); - OgreInit::OgreInit ogreInit; - - std::auto_ptr shinyFactory; - Application application (argc, argv); #ifdef Q_OS_MAC @@ -80,15 +72,13 @@ int main(int argc, char *argv[]) application.setWindowIcon (QIcon (":./openmw-cs.png")); - CS::Editor editor (ogreInit); + CS::Editor editor; if(!editor.makeIPCServer()) { editor.connectToIPCServer(); return 0; } - - shinyFactory = editor.setupGraphics(); return editor.run(); } catch (std::exception& e) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c35..0aa1cb4ad7 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -472,11 +472,11 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, if(settingKey == "3d-render-adv/num_lights" && !list.empty()) { - sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); + //sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); } else if(settingKey == "3d-render/shaders" && !list.empty()) { - sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); + //sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); } emit userSettingUpdated (settingKey, list); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 13c8df84d1..25fada93a5 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -15,6 +15,7 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T { int baseSize = mBaseDirectory.size(); + /* Ogre::StringVector resourcesGroups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); @@ -61,6 +62,7 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } } + */ } int CSMWorld::Resources::getSize() const @@ -105,4 +107,4 @@ int CSMWorld::Resources::searchId (const std::string& id) const CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const { return mType; -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3607fb415d..b54551c96d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -77,8 +77,8 @@ void CSVRender::Object::update() } else { - mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); - mObject->setVisibilityFlags (Element_Reference); + //mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); + //mObject->setVisibilityFlags (Element_Reference); if (mPhysics && !mReferenceId.empty()) { diff --git a/apps/opencs/view/render/overlaymask.cpp b/apps/opencs/view/render/overlaymask.cpp deleted file mode 100644 index 09f020354d..0000000000 --- a/apps/opencs/view/render/overlaymask.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "overlaymask.hpp" - -#include -#include - -#include "textoverlay.hpp" -#include "../../model/world/cellcoordinates.hpp" - -namespace CSVRender -{ - -// ideas from http://www.ogre3d.org/forums/viewtopic.php?f=5&t=44828#p486334 -OverlayMask::OverlayMask(std::map &overlays, Ogre::Viewport* viewport) - : mTextOverlays(overlays), mViewport(viewport) -{ -} - -OverlayMask::~OverlayMask() -{ -} - -void OverlayMask::setViewport(Ogre::Viewport *viewport) -{ - mViewport = viewport; -} - -void OverlayMask::preViewportUpdate(const Ogre::RenderTargetViewportEvent &event) -{ - if(event.source == mViewport) - { - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - for(Ogre::OverlayManager::OverlayMapIterator iter = overlayMgr.getOverlayIterator(); - iter.hasMoreElements();) - { - Ogre::Overlay* item = iter.getNext(); - for(Ogre::Overlay::Overlay2DElementsIterator it = item->get2DElementsIterator(); - it.hasMoreElements();) - { - Ogre::OverlayContainer* container = it.getNext(); - if(container) container->hide(); - } - } - - std::map::iterator it = mTextOverlays.begin(); - for(; it != mTextOverlays.end(); ++it) - { - it->second->show(true); - } - } -} - -} diff --git a/apps/opencs/view/render/overlaymask.hpp b/apps/opencs/view/render/overlaymask.hpp deleted file mode 100644 index ec050cac43..0000000000 --- a/apps/opencs/view/render/overlaymask.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef OPENCS_VIEW_OVERLAYMASK_H -#define OPENCS_VIEW_OVERLAYMASK_H - -#include - -namespace Ogre -{ - class Viewport; - class RendertargetViewportEvent; -} - -namespace CSMWorld -{ - class CellCoordinates; -} - -namespace CSVRender -{ - class TextOverlay; - - class OverlayMask : public Ogre::RenderTargetListener - { - - std::map &mTextOverlays; - Ogre::Viewport* mViewport; - - public: - - OverlayMask(std::map &overlays, - Ogre::Viewport* viewport); - - virtual ~OverlayMask(); - - void setViewport(Ogre::Viewport *viewport); - - protected: - - virtual void preViewportUpdate(const Ogre::RenderTargetViewportEvent &event); - }; -} - -#endif // OPENCS_VIEW_OVERLAYMASK_H diff --git a/apps/opencs/view/render/overlaysystem.cpp b/apps/opencs/view/render/overlaysystem.cpp deleted file mode 100644 index f565f5af06..0000000000 --- a/apps/opencs/view/render/overlaysystem.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "overlaysystem.hpp" - -#include - -#include - -namespace CSVRender -{ - OverlaySystem *OverlaySystem::mOverlaySystemInstance = 0; - - OverlaySystem::OverlaySystem() - { - assert(!mOverlaySystemInstance); - mOverlaySystemInstance = this; - mOverlaySystem = new Ogre::OverlaySystem(); - } - - OverlaySystem::~OverlaySystem() - { - delete mOverlaySystem; - } - - OverlaySystem &OverlaySystem::instance() - { - assert(mOverlaySystemInstance); - return *mOverlaySystemInstance; - } - - Ogre::OverlaySystem *OverlaySystem::get() - { - return mOverlaySystem; - } -} - diff --git a/apps/opencs/view/render/overlaysystem.hpp b/apps/opencs/view/render/overlaysystem.hpp deleted file mode 100644 index f8a78f3295..0000000000 --- a/apps/opencs/view/render/overlaysystem.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef OPENCS_VIEW_OVERLAYSYSTEM_H -#define OPENCS_VIEW_OVERLAYSYSTEM_H - -namespace Ogre -{ - class OverlaySystem; -} - -namespace CSVRender -{ - class OverlaySystem - { - Ogre::OverlaySystem *mOverlaySystem; - static OverlaySystem *mOverlaySystemInstance; - - public: - - OverlaySystem(); - ~OverlaySystem(); - static OverlaySystem &instance(); - - Ogre::OverlaySystem *get(); - }; -} - -#endif // OPENCS_VIEW_OVERLAYSYSTEM_H diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cf9edb5483..90181a3679 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -15,7 +15,6 @@ #include #include "textoverlay.hpp" -#include "overlaymask.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -160,11 +159,13 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() textDisp->setDesc(desc); // FIXME: config setting textDisp->update(); mTextOverlays.insert(std::make_pair(*iter, textDisp)); + /* if(!mOverlayMask) { mOverlayMask = new OverlayMask(mTextOverlays, getViewport()); addRenderTargetListener(mOverlayMask); } + */ modified = true; } @@ -342,7 +343,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), - mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL) + mControlElements(NULL), mDisplayCellCoord(true) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -371,11 +372,13 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() delete iter->second; } + /* if(mOverlayMask) { removeRenderTargetListener(mOverlayMask); delete mOverlayMask; } + */ } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 3db6ee4edb..22c6ed4786 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -29,7 +29,6 @@ namespace CSVRender CSVWidget::SceneToolToggle *mControlElements; bool mDisplayCellCoord; std::map mTextOverlays; - OverlayMask *mOverlayMask; private: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 55cf039fcd..3a660b5fd2 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,14 +11,12 @@ #include #include #include -#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" #include "navigation.hpp" #include "lighting.hpp" -#include "overlaysystem.hpp" namespace CSVRender { @@ -61,9 +59,6 @@ namespace CSVRender setLighting (&mLightingDay); - mOverlaySystem = OverlaySystem::instance().get(); - mSceneMgr->addRenderQueueListener(mOverlaySystem); - QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); @@ -165,9 +160,6 @@ namespace CSVRender if (mWindow) Ogre::Root::getSingleton().destroyRenderTarget (mWindow); - if (mSceneMgr) - mSceneMgr->removeRenderQueueListener (mOverlaySystem); - if (mSceneMgr) Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 699d6a7a56..c570388696 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -15,7 +15,6 @@ namespace Ogre class SceneManager; class RenderWindow; class Viewport; - class OverlaySystem; class RenderTargetListener; } @@ -99,7 +98,6 @@ namespace CSVRender Ogre::SceneManager* mSceneMgr; Ogre::RenderWindow* mWindow; Ogre::Viewport *mViewport; - Ogre::OverlaySystem *mOverlaySystem; Navigation *mNavigation; Lighting *mLighting; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 2cbe17dcfa..4e23c185ae 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -16,8 +16,9 @@ namespace CSVWorld PhysicsSystem::PhysicsSystem() { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); + //mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + mEngine = 0; } PhysicsSystem::~PhysicsSystem() diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c5d969d0df..d0b52a9ffc 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -170,4 +170,4 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 475f9d01f1..311b980391 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -106,7 +106,8 @@ add_component_dir (translation translation ) -add_definitions(-DTERRAIN_USE_SHADER=1) +#add_definitions(-DTERRAIN_USE_SHADER=1) +add_definitions(-DTERRAIN_USE_SHADER=0) add_component_dir (terrain quadtreenode chunk world defaultworld terraingrid storage material buffercache defs ) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ef00a0e13..a0259a11fd 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -82,12 +82,14 @@ namespace Physic , mWalkingOnWater(false) , mCanWaterWalk(false) { + /* if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) { mHalfExtents = Ogre::Vector3(0.f); mMeshTranslation = Ogre::Vector3(0.f); mMeshOrientation = Ogre::Quaternion::IDENTITY; } + */ // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) From 40fc09772290dc16ab5026bb8d42b499a0e59a1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 17:49:41 +0100 Subject: [PATCH 0033/1812] OpenCS: use the new VFS, restored resource tables --- apps/opencs/editor.cpp | 22 ++----- apps/opencs/editor.hpp | 8 +++ apps/opencs/model/doc/documentmanager.cpp | 12 ++-- apps/opencs/model/doc/documentmanager.hpp | 11 +++- apps/opencs/model/world/resources.cpp | 64 ++++++++------------ apps/opencs/model/world/resources.hpp | 7 ++- apps/opencs/model/world/resourcesmanager.cpp | 18 +++--- apps/opencs/model/world/resourcesmanager.hpp | 10 ++- components/CMakeLists.txt | 2 +- components/vfs/manager.cpp | 5 ++ components/vfs/manager.hpp | 3 + components/vfs/registerarchives.cpp | 42 +++++++++++++ components/vfs/registerarchives.hpp | 15 +++++ 13 files changed, 143 insertions(+), 76 deletions(-) create mode 100644 components/vfs/registerarchives.cpp create mode 100644 components/vfs/registerarchives.hpp diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 92fd40492c..3c4ce6868e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,21 +1,13 @@ #include "editor.hpp" -#include - #include #include #include #include -#include -#include - -#include -#include - -#include -#include +#include +#include #include "model/doc/document.hpp" #include "model/world/data.hpp" @@ -34,10 +26,11 @@ CS::Editor::Editor () //NifOgre::Loader::setShowMarkers(true); - //Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, - // mFsStrict); + mVFS.reset(new VFS::Manager(mFsStrict)); - mDocumentManager.listResources(); + VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true); + + mDocumentManager.setVFS(mVFS.get()); mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); @@ -74,9 +67,6 @@ CS::Editor::~Editor () if(mServer && boost::filesystem::exists(mPid)) static_cast ( // silence coverity warning remove(mPid.string().c_str())); // ignore any error - - // cleanup global resources used by OEngine - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index da4d639858..e973b9c558 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -27,12 +27,20 @@ #include "view/settings/dialog.hpp" +namespace VFS +{ + class Manager; +} + namespace CS { class Editor : public QObject { Q_OBJECT + // FIXME: should be moved to document, so we can have different resources for each opened project + std::auto_ptr mVFS; + Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 9b807225c9..ecff4bbed6 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -90,11 +90,6 @@ void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector mBlacklistedScripts; + VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -56,8 +62,7 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - /// Ask OGRE for a list of available resources. - void listResources(); + void setVFS(const VFS::Manager* vfs); private: @@ -99,4 +104,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 25fada93a5..158793173b 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -7,62 +7,50 @@ #include +#include + #include -CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type, +CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions) : mBaseDirectory (baseDirectory), mType (type) { int baseSize = mBaseDirectory.size(); - /* - Ogre::StringVector resourcesGroups = - Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); - - for (Ogre::StringVector::iterator iter (resourcesGroups.begin()); - iter!=resourcesGroups.end(); ++iter) + const std::map& index = vfs->getIndex(); + for (std::map::const_iterator it = index.begin(); it != index.end(); ++it) { - if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect") + std::string filepath = it->first; + if (static_cast (filepath.size())begin()); - iter!=resources->end(); ++iter) + if (extensions) { - if (static_cast (iter->size())substr (0, baseSize)!=mBaseDirectory || - ((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\')) + std::string::size_type index = filepath.find_last_of ('.'); + + if (index==std::string::npos) continue; - if (extensions) - { - std::string::size_type index = iter->find_last_of ('.'); + std::string extension = filepath.substr (index+1); - if (index==std::string::npos) - continue; + int i = 0; - std::string extension = iter->substr (index+1); + for (; extensions[i]; ++i) + if (extensions[i]==extension) + break; - int i = 0; - - for (; extensions[i]; ++i) - if (extensions[i]==extension) - break; - - if (!extensions[i]) - continue; - } - - std::string file = iter->substr (baseSize+1); - mFiles.push_back (file); - std::replace (file.begin(), file.end(), '\\', '/'); - mIndex.insert (std::make_pair ( - Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); + if (!extensions[i]) + continue; } + + std::string file = filepath.substr (baseSize+1); + mFiles.push_back (file); + std::replace (file.begin(), file.end(), '\\', '/'); + mIndex.insert (std::make_pair ( + Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } - */ } int CSMWorld::Resources::getSize() const diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index 9c1c76b6f2..d6998da9f0 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -7,6 +7,11 @@ #include "universalid.hpp" +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class Resources @@ -19,7 +24,7 @@ namespace CSMWorld public: /// \param type Type of resources in this table. - Resources (const std::string& baseDirectory, UniversalId::Type type, + Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions = 0); int getSize() const; diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 50014f4b5c..218937924d 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -10,16 +10,18 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::listResources() +void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) { + mResources.clear(); + static const char * const sMeshTypes[] = { "nif", 0 }; - addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes)); - addResources (Resources ("icons", UniversalId::Type_Icon)); - addResources (Resources ("music", UniversalId::Type_Music)); - addResources (Resources ("sound", UniversalId::Type_SoundRes)); - addResources (Resources ("textures", UniversalId::Type_Texture)); - addResources (Resources ("videos", UniversalId::Type_Video)); + addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); + addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); + addResources (Resources (vfs, "music", UniversalId::Type_Music)); + addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); + addResources (Resources (vfs, "textures", UniversalId::Type_Texture)); + addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const @@ -30,4 +32,4 @@ const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type ty throw std::logic_error ("Unknown resource type"); return iter->second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 77f210c478..ee939389f9 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -6,6 +6,11 @@ #include "universalid.hpp" #include "resources.hpp" +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class ResourcesManager @@ -18,11 +23,10 @@ namespace CSMWorld public: - /// Ask OGRE for a list of available resources. - void listResources(); + void setVFS(const VFS::Manager* vfs); const Resources& get (UniversalId::Type type) const; }; } -#endif \ No newline at end of file +#endif diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 311b980391..a78f164a61 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -35,7 +35,7 @@ add_component_dir (bsa ) add_component_dir (vfs - manager archive bsaarchive filesystemarchive + manager archive bsaarchive filesystemarchive registerarchives ) add_component_dir (nif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 82f4cd7bef..d0e0cf5862 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -73,4 +73,9 @@ namespace VFS return mIndex.find(normalized) != mIndex.end(); } + const std::map& Manager::getIndex() const + { + return mIndex; + } + } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 31538cc996..ebbec7d15b 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -35,6 +35,9 @@ namespace VFS /// Does a file with this name exist? bool exists(const std::string& name) const; + /// Get a complete list of files from all archives + const std::map& getIndex() const; + /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. Files::IStreamPtr get(const std::string& name) const; diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp new file mode 100644 index 0000000000..cd077356f7 --- /dev/null +++ b/components/vfs/registerarchives.cpp @@ -0,0 +1,42 @@ +#include "registerarchives.hpp" + +#include +#include +#include + +namespace VFS +{ + + void registerArchives(VFS::Manager *vfs, const Files::Collections &collections, const std::vector &archives, bool useLooseFiles) + { + const Files::PathContainer& dataDirs = collections.getPaths(); + + if (useLooseFiles) + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + // Last data dir has the highest priority + vfs->addArchive(new FileSystemArchive(iter->string())); + } + + for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) + { + if (collections.doesExist(*archive)) + { + // Last BSA has the highest priority + const std::string archivePath = collections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + + vfs->addArchive(new BsaArchive(archivePath)); + } + else + { + std::stringstream message; + message << "Archive '" << *archive << "' not found"; + throw std::runtime_error(message.str()); + } + } + + vfs->buildIndex(); + } + +} diff --git a/components/vfs/registerarchives.hpp b/components/vfs/registerarchives.hpp new file mode 100644 index 0000000000..1ef13f0f9e --- /dev/null +++ b/components/vfs/registerarchives.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_COMPONENTS_VFS_REGISTER_ARCHIVES_H +#define OPENMW_COMPONENTS_VFS_REGISTER_ARCHIVES_H + +#include + +namespace VFS +{ + class Manager; + + /// @brief Register BSA and file system archives based on the given OpenMW configuration. + void registerArchives (VFS::Manager* vfs, const Files::Collections& collections, + const std::vector& archives, bool useLooseFiles); +} + +#endif From 34d503017adda4e9c6366a7262759dc8c198ba83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Mar 2015 23:27:14 +0100 Subject: [PATCH 0034/1812] OpenCS: Set up an osgQt GraphicsWindow in SceneWidget --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 3 +- apps/opencs/main.cpp | 3 + apps/opencs/view/render/mousestate.cpp | 8 +- .../view/render/pagedworldspacewidget.cpp | 38 +- .../view/render/pagedworldspacewidget.hpp | 2 - apps/opencs/view/render/previewwidget.cpp | 13 +- apps/opencs/view/render/previewwidget.hpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 488 ++---------------- apps/opencs/view/render/scenewidget.hpp | 116 +---- .../view/render/unpagedworldspacewidget.cpp | 11 +- apps/opencs/view/render/worldspacewidget.cpp | 12 +- apps/opencs/view/world/previewsubview.cpp | 6 +- apps/opencs/view/world/scenesubview.cpp | 4 +- 14 files changed, 118 insertions(+), 590 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1059b1c3ac..17abedb4c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3548c175a4..6976aec422 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -157,7 +157,7 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) +find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtOpenGL REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) @@ -201,6 +201,7 @@ target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${OPENSCENEGRAPH_LIBRARIES} ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index eb5dcc64e6..e3d5d3cdd2 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -44,6 +44,9 @@ int main(int argc, char *argv[]) { try { + // To allow background thread drawing in OSG + QApplication::setAttribute(Qt::AA_X11InitThreads, true); + Q_INIT_RESOURCE (resources); qRegisterMetaType ("std::string"); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index a94f4f8ab1..8edd9d58fc 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -56,7 +56,7 @@ namespace CSVRender // MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager()) + : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(0/*parent->getSceneManager()*/) , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) @@ -447,17 +447,17 @@ namespace CSVRender std::map::iterator iter = sceneWidgets.begin(); for(; iter != sceneWidgets.end(); ++iter) { - (*iter).second->updateScene(); + //(*iter).second->updateScene(); } } Ogre::Camera *MouseState::getCamera() { - return mParent->getCamera(); + return 0;//mParent->getCamera(); } Ogre::Viewport *MouseState::getViewport() { - return mParent->getCamera()->getViewport(); + return 0;//mParent->getCamera()->getViewport(); } } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 90181a3679..84a5a5665b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -29,7 +29,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; - bool setCamera = false; + //bool setCamera = false; const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -53,7 +53,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } // destroy manual objects - getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); + //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); delete iter->second; mCells.erase (iter++); @@ -98,8 +98,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } } - if (mCells.begin()==mCells.end()) - setCamera = true; + //if (mCells.begin()==mCells.end()) + //setCamera = true; // add for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); @@ -110,6 +110,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { +#if 0 Cell *cell = new Cell (mDocument.getData(), getSceneManager(), iter->getId (mWorldspace), mDocument.getPhysics()); mCells.insert (std::make_pair (*iter, cell)); @@ -167,6 +168,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } */ +#endif + modified = true; } } @@ -242,28 +245,6 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::updateOverlay() -{ - if(getCamera()->getViewport()) - { - if((uint32_t)getCamera()->getViewport()->getVisibilityMask() - & (uint32_t)CSVRender::Element_CellMarker) - mDisplayCellCoord = true; - else - mDisplayCellCoord = false; - } - - if(!mTextOverlays.empty()) - { - std::map::iterator it = mTextOverlays.begin(); - for(; it != mTextOverlays.end(); ++it) - { - it->second->enable(mDisplayCellCoord); - it->second->update(); - } - } -} - void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -329,6 +310,7 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { + /* Ogre::Vector3 position = getCamera()->getPosition(); std::ostringstream stream; @@ -339,6 +321,8 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() << ", 0"; return stream.str(); + */ + return ""; } CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) @@ -363,7 +347,7 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() { delete iter->second; - getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); + //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); } for (std::map::iterator iter (mTextOverlays.begin()); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 22c6ed4786..1bc9c3c5c8 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -86,8 +86,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void updateOverlay(); - virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index da18e7c895..6982cad52d 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -9,10 +9,9 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, boost::shared_ptr(), true) +: SceneWidget (parent), mData (data) { - setNavigation (&mOrbit); + //setNavigation (&mOrbit); QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); @@ -37,6 +36,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { +#if 0 if (mObject.referenceableDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -51,11 +51,13 @@ void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topL if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted) emit closeRequest(); } +#endif } void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { +#if 0 if (mObject.referenceableAboutToBeRemoved (parent, start, end)) flagAsModified(); @@ -75,11 +77,13 @@ void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& emit closeRequest(); } } +#endif } void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { +#if 0 if (mObject.referenceDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -108,11 +112,13 @@ void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) if (index.column()>=topLeft.column() && index.column()<=bottomRight.row()) emit referenceableIdChanged (mObject.getReferenceableId()); +#endif } void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) { +#if 0 if (mObject.getReferenceId().empty()) return; @@ -123,4 +129,5 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); +#endif } diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index dd6a99c0f9..7260ee2428 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -21,7 +21,7 @@ namespace CSVRender CSMWorld::Data& mData; CSVRender::NavigationOrbit mOrbit; - Object mObject; + //Object mObject; public: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3a660b5fd2..82dc4c2115 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -4,13 +4,7 @@ #include #include #include - -#include -#include -#include -#include -#include -#include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -18,445 +12,75 @@ #include "navigation.hpp" #include "lighting.hpp" +#include +#include + +#include + namespace CSVRender { - SceneWidget::SceneWidget(QWidget *parent) - : QWidget(parent) - , mCamera(NULL) - , mSceneMgr(NULL) - , mWindow(NULL) - , mViewport(NULL) - , mNavigation (0), mLighting (0), mUpdate (false), mKeyForward (false) - , mKeyBackward (false), mKeyLeft (false), mKeyRight (false) - , mKeyRollLeft (false), mKeyRollRight (false) - , mFast (false), mDragging (false), mMod1 (false) - , mFastFactor (4) - , mDefaultAmbient (0, 0, 0, 0), mHasDefaultAmbient (false) - { - setAttribute(Qt::WA_PaintOnScreen); - setAttribute(Qt::WA_NoSystemBackground); - setFocusPolicy (Qt::StrongFocus); +SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f) +{ - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - mSceneMgr->setAmbientLight (Ogre::ColourValue (0,0,0,1)); - - mCamera = mSceneMgr->createCamera("foo"); - - mCamera->setPosition (300, 0, 0); - mCamera->lookAt (0, 0, 0); - mCamera->setNearClipDistance (0.1); - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - float farClipDist = userSettings.setting("3d-render/far-clip-distance", QString("300000")).toFloat(); - mCamera->setFarClipDistance (farClipDist); - - mFastFactor = userSettings.setting("scene-input/fast-factor", QString("4")).toInt(); - - mCamera->roll (Ogre::Degree (90)); - - setLighting (&mLightingDay); - - QTimer *timer = new QTimer (this); - - connect (timer, SIGNAL (timeout()), this, SLOT (update())); - - int timerStart = userSettings.setting("scene-input/timer", QString("20")).toInt(); - timer->start (timerStart); - - /// \todo make shortcut configurable - QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); - } - - CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) - { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode"); - - /// \todo replace icons - tool->addButton (":scenetoolbar/day", "day", - "Day" - "
  • Cell specific ambient in interiors
  • " - "
  • Low ambient in exteriors
  • " - "
  • Strong directional light source/lir>" - "
  • This mode closely resembles day time in-game
"); - tool->addButton (":scenetoolbar/night", "night", - "Night" - "
  • Cell specific ambient in interiors
  • " - "
  • Low ambient in exteriors
  • " - "
  • Weak directional light source
  • " - "
  • This mode closely resembles night time in-game
"); - tool->addButton (":scenetoolbar/bright", "bright", - "Bright" - "
  • Maximum ambient
  • " - "
  • Strong directional light source
"); - - connect (tool, SIGNAL (modeChanged (const std::string&)), - this, SLOT (selectLightingMode (const std::string&))); - - return tool; - } - - void SceneWidget::setDefaultAmbient (const Ogre::ColourValue& colour) - { - mDefaultAmbient = colour; - mHasDefaultAmbient = true; - - if (mLighting) - mLighting->setDefaultAmbient (colour); - } - - void SceneWidget::updateOgreWindow() - { - if (mWindow) - { - Ogre::Root::getSingleton().destroyRenderTarget(mWindow); - mWindow = NULL; - } - - std::stringstream windowHandle; -#ifdef WIN32 - windowHandle << Ogre::StringConverter::toString((uintptr_t)(this->winId())); +#if QT_VERSION >= 0x050000 + // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; #else - windowHandle << this->winId(); -#endif - std::stringstream windowTitle; - static int count=0; - windowTitle << ++count; - - Ogre::NameValuePairList params; - - params.insert(std::make_pair("externalWindowHandle", windowHandle.str())); - params.insert(std::make_pair("title", windowTitle.str())); - - std::string antialiasing = - CSMSettings::UserSettings::instance().settingValue("3d-render/antialiasing").toStdString(); - if(antialiasing == "MSAA 16") antialiasing = "16"; - else if(antialiasing == "MSAA 8") antialiasing = "8"; - else if(antialiasing == "MSAA 4") antialiasing = "4"; - else if(antialiasing == "MSAA 2") antialiasing = "2"; - else antialiasing = "0"; - params.insert(std::make_pair("FSAA", antialiasing)); - - params.insert(std::make_pair("vsync", "false")); // TODO setting -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - params.insert(std::make_pair("macAPI", "cocoa")); - params.insert(std::make_pair("macAPICocoaUseNSView", "true")); + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; #endif - mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms); + setThreadingModel(threadingModel); - mViewport = mWindow->addViewport (mCamera); - mViewport->setBackgroundColour (Ogre::ColourValue (0.3,0.3,0.3,1)); + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); - Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height()); - mCamera->setAspectRatio(aspectRatio); - } + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->windowName = ""; + traits->windowDecoration = true; + traits->x = 0; + traits->y = 0; + traits->width = width(); + traits->height = height(); + traits->doubleBuffer = true; + traits->alpha = ds->getMinimumNumAlphaBits(); + traits->stencil = ds->getMinimumNumStencilBits(); + traits->sampleBuffers = ds->getMultiSamples(); + traits->samples = ds->getNumMultiSamples(); - SceneWidget::~SceneWidget() - { - if (mWindow) - Ogre::Root::getSingleton().destroyRenderTarget (mWindow); + osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); + QLayout* layout = new QHBoxLayout(this); + layout->addWidget(window->getGLWidget()); + setLayout(layout); - if (mSceneMgr) - Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); + getCamera()->setGraphicsContext(window); - } + getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); + getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); + //getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); - void SceneWidget::setVisibilityMask (unsigned int mask) - { - mViewport->setVisibilityMask (mask); - } + osg::Node* root = new osg::Node; + setSceneData(root); - void SceneWidget::setNavigation (Navigation *navigation) - { - if ((mNavigation = navigation)) - { - mNavigation->setFastModeFactor (mFast ? mFastFactor : 1); - if (mNavigation->activate (mCamera)) - mUpdate = true; - } - } + setCameraManipulator(new osgGA::TrackballManipulator); - void SceneWidget::addRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->addListener(listener); - } + // Only render when the camera position changed, or content flagged dirty + //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); + + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); + mTimer.start( 10 ); +} + +void SceneWidget::paintEvent(QPaintEvent *event) +{ + frame(); +} + +void SceneWidget::flagAsModified() +{ + _requestRedraw = true; +} - void SceneWidget::removeRenderTargetListener(Ogre::RenderTargetListener *listener) - { - mWindow->removeListener(listener); - } - - Ogre::Viewport *SceneWidget::getViewport() - { - if (!mWindow) - updateOgreWindow(); - - return mViewport; - } - - Ogre::SceneManager *SceneWidget::getSceneManager() - { - return mSceneMgr; - } - - Ogre::Camera *SceneWidget::getCamera() - { - return mCamera; - } - - void SceneWidget::flagAsModified() - { - mUpdate = true; - } - - void SceneWidget::paintEvent(QPaintEvent* e) - { - if (!mWindow) - updateOgreWindow(); - - mWindow->update(); - e->accept(); - } - - QPaintEngine* SceneWidget::paintEngine() const - { - // We don't want another paint engine to get in the way. - // So we return nothing. - return NULL; - } - - void SceneWidget::resizeEvent(QResizeEvent *e) - { - if (!mWindow) - return; - - const QSize &newSize = e->size(); - - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mWindow->resize(newSize.width(), newSize.height()); -#else - mWindow->windowMovedOrResized(); -#endif - - Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height()); - mCamera->setAspectRatio(aspectRatio); - } - - bool SceneWidget::event(QEvent *e) - { - if (e->type() == QEvent::WinIdChange) - { - // I haven't actually seen this happen yet. - if (mWindow) - updateOgreWindow(); - } - return QWidget::event(e); - } - - void SceneWidget::keyPressEvent (QKeyEvent *event) - { - switch (event->key()) - { - case Qt::Key_W: mKeyForward = true; break; - case Qt::Key_S: mKeyBackward = true; break; - case Qt::Key_A: mKeyLeft = true; break; - case Qt::Key_D: mKeyRight = true; break; - case Qt::Key_Q: mKeyRollLeft = true; break; - case Qt::Key_E: mKeyRollRight = true; break; - case Qt::Key_Control: mMod1 = true; break; - - case Qt::Key_Shift: - - mFast = true; - - if (mNavigation) - mNavigation->setFastModeFactor (mFastFactor); - - break; - - default: QWidget::keyPressEvent (event); - } - } - - void SceneWidget::keyReleaseEvent (QKeyEvent *event) - { - switch (event->key()) - { - case Qt::Key_W: mKeyForward = false; break; - case Qt::Key_S: mKeyBackward = false; break; - case Qt::Key_A: mKeyLeft = false; break; - case Qt::Key_D: mKeyRight = false; break; - case Qt::Key_Q: mKeyRollLeft = false; break; - case Qt::Key_E: mKeyRollRight = false; break; - case Qt::Key_Control: mMod1 = false; break; - - case Qt::Key_Shift: - - mFast = false; - - if (mNavigation) - mNavigation->setFastModeFactor (1); - - break; - - default: QWidget::keyReleaseEvent (event); - } - } - - void SceneWidget::wheelEvent (QWheelEvent *event) - { - if (mNavigation) - if (event->delta()) - if (mNavigation->wheelMoved (event->delta())) - mUpdate = true; - } - - void SceneWidget::leaveEvent (QEvent *event) - { - mDragging = false; - } - - void SceneWidget::mouseMoveEvent (QMouseEvent *event) - { - if (event->buttons() & Qt::LeftButton) - { - if (mDragging) - { - QPoint diff = mOldPos-event->pos(); - mOldPos = event->pos(); - - if (mNavigation) - if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0)) - mUpdate = true; - } - else - { - mDragging = true; - mOldPos = event->pos(); - } - } - } - - void SceneWidget::mouseReleaseEvent (QMouseEvent *event) - { - if (!(event->buttons() & Qt::LeftButton)) - mDragging = false; - } - - void SceneWidget::focusOutEvent (QFocusEvent *event) - { - mKeyForward = false; - mKeyBackward = false; - mKeyLeft = false; - mKeyRight = false; - mFast = false; - mMod1 = false; - - QWidget::focusOutEvent (event); - } - - void SceneWidget::update() - { - if (mNavigation) - { - int horizontal = 0; - int vertical = 0; - - if (mKeyForward && !mKeyBackward) - vertical = 1; - else if (!mKeyForward && mKeyBackward) - vertical = -1; - - if (mKeyLeft && !mKeyRight) - horizontal = -1; - else if (!mKeyLeft && mKeyRight) - horizontal = 1; - - if (horizontal || vertical) - if (mNavigation->handleMovementKeys (vertical, horizontal)) - mUpdate = true; - - int roll = 0; - - if (mKeyRollLeft && !mKeyRollRight) - roll = 1; - else if (!mKeyRollLeft && mKeyRollRight) - roll = -1; - - if (roll) - if (mNavigation->handleRollKeys (roll)) - mUpdate = true; - - } - - if (mUpdate && mWindow) - { - mUpdate = false; - mWindow->update(); - updateOverlay(); - } - } - - void SceneWidget::updateScene() - { - flagAsModified(); - } - - void SceneWidget::updateOverlay() - { } - - void SceneWidget::setLighting (Lighting *lighting) - { - if (mLighting) - mLighting->deactivate(); - - mLighting = lighting; - mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0); - - if (mWindow) - mWindow->update(); - } - - void SceneWidget::selectLightingMode (const std::string& mode) - { - if (mode=="day") - setLighting (&mLightingDay); - else if (mode=="night") - setLighting (&mLightingNight); - else if (mode=="bright") - setLighting (&mLightingBright); - } - - void SceneWidget::updateUserSetting (const QString &key, const QStringList &list) - { - if(key.contains(QRegExp("^\\b(Objects|Shader|Scene)", Qt::CaseInsensitive))) - flagAsModified(); - - if(key == "3d-render/far-clip-distance" && !list.empty()) - { - if(mCamera->getFarClipDistance() != list.at(0).toFloat()) - mCamera->setFarClipDistance(list.at(0).toFloat()); - } - - // minimise unnecessary ogre window creation by updating only when there is a change - if(key == "3d-render/antialiasing") - { - unsigned int aa = mWindow->getFSAA(); - unsigned int antialiasing = 0; - if(!list.empty()) - { - if(list.at(0) == "MSAA 16") antialiasing = 16; - else if(list.at(0) == "MSAA 8") antialiasing = 8; - else if(list.at(0) == "MSAA 4") antialiasing = 4; - else if(list.at(0) == "MSAA 2") antialiasing = 2; - } - if(aa != antialiasing) - updateOgreWindow(); - } - } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c570388696..0cdf1ef997 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -2,21 +2,13 @@ #define OPENCS_VIEW_SCENEWIDGET_H #include - -#include +#include #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" -namespace Ogre -{ - class Camera; - class SceneManager; - class RenderWindow; - class Viewport; - class RenderTargetListener; -} +#include namespace CSVWidget { @@ -29,110 +21,22 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget + class SceneWidget : public QWidget, public osgViewer::Viewer { Q_OBJECT - public: + public: + SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - SceneWidget(QWidget *parent); - virtual ~SceneWidget(); + virtual void paintEvent( QPaintEvent* event ); - QPaintEngine* paintEngine() const; + void flagAsModified(); - CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); - ///< \attention The created tool is not added to the toolbar (via addTool). Doing that - /// is the responsibility of the calling function. + protected: - virtual void setVisibilityMask (unsigned int mask); - - virtual void updateScene(); - - protected: - - void setNavigation (Navigation *navigation); - ///< \attention The ownership of \a navigation is not transferred to *this. - - void addRenderTargetListener(Ogre::RenderTargetListener *listener); - - void removeRenderTargetListener(Ogre::RenderTargetListener *listener); - - Ogre::Viewport *getViewport(); - - Ogre::SceneManager *getSceneManager(); - - Ogre::Camera *getCamera(); - - void flagAsModified(); - - void setDefaultAmbient (const Ogre::ColourValue& colour); - ///< \note The actual ambient colour may differ based on lighting settings. - - virtual void updateOverlay(); - - virtual void mouseReleaseEvent (QMouseEvent *event); - - virtual void mouseMoveEvent (QMouseEvent *event); - - void wheelEvent (QWheelEvent *event); - - void keyPressEvent (QKeyEvent *event); - - private: - void paintEvent(QPaintEvent* e); - void resizeEvent(QResizeEvent* e); - bool event(QEvent* e); - - void keyReleaseEvent (QKeyEvent *event); - - void focusOutEvent (QFocusEvent *event); - - void leaveEvent (QEvent *event); - - void updateOgreWindow(); - - void setLighting (Lighting *lighting); - ///< \attention The ownership of \a lighting is not transferred to *this. - - Ogre::Camera* mCamera; - Ogre::SceneManager* mSceneMgr; - Ogre::RenderWindow* mWindow; - Ogre::Viewport *mViewport; - - Navigation *mNavigation; - Lighting *mLighting; - bool mUpdate; - bool mKeyForward; - bool mKeyBackward; - bool mKeyLeft; - bool mKeyRight; - bool mKeyRollLeft; - bool mKeyRollRight; - bool mFast; - bool mDragging; - bool mMod1; - QPoint mOldPos; - int mFastFactor; - Ogre::ColourValue mDefaultAmbient; - bool mHasDefaultAmbient; - LightingDay mLightingDay; - LightingNight mLightingNight; - LightingBright mLightingBright; - - public slots: - - void updateUserSetting (const QString &key, const QStringList &list); - - private slots: - - void update(); - - void selectLightingMode (const std::string& mode); - - signals: - - void focusToolbarRequest(); + QTimer mTimer; }; + } #endif diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 462b62b7a8..a269fab45b 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -26,11 +26,11 @@ void CSVRender::UnpagedWorldspaceWidget::update() Ogre::ColourValue colour; colour.setAsABGR (record.get().mAmbi.mAmbient); - setDefaultAmbient (colour); + //setDefaultAmbient (colour); /// \todo deal with mSunlight and mFog/mForDensity - flagAsModified(); + //flagAsModified(); } CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); + //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); + //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); update(); emit cellChanged(*data.begin()); @@ -163,6 +163,7 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { + /* Ogre::Vector3 position = getCamera()->getPosition(); std::ostringstream stream; @@ -173,6 +174,8 @@ std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() << ", 0, \"" << mCellId << "\""; return stream.str(); + */ + return ""; } CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 582ccea643..5ae5c8177f 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -56,31 +56,33 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); mPhysics = document.getPhysics(); // create physics if one doesn't exist - mPhysics->addSceneManager(getSceneManager(), this); + //mPhysics->addSceneManager(getSceneManager(), this); mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { delete mMouse; - mPhysics->removeSceneManager(getSceneManager()); + //mPhysics->removeSceneManager(getSceneManager()); } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { + /* if (mode=="1st") setNavigation (&m1st); else if (mode=="free") setNavigation (&mFree); else if (mode=="orbit") setNavigation (&mOrbit); + */ } void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {} void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() { - setNavigation (&m1st); + //setNavigation (&m1st); } CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( @@ -355,7 +357,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::elementSelectionChanged() { - setVisibilityMask (getVisibilityMask()); + //setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); } @@ -386,11 +388,13 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { + /* if(!getViewport()) { SceneWidget::mouseReleaseEvent(event); return; } + */ mMouse->mouseReleaseEvent(event); } SceneWidget::mouseReleaseEvent(event); diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1ae466f42b..0c9823c444 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -30,8 +30,8 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); - CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); - toolbar->addTool (lightingTool); + //CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); + //toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); @@ -67,4 +67,4 @@ void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) setWindowTitle (QString::fromUtf8 (mTitle.c_str())); emit updateTitle(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 3fdf2f6e5c..c59236ee5d 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -107,8 +107,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); - CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); - toolbar->addTool (lightingTool); + //CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); + //toolbar->addTool (lightingTool); CSVWidget::SceneToolToggle2 *sceneVisibilityTool = widget->makeSceneVisibilitySelector (toolbar); From af27a10b0cc541cfc16d465ff12d0f164edfa04b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 00:39:24 +0100 Subject: [PATCH 0035/1812] OpenCS: preliminary port of PreviewWidget to OSG --- apps/opencs/model/doc/document.cpp | 9 +++- apps/opencs/model/doc/document.hpp | 11 +++- apps/opencs/model/doc/documentmanager.cpp | 5 +- apps/opencs/model/doc/documentmanager.hpp | 2 +- apps/opencs/view/render/cell.cpp | 6 +-- apps/opencs/view/render/object.cpp | 65 +++++++++-------------- apps/opencs/view/render/object.hpp | 24 +++++---- apps/opencs/view/render/previewwidget.cpp | 12 +---- apps/opencs/view/render/previewwidget.hpp | 9 +++- apps/opencs/view/render/scenewidget.cpp | 15 ++++-- apps/opencs/view/render/scenewidget.hpp | 7 +++ apps/opencs/view/world/previewsubview.cpp | 4 +- components/nifosg/nifloader.hpp | 2 +- 13 files changed, 92 insertions(+), 79 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e688a9474a..2a5fa77465 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2245,12 +2245,12 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, +CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) -: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), +: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), @@ -2311,6 +2311,11 @@ CSMDoc::Document::~Document() { } +const VFS::Manager *CSMDoc::Document::getVFS() const +{ + return mVFS; +} + QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db63..2d42e99034 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -23,6 +23,12 @@ class QAbstractItemModel; +namespace VFS +{ + + class Manager; +} + namespace ESM { struct GameSetting; @@ -53,6 +59,7 @@ namespace CSMDoc private: + const VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -91,7 +98,7 @@ namespace CSMDoc public: - Document (const Files::ConfigurationManager& configuration, + Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, @@ -99,6 +106,8 @@ namespace CSMDoc ~Document(); + const VFS::Manager* getVFS() const; + QUndoStack& getUndoStack(); int getState() const; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index ecff4bbed6..edce6e6130 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -13,7 +13,7 @@ #include "document.hpp" CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) -: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) +: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL) { boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; @@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); mDocuments.push_back (document); @@ -107,4 +107,5 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs) { mResourcesManager.setVFS(vfs); + mVFS = vfs; } diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index a12d22c4ed..8dc4f338aa 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -40,7 +40,7 @@ namespace CSMDoc ToUTF8::FromType mEncoding; CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - VFS::Manager* mVFS; + const VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a0d0f6e71b..72ceb654a1 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,7 +51,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + //mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; } } @@ -191,8 +191,8 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, // add new objects for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { - mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + //mObjects.insert (std::make_pair ( + // iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); modified = true; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index b54551c96d..2434343c9f 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,9 +1,6 @@ - #include "object.hpp" -#include -#include -#include +#include #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" @@ -11,43 +8,20 @@ #include "../world/physicssystem.hpp" +#include + #include "elements.hpp" -void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) -{ - for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator(); - iter.hasMoreElements(); ) - { - Ogre::MovableObject* object = dynamic_cast (iter.getNext()); - node->getCreator()->destroyMovableObject (object); - } - - for (Ogre::SceneNode::ChildNodeIterator iter = node->getChildIterator(); - iter.hasMoreElements(); ) - { - Ogre::SceneNode* childNode = dynamic_cast (iter.getNext()); - clearSceneNode (childNode); - node->getCreator()->destroySceneNode (childNode); - } -} - void CSVRender::Object::clear() { - mObject.setNull(); - - if (mBase) - clearSceneNode (mBase); } void CSVRender::Object::update() { - if(!mObject.isNull()) - mPhysics->removePhysicsObject(mBase->getName()); - clear(); std::string model; - int error = 0; // 1 referemceanöe does not exist, 2 referenceable does not specify a mesh + int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); @@ -69,17 +43,28 @@ void CSVRender::Object::update() if (error) { + /* Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE); entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error entity->setVisibilityFlags (Element_Reference); mBase->attachObject (entity); + */ } else { - //mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); + NifOsg::Loader loader; + loader.resourceManager = mVFS; + + std::string path = "meshes\\" + model; + + Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + + loader.load(file, mBaseNode); + //mObject->setVisibilityFlags (Element_Reference); + /* if (mPhysics && !mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); @@ -96,11 +81,13 @@ void CSVRender::Object::update() mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); } + */ } } void CSVRender::Object::adjust() { + /* if (mReferenceId.empty()) return; @@ -122,6 +109,7 @@ void CSVRender::Object::adjust() // scale mBase->setScale (reference.mScale, reference.mScale, reference.mScale); + */ } const CSMWorld::CellRef& CSVRender::Object::getReference() const @@ -132,12 +120,13 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, +CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, boost::shared_ptr physics, bool forceBaseToZero) -: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) +: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero), mPhysics(physics) { - mBase = cellNode->createChildSceneNode(); + mBaseNode = new osg::Group; + parentNode->addChild(mBaseNode); if (referenceable) { @@ -157,13 +146,7 @@ CSVRender::Object::~Object() { clear(); - if (mBase) - { - if(mPhysics) // preview may not have physics enabled - mPhysics->removeObject(mBase->getName()); - - mBase->getCreator()->destroySceneNode (mBase); - } + mParentNode->removeChild(mBaseNode); } bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 3ed4fa793f..8e9598bbf2 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -3,15 +3,19 @@ #include -#ifndef Q_MOC_RUN -#include -#endif +#include class QModelIndex; -namespace Ogre + +namespace osg { - class SceneNode; + class Group; +} + +namespace VFS +{ + class Manager; } namespace CSMWorld @@ -32,8 +36,9 @@ namespace CSVRender const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; - Ogre::SceneNode *mBase; - NifOgre::ObjectScenePtr mObject; + osg::ref_ptr mBaseNode; + osg::Group* mParentNode; + const VFS::Manager* mVFS; bool mForceBaseToZero; boost::shared_ptr mPhysics; @@ -43,9 +48,6 @@ namespace CSVRender /// Not implemented Object& operator= (const Object&); - /// Destroy all scene nodes and movable objects attached to node. - static void clearSceneNode (Ogre::SceneNode *node); - /// Remove object from node (includes deleting) void clear(); @@ -60,7 +62,7 @@ namespace CSVRender public: - Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, + Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, boost::shared_ptr physics = boost::shared_ptr (), bool forceBaseToZero = false); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 6982cad52d..ee43ac13c6 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -7,9 +7,9 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" -CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, +CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data) +: SceneWidget (parent), mData (data), mObject(vfs, data, mRootNode, id, referenceable) { //setNavigation (&mOrbit); @@ -36,7 +36,6 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { -#if 0 if (mObject.referenceableDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -51,13 +50,11 @@ void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topL if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted) emit closeRequest(); } -#endif } void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { -#if 0 if (mObject.referenceableAboutToBeRemoved (parent, start, end)) flagAsModified(); @@ -77,13 +74,11 @@ void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& emit closeRequest(); } } -#endif } void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { -#if 0 if (mObject.referenceDataChanged (topLeft, bottomRight)) flagAsModified(); @@ -112,13 +107,11 @@ void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft, if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) if (index.column()>=topLeft.column() && index.column()<=bottomRight.row()) emit referenceableIdChanged (mObject.getReferenceableId()); -#endif } void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) { -#if 0 if (mObject.getReferenceId().empty()) return; @@ -129,5 +122,4 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); -#endif } diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 7260ee2428..dfe05b4843 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -8,6 +8,11 @@ class QModelIndex; +namespace VFS +{ + class Manager; +} + namespace CSMWorld { class Data; @@ -21,11 +26,11 @@ namespace CSVRender CSMWorld::Data& mData; CSVRender::NavigationOrbit mOrbit; - //Object mObject; + CSVRender::Object mObject; public: - PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, + PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 82dc4c2115..2f28c06df2 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -16,12 +16,14 @@ #include #include +#include namespace CSVRender { SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) + , mRootNode(0) { #if QT_VERSION >= 0x050000 @@ -37,6 +39,7 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) setKeyEventSetsDone(0); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + //ds->setNumMultiSamples(8); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->windowName = ""; traits->windowDecoration = true; @@ -49,6 +52,8 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) traits->stencil = ds->getMinimumNumStencilBits(); traits->sampleBuffers = ds->getMultiSamples(); traits->samples = ds->getNumMultiSamples(); + // Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate when running multiple QGLWidgets + traits->vsync = false; osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); @@ -59,15 +64,19 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - //getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); + getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); - osg::Node* root = new osg::Node; - setSceneData(root); + mRootNode = new osg::Group; + setSceneData(mRootNode); + + // Press S to reveal profiling stats + addEventHandler(new osgViewer::StatsHandler); setCameraManipulator(new osgGA::TrackballManipulator); // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); + setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 0cdf1ef997..3784a5c597 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -10,6 +10,11 @@ #include +namespace osg +{ + class Group; +} + namespace CSVWidget { class SceneToolMode; @@ -34,6 +39,8 @@ namespace CSVRender protected: + osg::Group* mRootNode; + QTimer mTimer; }; diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 0c9823c444..c82d1b82e4 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo referenceableIdChanged (referenceableId); mScene = - new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this); + new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), false, this); } else - mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this); + mScene = new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), true, this); CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 5a0c901c1a..7b38ce5607 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -39,7 +39,7 @@ namespace NifOsg void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); - VFS::Manager* resourceManager; + const VFS::Manager* resourceManager; // FIXME move std::vector mControllers; From 4957ceeb1d25bf359c341bcd551a2f536a8d7418 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 19:51:54 +0100 Subject: [PATCH 0036/1812] Refactor controllers, now part of the scene graph as UpdateCallbacks Practical benefits: - The controller update is now run automatically - Creating an instance of a scene graph should now work properly using the defined copy constructors --- apps/nifosgtest/test.cpp | 9 +- .../view/render/unpagedworldspacewidget.cpp | 2 +- components/nifosg/controller.cpp | 445 ++++++++++++------ components/nifosg/controller.hpp | 146 +++--- components/nifosg/nifloader.cpp | 103 ++-- components/nifosg/nifloader.hpp | 18 +- components/nifosg/particle.cpp | 1 + 7 files changed, 443 insertions(+), 281 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9a7ce3f4..fee9197871 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -112,15 +112,11 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; loader.loadAsSkeleton(nif, newNode); - for (unsigned int i=0; iaddChild(trans); @@ -137,6 +133,8 @@ int main(int argc, char** argv) viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); + //viewer.getCamera()->setCullMask() + // We're going to change this from the event callback, set the variance to DYNAMIC so that // we don't interfere with the draw thread. root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); @@ -148,9 +146,6 @@ int main(int argc, char** argv) //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); viewer.frame(); - - for (unsigned int i=0; igetFrameStamp()->getReferenceTime(); + float dt = static_cast(time - mLastTime); + mLastTime = time; + return dt; +} + +KeyframeController::KeyframeController() +{ +} + +KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mRotations(copy.mRotations) + , mXRotations(copy.mXRotations) + , mYRotations(copy.mYRotations) + , mZRotations(copy.mZRotations) + , mTranslations(copy.mTranslations) + , mScales(copy.mScales) + , mNif(copy.mNif) + , mInitialQuat(copy.mInitialQuat) + , mInitialScale(copy.mInitialScale) +{ +} + +KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale) + : mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) + , mTranslations(&data->mTranslations) + , mScales(&data->mScales) + , mNif(nif) + , mInitialQuat(initialQuat) + , mInitialScale(initialScale) +{ } + +osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { if(time <= keys.begin()->first) return keys.begin()->second.mValue; @@ -81,7 +127,7 @@ osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapTyp return keys.rbegin()->second.mValue; } -osg::Quat KeyframeControllerValue::getXYZRotation(float time) const +osg::Quat KeyframeController::getXYZRotation(float time) const { float xrot = interpKey(mXRotations->mKeys, time); float yrot = interpKey(mYRotations->mKeys, time); @@ -92,96 +138,108 @@ osg::Quat KeyframeControllerValue::getXYZRotation(float time) const return (zr*yr*xr); } -KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale) - : NodeTargetValue(target) - , mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) - , mInitialQuat(initialQuat) - , mInitialScale(initialScale) -{ } - -osg::Vec3f KeyframeControllerValue::getTranslation(float time) const +osg::Vec3f KeyframeController::getTranslation(float time) const { if(mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); - osg::MatrixTransform* trans = static_cast(mNode); - return trans->getMatrix().getTrans(); + return osg::Vec3f(); } -void KeyframeControllerValue::setValue(float time) +void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) { - osg::MatrixTransform* trans = static_cast(mNode); - osg::Matrix mat = trans->getMatrix(); - - if(mRotations->mKeys.size() > 0) - mat.setRotate(interpKey(mRotations->mKeys, time)); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - mat.setRotate(getXYZRotation(time)); - else - mat.setRotate(mInitialQuat); - - // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) - float scale = mInitialScale; - if(mScales->mKeys.size() > 0) - scale = interpKey(mScales->mKeys, time); - - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(i,j) *= scale; - - if(mTranslations->mKeys.size() > 0) - mat.setTrans(interpKey(mTranslations->mKeys, time)); - trans->setMatrix(mat); -} - -Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) - : mSource(src) - , mDestValue(dest) - , mFunction(function) -{ - -} - -void Controller::update() -{ - if (mSource.get()) + if (hasInput()) { - mDestValue->setValue(mFunction->calculate(mSource->getValue())); + osg::MatrixTransform* trans = static_cast(node); + osg::Matrix mat = trans->getMatrix(); + + float time = getInputValue(nv); + + if(mRotations->mKeys.size() > 0) + mat.setRotate(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mat.setRotate(getXYZRotation(time)); + else + mat.setRotate(mInitialQuat); + + // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) + float scale = mInitialScale; + if(mScales->mKeys.size() > 0) + scale = interpKey(mScales->mKeys, time); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(i,j) *= scale; + + if(mTranslations->mKeys.size() > 0) + mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); + } + + traverse(node, nv); +} + +Controller::Controller() +{ +} + +bool Controller::hasInput() const +{ + return mSource.get() != NULL; +} + +float Controller::getInputValue(osg::NodeVisitor* nv) +{ + return mFunction->calculate(mSource->getValue(nv)); +} + +GeomMorpherController::GeomMorpherController() +{ +} + +GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, const osg::CopyOp ©op) + : osg::Drawable::UpdateCallback(copy, copyop) + , Controller(copy) + , mMorphs(copy.mMorphs) +{ +} + +GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) + : mMorphs(data->mMorphs) +{ +} + +void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) +{ + osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); + if (morphGeom) + { + if (hasInput()) + { + if (mMorphs.size() <= 1) + return; + float input = getInputValue(nv); + int i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, input); + val = std::max(0.f, std::min(1.f, val)); + + morphGeom->setWeight(i, val); + } + } + + morphGeom->transformSoftwareMethod(); } } -GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) - : mGeom(geom) - , mMorphs(morphData->mMorphs) +UVController::UVController() { - } -void GeomMorpherControllerValue::setValue(float time) -{ - if (mMorphs.size() <= 1) - return; - int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) - { - float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, time); - val = std::max(0.f, std::min(1.f, val)); - - mGeom->setWeight(i, val); - } -} - -UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) - : mStateSet(target) - , mUTrans(data->mKeyList[0]) +UVController::UVController(const Nif::NiUVData *data, std::set textureUnits) + : mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) , mUScale(data->mKeyList[2]) , mVScale(data->mKeyList[3]) @@ -189,26 +247,58 @@ UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData { } -void UVControllerValue::setValue(float value) +UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy) + , mUTrans(copy.mUTrans) + , mVTrans(copy.mVTrans) + , mUScale(copy.mUScale) + , mVScale(copy.mVScale) + , mTextureUnits(copy.mTextureUnits) { - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); - - osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); - mat.setTrans(uTrans, vTrans, 0); - - osg::TexMat* texMat = new osg::TexMat; - texMat->setMatrix(mat); - - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) - { - mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); - } } -bool VisControllerValue::calculate(float time) const +void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + float value = getInputValue(nv); + float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); + float uScale = interpKey(mUScale.mKeys, value, 1.0f); + float vScale = interpKey(mVScale.mKeys, value, 1.0f); + + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); + mat.setTrans(uTrans, vTrans, 0); + + osg::TexMat* texMat = new osg::TexMat; + texMat->setMatrix(mat); + + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + { + stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + } + } + traverse(node, nv); +} + +VisController::VisController(const Nif::NiVisData *data) + : mData(data->mVis) +{ +} + +VisController::VisController() +{ +} + +VisController::VisController(const VisController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) +{ +} + +bool VisController::calculate(float time) const { if(mData.size() == 0) return true; @@ -221,77 +311,140 @@ bool VisControllerValue::calculate(float time) const return mData.back().isSet; } -void VisControllerValue::setValue(float time) +void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) { - bool vis = calculate(time); - mNode->setNodeMask(vis ? ~0 : 0); + if (hasInput()) + { + bool vis = calculate(getInputValue(nv)); + node->setNodeMask(vis ? ~0 : 0); + } + traverse(node, nv); } -AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) - : mTarget(target) - , mData(data->mKeyList) -{ -} - -void AlphaControllerValue::setValue(float time) -{ - float value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; - - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.a() = value; - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); -} - -MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) - : mTarget(target), mData(data->mKeyList) +AlphaController::AlphaController(const Nif::NiFloatData *data) + : mData(data->mKeyList) { } -void MaterialColorControllerValue::setValue(float time) +AlphaController::AlphaController() { - osg::Vec3f value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; - - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } -FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, - std::vector > textures) +AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) +{ +} + +void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + float value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); +} + +MaterialColorController::MaterialColorController(const Nif::NiPosData *data) + : mData(data->mKeyList) +{ +} + +MaterialColorController::MaterialColorController() +{ +} + +MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), Controller(copy) + , mData(copy.mData) +{ +} + +void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); +} + +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) - , mTarget(target) { } -void FlipControllerValue::setValue(float time) -{ - if (mDelta == 0) - return; - int curTexture = int(time / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); - if (!tex) - return; - tex->setImage(mTextures[curTexture].get()); -} - -ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl) - : mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +FlipController::FlipController() { } -void ParticleSystemControllerValue::setValue(float time) +FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mTexSlot(copy.mTexSlot) + , mDelta(copy.mDelta) + , mTextures(copy.mTextures) { - mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop); } +void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput() && mDelta != 0) + { + osg::StateSet* stateset = node->getStateSet(); + int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(stateset->getAttribute(osg::StateAttribute::TEXTURE)); + if (tex) + tex->setImage(mTextures[curTexture].get()); + } + traverse(node, nv); +} + +ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl) + : mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +{ +} + +ParticleSystemController::ParticleSystemController() +{ +} + +ParticleSystemController::ParticleSystemController(const ParticleSystemController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mEmitStart(copy.mEmitStart) + , mEmitStop(copy.mEmitStop) +{ +} + +void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osgParticle::ParticleProcessor* emitter = dynamic_cast(node); + float time = getInputValue(nv); + if (emitter) + emitter->setEnabled(time >= mEmitStart && time < mEmitStop); + } + traverse(node, nv); +} } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c92a778165..5a9af6324d 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -17,6 +17,9 @@ #include #include +#include +#include +#include namespace osg @@ -93,76 +96,49 @@ namespace NifOsg class ControllerSource { public: - virtual float getValue() const = 0; + virtual float getValue(osg::NodeVisitor* nv) = 0; }; - // FIXME: Should return a dt instead of time class FrameTimeSource : public ControllerSource { public: - - virtual float getValue() const - { - return mTimer.time_s(); - } - + FrameTimeSource(); + virtual float getValue(osg::NodeVisitor* nv); private: - osg::Timer mTimer; - }; - - class ControllerValue - { - public: - virtual void setValue(float value) = 0; + double mLastTime; }; class Controller { public: - Controller (boost::shared_ptr src, boost::shared_ptr dest, - boost::shared_ptr function); + Controller(); - virtual void update(); + bool hasInput() const; + + float getInputValue(osg::NodeVisitor* nv); boost::shared_ptr mSource; - boost::shared_ptr mDestValue; // The source value gets passed through this function before it's passed on to the DestValue. boost::shared_ptr mFunction; }; - // FIXME: Should be with other general extensions. - class NodeTargetValue : public ControllerValue - { - protected: - // TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later - // instead, controllers can be a Node added as child of their target - osg::Node *mNode; - - public: - NodeTargetValue(osg::Node *target) : mNode(target) - { } - - virtual osg::Vec3f getTranslation(float value) const = 0; - - osg::Node *getNode() const - { return mNode; } - }; - - class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator + class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator { public: - // FIXME: don't copy the morph data? - GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + GeomMorpherController(const Nif::NiMorphData* data); + GeomMorpherController(); + GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, GeomMorpherController) + + virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - osgAnimation::MorphGeometry* mGeom; std::vector mMorphs; }; - class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: const Nif::QuaternionKeyMap* mRotations; @@ -185,31 +161,39 @@ namespace NifOsg public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, osg::Quat initialQuat, float initialScale); + KeyframeController(); + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, KeyframeController) virtual osg::Vec3f getTranslation(float time) const; - virtual void setValue(float time); + virtual void operator() (osg::Node*, osg::NodeVisitor*); }; - class UVControllerValue : public ControllerValue, ValueInterpolator + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting + struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator { + public: + UVController(); + UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const Nif::NiUVData *data, std::set textureUnits); + + META_Object(NifOsg,UVController) + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + private: - osg::StateSet* mStateSet; Nif::FloatKeyMap mUTrans; Nif::FloatKeyMap mVTrans; Nif::FloatKeyMap mUScale; Nif::FloatKeyMap mVScale; std::set mTextureUnits; - - public: - UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); }; - class VisControllerValue : public NodeTargetValue + class VisController : public osg::NodeCallback, public Controller { private: std::vector mData; @@ -217,65 +201,75 @@ namespace NifOsg bool calculate(float time) const; public: - VisControllerValue(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } + VisController(const Nif::NiVisData *data); + VisController(); + VisController(const VisController& copy, const osg::CopyOp& copyop); - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } + META_Object(NifOsg, VisController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaControllerValue : public ControllerValue, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::FloatKeyMap mData; public: - AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + AlphaController(const Nif::NiFloatData *data); + AlphaController(); + AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + META_Object(NifOsg, AlphaController) }; - class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::Vector3KeyMap mData; public: - MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + MaterialColorController(const Nif::NiPosData *data); + MaterialColorController(); + MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, MaterialColorController) + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; // untested - class FlipControllerValue : public ControllerValue + class FlipController : public osg::NodeCallback, public Controller { private: - osg::StateSet* mTarget; int mTexSlot; float mDelta; std::vector > mTextures; public: - FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(); + FlipController(const FlipController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, FlipController) + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class ParticleSystemControllerValue : public ControllerValue + class ParticleSystemController : public osg::NodeCallback, public Controller { public: - ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(); + ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, ParticleSystemController) + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); private: - osgParticle::Emitter* mEmitter; float mEmitStart; float mEmitStop; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a92baee790..26f0927b55 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -285,17 +285,13 @@ namespace NifOsg } } - void Loader::createController(const Nif::Controller *ctrl, boost::shared_ptr value, int animflags) + void Loader::setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags) { - // FIXME animflags currently not passed to this function //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; - boost::shared_ptr src(new FrameTimeSource); // if autoPlay + //if (autoPlay) + toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - boost::shared_ptr function (new ControllerFunction(ctrl - , 0/*autoPlay*/)); - //scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - - mControllers.push_back(Controller(src, value, function)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, @@ -308,7 +304,6 @@ namespace NifOsg transformNode = bone; bone->setMatrix(toMatrix(nifNode->trafo)); bone->setName(nifNode->name); - bone->setUpdateCallback(new UpdateBone); bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } else @@ -332,6 +327,7 @@ namespace NifOsg // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later + // FIXME: this disables update callbacks, so VisController no longer works if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0); @@ -358,6 +354,10 @@ namespace NifOsg if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Added last so the changes from KeyframeControllers are taken into account + if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) + bone->addUpdateCallback(new UpdateBone); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -382,9 +382,12 @@ namespace NifOsg std::set texUnits; for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) texUnits.insert(it->first); - boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() - , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, animflags); + + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); + + transformNode->addUpdateCallback(ctrl); } } } @@ -406,23 +409,27 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), - transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), + transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); - createController(key, dest, animflags); seenKeyframeCtrl = true; } } else if (ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, animflags); + + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + transformNode->addUpdateCallback(callback); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -431,21 +438,25 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, animflags); + osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); + setupController(alphactrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, animflags); + osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); + setupController(matctrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -470,8 +481,10 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); textures.push_back(osg::ref_ptr(result.getImage())); } - boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); - createController(flipctrl, dest, animflags); + osg::ref_ptr callback(new FlipController(flipctrl, textures)); + setupController(ctrl.getPtr(), callback, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(callback); } else std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; @@ -577,7 +590,9 @@ namespace NifOsg // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. parentNode->addChild(emitter); - createController(partctrl, boost::shared_ptr(new ParticleSystemControllerValue(emitter, partctrl)), animflags); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); // ----------- affector (must be after emitters in the scene graph) osgParticle::ModularProgram* program = new osgParticle::ModularProgram; @@ -615,14 +630,16 @@ namespace NifOsg // ----------- + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + std::vector materialProps; collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags); + applyMaterialProperties(geode, materialProps, true, animflags); partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -640,7 +657,7 @@ namespace NifOsg parentNode->addChild(updater); } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -720,7 +737,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); + applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) @@ -733,10 +750,11 @@ namespace NifOsg if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) { geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - boost::shared_ptr value( - new GeomMorpherControllerValue(static_cast(geometry.get()), - static_cast(ctrl.getPtr())->data.getPtr())); - createController(ctrl.getPtr(), value, 0); + + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); break; } } while(!(ctrl=ctrl->next).empty()); @@ -744,9 +762,10 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + geode->addDrawable(geometry); parentNode->addChild(geode); @@ -754,8 +773,9 @@ namespace NifOsg void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { + osg::ref_ptr geode (new osg::Geode); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -795,7 +815,6 @@ namespace NifOsg osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix()); - osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); trans->addChild(geode); @@ -987,7 +1006,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, stateset, animflags); + handleTextureControllers(texprop, node, stateset, animflags); } break; } @@ -1003,9 +1022,11 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void Loader::applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { + osg::StateSet* stateset = node->getOrCreateStateSet(); + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); @@ -1032,7 +1053,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset, animflags); + handleMaterialControllers(matprop, node, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7b38ce5607..5bd25f6ca7 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -9,8 +9,6 @@ #include -#include "controller.hpp" - namespace osg { class Geometry; @@ -25,10 +23,12 @@ namespace Nif class Node; class NiTriShape; class Property; + class Controller; } namespace NifOsg { + class Controller; /// The main class responsible for loading NIF files into an OSG-Scenegraph. class Loader @@ -41,9 +41,6 @@ namespace NifOsg const VFS::Manager* resourceManager; - // FIXME move - std::vector mControllers; - private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. @@ -54,9 +51,9 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); + void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); @@ -67,7 +64,7 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); @@ -75,10 +72,11 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags); - void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); + // Set up the default input and controller function for the given controller. + void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags); Nif::NIFFilePtr mNif; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 58501763b2..f2f59195cf 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -39,6 +39,7 @@ ParticleShooter::ParticleShooter() } ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) + : osgParticle::Shooter(copy, copyop) { *this = copy; } From d486cde330e5797ed484ac66e8b27ab413ee7f6a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 21:32:26 +0100 Subject: [PATCH 0037/1812] Fix broken VisControllers --- apps/nifosgtest/test.cpp | 3 ++- components/nifosg/controller.cpp | 3 ++- components/nifosg/nifloader.cpp | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index fee9197871..3e70c8cd22 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -133,7 +133,8 @@ int main(int argc, char** argv) viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); - //viewer.getCamera()->setCullMask() + // Mask to separate cull visitors from update visitors + viewer.getCamera()->setCullMask(~(0x1)); // We're going to change this from the event callback, set the variance to DYNAMIC so that // we don't interfere with the draw thread. diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 509d20bbf5..01671dbd81 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -316,7 +316,8 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { bool vis = calculate(getInputValue(nv)); - node->setNodeMask(vis ? ~0 : 0); + // Leave 0x1 enabled for UpdateVisitor, so we can make ourselves visible again in the future from this update callback + node->setNodeMask(vis ? ~0 : 0x1); } traverse(node, nv); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 26f0927b55..2fb60280b7 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -322,14 +322,14 @@ namespace NifOsg if (nifNode->recType == Nif::RC_RootCollisionNode) { collisionNode = true; - transformNode->setNodeMask(0); + // Leave mask for UpdateVisitor enabled + transformNode->setNodeMask(0x1); } // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later - // FIXME: this disables update callbacks, so VisController no longer works if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0); + transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) parentNode->insertChild(0, transformNode); From 32bb202290ecde69c3fbc491f6eb0ae32baabacb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Mar 2015 23:14:01 +0100 Subject: [PATCH 0038/1812] Implement BillboardNode --- components/nifosg/nifloader.cpp | 39 ++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2fb60280b7..5666fe07f6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -128,6 +128,7 @@ namespace } // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. + // Must be set on a Bone. class UpdateBone : public osg::NodeCallback { public: @@ -161,10 +162,39 @@ namespace } }; + // Custom node used to have a transform always oriented towards the camera. Can have translation and scale + // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. + class BillboardNode : public osg::MatrixTransform + { + public: + BillboardNode() : osg::MatrixTransform() {} + BillboardNode(const BillboardNode& copy, const osg::CopyOp& copyop) + : osg::MatrixTransform(copy, copyop) {} + BillboardNode(const osg::Matrix& matrix) + : osg::MatrixTransform(matrix) {} + + META_Node(NifOsg, BillboardNode) + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) + { + matrix.preMult(_matrix); + matrix.setRotate(osg::Quat()); + } + else // absolute + { + matrix = _matrix; + } + return true; + } + }; + // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space // on the MatrixTransform that the NodeCallback is attached to. This is used so we can // attach skinned meshes to their actual parent node, while still having the skinning // work in skeleton space as expected. + // Must be set on a MatrixTransform. class InvertBoneMatrix : public osg::NodeCallback { public: @@ -298,7 +328,11 @@ namespace NifOsg std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; - if (createSkeleton) + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode = new BillboardNode(toMatrix(nifNode->trafo)); + } + else if (createSkeleton) { osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; @@ -308,8 +342,7 @@ namespace NifOsg } else { - transformNode = new osg::MatrixTransform; - transformNode->setMatrix(toMatrix(nifNode->trafo)); + transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } if (nifNode->recType == Nif::RC_NiBSAnimationNode) From a9aee389c0e0551593ba995b2867e4cb833adca9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 03:50:50 +0100 Subject: [PATCH 0039/1812] Emitters attached to correct node, a bit ugly --- components/nifosg/nifloader.cpp | 63 +++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5666fe07f6..099288b4f9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -324,6 +324,13 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } + class RecIndexHolder : public osg::Referenced + { + public: + RecIndexHolder(int index) : mIndex(index) {} + int mIndex; + }; + void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { @@ -345,6 +352,8 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); + if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; if (nifNode->recType == Nif::RC_NiBSParticleNode) @@ -442,8 +451,14 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), - transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + // build the rotation part manually to avoid issues caused by scaling + osg::Matrixf mat; + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; + + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), mat.getRotate(), nifNode->trafo.scale)); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); @@ -524,6 +539,32 @@ namespace NifOsg } } + class FindEmitterNode : public osg::NodeVisitor + { + public: + FindEmitterNode(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) + { + } + + virtual void apply(osg::Node &searchNode) + { + if (searchNode.getUserData()) + { + RecIndexHolder* holder = static_cast(searchNode.getUserData()); + if (holder->mIndex == mRecIndex) + mFound = static_cast(&searchNode); + } + traverse(searchNode); + } + + osg::Group* mFound; + private: + int mRecIndex; + }; + void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new osgParticle::ParticleSystem); @@ -591,7 +632,7 @@ namespace NifOsg // ---- emitter - osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter; + osg::ref_ptr emitter = new osgParticle::ModularEmitter; emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); @@ -617,11 +658,19 @@ namespace NifOsg emitter->setPlacer(placer); - // TODO: attach to the emitter node - // Note: we also assume that the Emitter node is placed *before* the Particle node in the scene graph. + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - parentNode->addChild(emitter); + + FindEmitterNode find (partctrl->emitter->recIndex); + mRootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order?" << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; + emitterNode->addChild(emitter); osg::ref_ptr callback(new ParticleSystemController(partctrl)); setupController(partctrl, callback, animflags); @@ -631,7 +680,7 @@ namespace NifOsg osgParticle::ModularProgram* program = new osgParticle::ModularProgram; program->setParticleSystem(partsys); program->setReferenceFrame(rf); - parentNode->addChild(program); + emitterNode->addChild(program); for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) { if (e->recType == Nif::RC_NiParticleGrowFade) From 2e11642273fa218f34524cdc1dca2bd02657550a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 04:10:50 +0100 Subject: [PATCH 0040/1812] Fix BillboardNode overriding scale --- components/nifosg/nifloader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 099288b4f9..30b3c65373 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -180,7 +180,11 @@ namespace if (_referenceFrame==RELATIVE_RF) { matrix.preMult(_matrix); + osg::Vec3 scale = matrix.getScale(); matrix.setRotate(osg::Quat()); + matrix(0,0) = scale.x(); + matrix(1,1) = scale.y(); + matrix(2,2) = scale.z(); } else // absolute { From 71782462b73231bf088f51058b31fb3703949e5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 04:28:26 +0100 Subject: [PATCH 0041/1812] Subclass ParticleSystem to support limit on the number of particles --- components/nifosg/nifloader.cpp | 4 +++- components/nifosg/particle.cpp | 26 ++++++++++++++++++++++++++ components/nifosg/particle.hpp | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 30b3c65373..dcab807079 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -571,7 +571,7 @@ namespace NifOsg void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { - osg::ref_ptr partsys (new osgParticle::ParticleSystem); + osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); const Nif::NiAutoNormalParticlesData *particledata = NULL; @@ -630,6 +630,8 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + partsys->setQuota(partctrl->numParticles); + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index f2f59195cf..77e5f16df6 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -1,5 +1,7 @@ #include "particle.hpp" +#include + #include #include @@ -9,6 +11,30 @@ namespace NifOsg { +ParticleSystem::ParticleSystem() + : osgParticle::ParticleSystem() + , mQuota(std::numeric_limits::max()) +{ +} + +ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp ©op) + : osgParticle::ParticleSystem(copy, copyop) + , mQuota(copy.mQuota) +{ +} + +void ParticleSystem::setQuota(int quota) +{ + mQuota = quota; +} + +osgParticle::Particle* ParticleSystem::createParticle(const osgParticle::Particle *ptemplate) +{ + if (numParticles()-numDeadParticles() < mQuota) + return osgParticle::ParticleSystem::createParticle(ptemplate); + return NULL; +} + void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) { if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 13010fbac9..1f39050897 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -20,6 +20,23 @@ namespace Nif namespace NifOsg { + // Subclass ParticleSystem to support a limit on the number of active particles. + class ParticleSystem : public osgParticle::ParticleSystem + { + public: + ParticleSystem(); + ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, NifOsg::ParticleSystem) + + virtual osgParticle::Particle* createParticle(const osgParticle::Particle *ptemplate); + + void setQuota(int quota); + + private: + int mQuota; + }; + // HACK: Particle doesn't allow setting the initial age, but we need this for loading the particle system state class ParticleAgeSetter : public osgParticle::Particle { From 15f9c1ddcf25e3ec705b7a65b8d01ceecf4d069f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Mar 2015 23:10:52 +0100 Subject: [PATCH 0042/1812] NiBSPArrayController works --- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 4 ++ apps/opencs/view/render/scenewidget.cpp | 7 +- components/nifosg/nifloader.cpp | 68 ++++++++---------- components/nifosg/particle.cpp | 88 +++++++++++++++++++++++ components/nifosg/particle.hpp | 66 +++++++++++++++++ 6 files changed, 193 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2434343c9f..f21e8dd4da 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - loader.load(file, mBaseNode); + loader.loadAsSkeleton(file, mBaseNode); //mObject->setVisibilityFlags (Element_Reference); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index ee43ac13c6..8802b5cf33 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" @@ -13,6 +15,8 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data { //setNavigation (&mOrbit); + setCameraManipulator(new osgGA::TrackballManipulator); + QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 2f28c06df2..2dc5bdbc69 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -15,7 +15,6 @@ #include #include -#include #include namespace CSVRender @@ -72,14 +71,16 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) // Press S to reveal profiling stats addEventHandler(new osgViewer::StatsHandler); - setCameraManipulator(new osgGA::TrackballManipulator); - // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); + getCamera()->setCullMask(~(0x1)); + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); + + realize(); } void SceneWidget::paintEvent(QPaintEvent *event) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index dcab807079..27cce16fd3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -64,6 +64,18 @@ namespace return toMatrix(node->trafo); } + void getAllNiNodes(const Nif::Node* node, std::vector& outIndices) + { + const Nif::NiNode* ninode = dynamic_cast(node); + if (ninode) + { + outIndices.push_back(ninode->recIndex); + for (unsigned int i=0; ichildren.length(); ++i) + if (!ninode->children[i].empty()) + getAllNiNodes(ninode->children[i].getPtr(), outIndices); + } + } + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) { switch(mode) @@ -328,13 +340,6 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - class RecIndexHolder : public osg::Referenced - { - public: - RecIndexHolder(int index) : mIndex(index) {} - int mIndex; - }; - void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { @@ -356,6 +361,10 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + // UserData used for a variety of features: + // - finding the correct emitter node for a particle system + // - establishing connections to the animated collision shapes, which are handled in a separate loader + // - finding a random child NiNode in NiBspArrayController transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); if (nifNode->recType == Nif::RC_NiBSAnimationNode) @@ -543,32 +552,6 @@ namespace NifOsg } } - class FindEmitterNode : public osg::NodeVisitor - { - public: - FindEmitterNode(int recIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFound(NULL) - , mRecIndex(recIndex) - { - } - - virtual void apply(osg::Node &searchNode) - { - if (searchNode.getUserData()) - { - RecIndexHolder* holder = static_cast(searchNode.getUserData()); - if (holder->mIndex == mRecIndex) - mFound = static_cast(&searchNode); - } - traverse(searchNode); - } - - osg::Group* mFound; - private: - int mRecIndex; - }; - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) { osg::ref_ptr partsys (new ParticleSystem); @@ -582,8 +565,6 @@ namespace NifOsg else return; - // TODO: add special handling for NiBSPArrayController - const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -598,6 +579,12 @@ namespace NifOsg return; } + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) ? osgParticle::ParticleProcessor::RELATIVE_RF : osgParticle::ParticleProcessor::ABSOLUTE_RF; @@ -638,7 +625,7 @@ namespace NifOsg // ---- emitter - osg::ref_ptr emitter = new osgParticle::ModularEmitter; + osg::ref_ptr emitter = new Emitter(targets); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); @@ -668,7 +655,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - FindEmitterNode find (partctrl->emitter->recIndex); + FindRecIndexVisitor find (partctrl->emitter->recIndex); mRootNode->accept(find); if (!find.mFound) { @@ -676,6 +663,9 @@ namespace NifOsg return; } osg::Group* emitterNode = find.mFound; + + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! emitterNode->addChild(emitter); osg::ref_ptr callback(new ParticleSystemController(partctrl)); @@ -852,6 +842,7 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); geode->addDrawable(geometry); @@ -862,6 +853,7 @@ namespace NifOsg void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); @@ -969,7 +961,7 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: case Nif::RC_NiSpecularProperty: { - // TODO: handle these in handleTriShape so we know whether vertex colors are available + // Handled in handleTriShape so we know whether vertex colors are available break; } case Nif::RC_NiAlphaProperty: diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 77e5f16df6..934ef51ebe 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -191,4 +191,92 @@ void GravityAffector::operate(osgParticle::Particle *particle, double dt) } } +Emitter::Emitter() + : osgParticle::Emitter() +{ +} + +Emitter::Emitter(const Emitter ©, const osg::CopyOp ©op) + : osgParticle::Emitter(copy, copyop) + , mTargets(copy.mTargets) +{ +} + +Emitter::Emitter(const std::vector &targets) + : mTargets(targets) +{ +} + +void Emitter::setShooter(osgParticle::Shooter *shooter) +{ + mShooter = shooter; +} + +void Emitter::setPlacer(osgParticle::Placer *placer) +{ + mPlacer = placer; +} + +void Emitter::setCounter(osgParticle::Counter *counter) +{ + mCounter = counter; +} + +void Emitter::emitParticles(double dt) +{ + osg::Matrix worldToPs; + osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); + if (!worldMats.empty()) + { + const osg::Matrix psToWorld = worldMats[0]; + worldToPs = osg::Matrix::inverse(psToWorld); + } + + const osg::Matrix& ltw = getLocalToWorldMatrix(); + const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); + const osg::Matrix emitterToPs = ltw * worldToPs; + const osg::Matrix prevEmitterToPs = previous_ltw * worldToPs; + + int n = mCounter->numParticlesToCreate(dt); + + osg::Matrix transform; + if (!mTargets.empty()) + { + int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; + + // we could use a map here for faster lookup + FindRecIndexVisitor visitor(randomRecIndex); + getParent(0)->accept(visitor); + + if (!visitor.mFound) + { + std::cerr << "Emitter: Can't find emitter node" << randomRecIndex << std::endl; + return; + } + + osg::NodePath path = visitor.mFoundPath; + path.erase(path.begin()); + transform = osg::computeLocalToWorld(path); + } + + for (int i=0; icreateParticle(0); + if (P) + { + mPlacer->place(P); + + P->transformPositionVelocity(transform); + + mShooter->shoot(P); + + // Now need to transform the position and velocity because we having a moving model. + // (is this actually how MW works?) + float r = ((float)rand()/(float)RAND_MAX); + P->transformPositionVelocity(emitterToPs, prevEmitterToPs, r); + //P->transformPositionVelocity(ltw); + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 1f39050897..1c8174e8a4 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -151,6 +152,71 @@ namespace NifOsg osg::Vec3f mCachedWorldPositionDirection; }; + + class RecIndexHolder : public osg::Referenced + { + public: + RecIndexHolder(int index) : mIndex(index) {} + int mIndex; + }; + + // NodeVisitor to find a child node with the given record index, stored in the node's user data. + class FindRecIndexVisitor : public osg::NodeVisitor + { + public: + FindRecIndexVisitor(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) + { + } + + virtual void apply(osg::Node &searchNode) + { + if (searchNode.getUserData()) + { + RecIndexHolder* holder = static_cast(searchNode.getUserData()); + if (holder->mIndex == mRecIndex) + { + mFound = static_cast(&searchNode); + mFoundPath = getNodePath(); + return; + } + } + traverse(searchNode); + } + + osg::Group* mFound; + osg::NodePath mFoundPath; + private: + int mRecIndex; + }; + + // Subclass emitter to support randomly choosing one of the child node's transforms for the emit position of new particles. + class Emitter : public osgParticle::Emitter + { + public: + Emitter(const std::vector& targets); + Emitter(); + Emitter(const Emitter& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, NifOsg::Emitter) + + virtual void emitParticles(double dt); + + void setShooter(osgParticle::Shooter* shooter); + void setPlacer(osgParticle::Placer* placer); + void setCounter(osgParticle::Counter* counter); + + private: + // NIF Record indices + std::vector mTargets; + + osg::ref_ptr mPlacer; + osg::ref_ptr mShooter; + osg::ref_ptr mCounter; + }; + } #endif From 2db5df77f030ef053a008ea682be6e950a106474 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Mar 2015 22:52:44 +0100 Subject: [PATCH 0043/1812] Change rotation/scale workaround in preparation for loading .kf controllers --- components/CMakeLists.txt | 2 +- components/nif/niftypes.hpp | 2 +- components/nifosg/controller.cpp | 40 +++++++++++++++++++------- components/nifosg/controller.hpp | 7 ++--- components/nifosg/nifloader.cpp | 17 +++++++---- components/nifosg/particle.cpp | 24 ++++++++++++++++ components/nifosg/particle.hpp | 33 +++------------------ components/nifosg/userdata.hpp | 49 ++++++++++++++++++++++++++++++++ 8 files changed, 121 insertions(+), 53 deletions(-) create mode 100644 components/nifosg/userdata.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a78f164a61..e0ddeb2548 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -43,7 +43,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle + nifloader controller particle userdata ) #add_component_dir (nifcache diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 4f6998200f..7fefb92a2b 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -46,7 +46,7 @@ struct Matrix3 struct Transformation { osg::Vec3f pos; - Matrix3 rotation; + Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales float scale; static const Transformation& getIdentity() diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 01671dbd81..d61a8937af 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,15 +4,17 @@ #include #include #include +#include +#include #include #include -#include - #include +#include "userdata.hpp" + namespace NifOsg { @@ -76,13 +78,10 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg , mTranslations(copy.mTranslations) , mScales(copy.mScales) , mNif(copy.mNif) - , mInitialQuat(copy.mInitialQuat) - , mInitialScale(copy.mInitialScale) { } -KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale) +KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data) : mRotations(&data->mRotations) , mXRotations(&data->mXRotations) , mYRotations(&data->mYRotations) @@ -90,9 +89,8 @@ KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::Ni , mTranslations(&data->mTranslations) , mScales(&data->mScales) , mNif(nif) - , mInitialQuat(initialQuat) - , mInitialScale(initialScale) -{ } +{ +} osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { @@ -154,15 +152,35 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) float time = getInputValue(nv); + NodeUserData* userdata = static_cast(trans->getUserDataContainer()->getUserObject(0)); + Nif::Matrix3& rot = userdata->mRotationScale; + + bool setRot = false; if(mRotations->mKeys.size() > 0) + { mat.setRotate(interpKey(mRotations->mKeys, time)); + setRot = true; + } else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + { mat.setRotate(getXYZRotation(time)); + setRot = true; + } else - mat.setRotate(mInitialQuat); + { + // no rotation specified, use the previous value from the UserData + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(j,i) = rot.mValues[i][j]; // NB column/row major difference + } + + if (setRot) // copy the new values back to the UserData + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + rot.mValues[i][j] = mat(j,i); // NB column/row major difference // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) - float scale = mInitialScale; + float& scale = userdata->mScale; if(mScales->mKeys.size() > 0) scale = interpKey(mScales->mKeys, time); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 5a9af6324d..fb24fb5183 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -147,11 +147,9 @@ namespace NifOsg const Nif::FloatKeyMap* mZRotations; const Nif::Vector3KeyMap* mTranslations; const Nif::FloatKeyMap* mScales; + // TODO: we don't need to keep the whole NIF around, just change the key maps to Referenced Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid - osg::Quat mInitialQuat; - float mInitialScale; - using ValueInterpolator::interpKey; @@ -161,8 +159,7 @@ namespace NifOsg public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale); + KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data); KeyframeController(); KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 27cce16fd3..edc011c545 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -42,6 +42,7 @@ #include #include "particle.hpp" +#include "userdata.hpp" namespace { @@ -191,12 +192,13 @@ namespace { if (_referenceFrame==RELATIVE_RF) { + const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + matrix.preMult(_matrix); - osg::Vec3 scale = matrix.getScale(); matrix.setRotate(osg::Quat()); - matrix(0,0) = scale.x(); - matrix(1,1) = scale.y(); - matrix(2,2) = scale.z(); + matrix(0,0) = userdata->mScale; + matrix(1,1) = userdata->mScale; + matrix(2,2) = userdata->mScale; } else // absolute { @@ -365,7 +367,10 @@ namespace NifOsg // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader // - finding a random child NiNode in NiBspArrayController - transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); + // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to + // change only certain elements of the 4x4 transform + transformNode->getOrCreateUserDataContainer()->addUserObject( + new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; @@ -471,7 +476,7 @@ namespace NifOsg for (int j=0;j<3;++j) mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), mat.getRotate(), nifNode->trafo.scale)); + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr())); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 934ef51ebe..16c2b692c2 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -8,6 +8,8 @@ #include +#include "userdata.hpp" + namespace NifOsg { @@ -279,4 +281,26 @@ void Emitter::emitParticles(double dt) } } +FindRecIndexVisitor::FindRecIndexVisitor(int recIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFound(NULL) + , mRecIndex(recIndex) +{ +} + +void FindRecIndexVisitor::apply(osg::Node &searchNode) +{ + if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) + { + NodeUserData* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); + if (holder && holder->mIndex == mRecIndex) + { + mFound = static_cast(&searchNode); + mFoundPath = getNodePath(); + return; + } + } + traverse(searchNode); +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 1c8174e8a4..01e06f471f 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -152,39 +153,13 @@ namespace NifOsg osg::Vec3f mCachedWorldPositionDirection; }; - - class RecIndexHolder : public osg::Referenced - { - public: - RecIndexHolder(int index) : mIndex(index) {} - int mIndex; - }; - - // NodeVisitor to find a child node with the given record index, stored in the node's user data. + // NodeVisitor to find a child node with the given record index, stored in the node's user data container. class FindRecIndexVisitor : public osg::NodeVisitor { public: - FindRecIndexVisitor(int recIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFound(NULL) - , mRecIndex(recIndex) - { - } + FindRecIndexVisitor(int recIndex); - virtual void apply(osg::Node &searchNode) - { - if (searchNode.getUserData()) - { - RecIndexHolder* holder = static_cast(searchNode.getUserData()); - if (holder->mIndex == mRecIndex) - { - mFound = static_cast(&searchNode); - mFoundPath = getNodePath(); - return; - } - } - traverse(searchNode); - } + virtual void apply(osg::Node &searchNode); osg::Group* mFound; osg::NodePath mFoundPath; diff --git a/components/nifosg/userdata.hpp b/components/nifosg/userdata.hpp new file mode 100644 index 0000000000..9770890b0d --- /dev/null +++ b/components/nifosg/userdata.hpp @@ -0,0 +1,49 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_USERDATA_H +#define OPENMW_COMPONENTS_NIFOSG_USERDATA_H + +#include + +#include + +namespace NifOsg +{ + + // Note if you are copying a scene graph with this user data you should use the DEEP_COPY_USERDATA copyop. + class NodeUserData : public osg::Object + { + public: + NodeUserData(int index, float scale, const Nif::Matrix3& rotationScale) + : mIndex(index), mScale(scale), mRotationScale(rotationScale) + { + } + NodeUserData() + : mIndex(0), mScale(0) + { + } + NodeUserData(const NodeUserData& copy, const osg::CopyOp& copyop) + : Object(copy, copyop) + , mIndex(copy.mIndex) + , mScale(copy.mScale) + , mRotationScale(copy.mRotationScale) + { + } + + META_Object(NifOsg, NodeUserData) + + // NIF record index + int mIndex; + + // Hack: account for Transform differences between OSG and NIFs. + // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. + // Decomposing the original components from the 4x4 matrix isn't possible, which causes + // problems when a KeyframeController wants to change only one of these components. So + // we store the scale and rotation components separately here. + // Note for a cleaner solution it would be possible to write a custom Transform node, + // but then we have to fork osgAnimation :/ + float mScale; + Nif::Matrix3 mRotationScale; + }; + +} + +#endif From 9242e6d256601c220597ed9851e1eeac26e81001 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Mar 2015 23:47:49 +0100 Subject: [PATCH 0044/1812] Avoid copying keyframes in controller instances --- components/nif/data.cpp | 37 +++++++++++++------ components/nif/data.hpp | 23 ++++++------ components/nif/nifkey.hpp | 7 ++++ components/nifosg/controller.cpp | 63 +++++++++++++++++--------------- components/nifosg/controller.hpp | 33 ++++++++--------- components/nifosg/nifloader.cpp | 17 +-------- components/nifosg/particle.cpp | 2 +- 7 files changed, 95 insertions(+), 87 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index c4de1e1bfa..1fef8d56f2 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -115,18 +115,23 @@ void NiRotatingParticlesData::read(NIFStream *nif) void NiPosData::read(NIFStream *nif) { - mKeyList.read(nif); + mKeyList.reset(new Vector3KeyMap); + mKeyList->read(nif); } void NiUVData::read(NIFStream *nif) { for(int i = 0;i < 4;i++) - mKeyList[i].read(nif); + { + mKeyList[i].reset(new FloatKeyMap); + mKeyList[i]->read(nif); + } } void NiFloatData::read(NIFStream *nif) { - mKeyList.read(nif); + mKeyList.reset(new FloatKeyMap); + mKeyList->read(nif); } void NiPixelData::read(NIFStream *nif) @@ -163,7 +168,8 @@ void NiPixelData::read(NIFStream *nif) void NiColorData::read(NIFStream *nif) { - mKeyMap.read(nif); + mKeyMap.reset(new Vector4KeyMap); + mKeyMap->read(nif); } void NiVisData::read(NIFStream *nif) @@ -215,24 +221,31 @@ void NiMorphData::read(NIFStream *nif) mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { - mMorphs[i].mData.read(nif, true); + mMorphs[i].mKeyFrames.reset(new FloatKeyMap); + mMorphs[i].mKeyFrames->read(nif, true); nif->getVector3s(mMorphs[i].mVertices, vertCount); } } void NiKeyframeData::read(NIFStream *nif) { - mRotations.read(nif); - if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) + mRotations.reset(new QuaternionKeyMap); + mRotations->read(nif); + if(mRotations->mInterpolationType == Vector3KeyMap::sXYZInterpolation) { //Chomp unused float nif->getFloat(); - mXRotations.read(nif, true); - mYRotations.read(nif, true); - mZRotations.read(nif, true); + mXRotations.reset(new FloatKeyMap); + mYRotations.reset(new FloatKeyMap); + mZRotations.reset(new FloatKeyMap); + mXRotations->read(nif, true); + mYRotations->read(nif, true); + mZRotations->read(nif, true); } - mTranslations.read(nif); - mScales.read(nif); + mTranslations.reset(new Vector3KeyMap); + mTranslations->read(nif); + mScales.reset(new FloatKeyMap); + mScales->read(nif); } } // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 3b12448314..702fbf3138 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -78,7 +78,7 @@ public: class NiPosData : public Record { public: - Vector3KeyMap mKeyList; + Vector3KeyMapPtr mKeyList; void read(NIFStream *nif); }; @@ -86,7 +86,7 @@ public: class NiUVData : public Record { public: - FloatKeyMap mKeyList[4]; + FloatKeyMapPtr mKeyList[4]; void read(NIFStream *nif); }; @@ -94,7 +94,7 @@ public: class NiFloatData : public Record { public: - FloatKeyMap mKeyList; + FloatKeyMapPtr mKeyList; void read(NIFStream *nif); }; @@ -111,7 +111,7 @@ public: class NiColorData : public Record { public: - Vector4KeyMap mKeyMap; + Vector4KeyMapPtr mKeyMap; void read(NIFStream *nif); }; @@ -164,7 +164,7 @@ public: struct NiMorphData : public Record { struct MorphData { - FloatKeyMap mData; + FloatKeyMapPtr mKeyFrames; std::vector mVertices; }; std::vector mMorphs; @@ -175,14 +175,15 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { - QuaternionKeyMap mRotations; + QuaternionKeyMapPtr mRotations; - FloatKeyMap mXRotations; - FloatKeyMap mYRotations; - FloatKeyMap mZRotations; + // may be NULL + FloatKeyMapPtr mXRotations; + FloatKeyMapPtr mYRotations; + FloatKeyMapPtr mZRotations; - Vector3KeyMap mTranslations; - FloatKeyMap mScales; + Vector3KeyMapPtr mTranslations; + FloatKeyMapPtr mScales; void read(NIFStream *nif); }; diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 98687a2f97..d702d02925 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -8,6 +8,8 @@ #include #include +#include + #include "niffile.hpp" namespace Nif @@ -146,5 +148,10 @@ typedef KeyMapT Vector3KeyMap; typedef KeyMapT Vector4KeyMap; typedef KeyMapT QuaternionKeyMap; +typedef boost::shared_ptr FloatKeyMapPtr; +typedef boost::shared_ptr Vector3KeyMapPtr; +typedef boost::shared_ptr Vector4KeyMapPtr; +typedef boost::shared_ptr QuaternionKeyMapPtr; + } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d61a8937af..88802f81e0 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -77,18 +77,16 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg , mZRotations(copy.mZRotations) , mTranslations(copy.mTranslations) , mScales(copy.mScales) - , mNif(copy.mNif) { } -KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data) - : mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) +KeyframeController::KeyframeController(const Nif::NiKeyframeData *data) + : mRotations(data->mRotations) + , mXRotations(data->mXRotations) + , mYRotations(data->mYRotations) + , mZRotations(data->mZRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) { } @@ -127,9 +125,13 @@ osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &ke osg::Quat KeyframeController::getXYZRotation(float time) const { - float xrot = interpKey(mXRotations->mKeys, time); - float yrot = interpKey(mYRotations->mKeys, time); - float zrot = interpKey(mZRotations->mKeys, time); + float xrot = 0, yrot = 0, zrot = 0; + if (mXRotations.get()) + xrot = interpKey(mXRotations->mKeys, time); + if (mYRotations.get()) + yrot = interpKey(mYRotations->mKeys, time); + if (mZRotations.get()) + zrot = interpKey(mZRotations->mKeys, time); osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); @@ -138,7 +140,7 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Vec3f KeyframeController::getTranslation(float time) const { - if(mTranslations->mKeys.size() > 0) + if(mTranslations.get() && mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); return osg::Vec3f(); } @@ -156,12 +158,12 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) Nif::Matrix3& rot = userdata->mRotationScale; bool setRot = false; - if(mRotations->mKeys.size() > 0) + if(mRotations.get() && !mRotations->mKeys.empty()) { mat.setRotate(interpKey(mRotations->mKeys, time)); setRot = true; } - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + else if (mXRotations.get() || mYRotations.get() || mZRotations.get()) { mat.setRotate(getXYZRotation(time)); setRot = true; @@ -179,17 +181,17 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) for (int j=0;j<3;++j) rot.mValues[i][j] = mat(j,i); // NB column/row major difference - // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) float& scale = userdata->mScale; - if(mScales->mKeys.size() > 0) + if(mScales.get() && !mScales->mKeys.empty()) scale = interpKey(mScales->mKeys, time); for (int i=0;i<3;++i) for (int j=0;j<3;++j) mat(i,j) *= scale; - if(mTranslations->mKeys.size() > 0) + if(mTranslations.get() && !mTranslations->mKeys.empty()) mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); } @@ -217,13 +219,14 @@ GeomMorpherController::GeomMorpherController() GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, const osg::CopyOp ©op) : osg::Drawable::UpdateCallback(copy, copyop) , Controller(copy) - , mMorphs(copy.mMorphs) + , mKeyFrames(copy.mKeyFrames) { } GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) - : mMorphs(data->mMorphs) { + for (unsigned int i=0; imMorphs.size(); ++i) + mKeyFrames.push_back(data->mMorphs[i].mKeyFrames); } void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) @@ -233,15 +236,15 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable { if (hasInput()) { - if (mMorphs.size() <= 1) + if (mKeyFrames.size() <= 1) return; float input = getInputValue(nv); int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, input); + if (!(*it)->mKeys.empty()) + val = interpKey((*it)->mKeys, input); val = std::max(0.f, std::min(1.f, val)); morphGeom->setWeight(i, val); @@ -281,10 +284,10 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); float value = getInputValue(nv); - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); + float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); + float uScale = interpKey(mUScale->mKeys, value, 1.0f); + float vScale = interpKey(mVScale->mKeys, value, 1.0f); osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); @@ -360,7 +363,7 @@ void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { osg::StateSet* stateset = node->getStateSet(); - float value = interpKey(mData.mKeys, getInputValue(nv)); + float value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { @@ -392,7 +395,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { osg::StateSet* stateset = node->getStateSet(); - osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index fb24fb5183..eb9b95a814 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -135,20 +135,20 @@ namespace NifOsg virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - std::vector mMorphs; + std::vector mKeyFrames; }; class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - // TODO: we don't need to keep the whole NIF around, just change the key maps to Referenced - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid + Nif::QuaternionKeyMapPtr mRotations; + + Nif::FloatKeyMapPtr mXRotations; + Nif::FloatKeyMapPtr mYRotations; + Nif::FloatKeyMapPtr mZRotations; + + Nif::Vector3KeyMapPtr mTranslations; + Nif::FloatKeyMapPtr mScales; using ValueInterpolator::interpKey; @@ -158,8 +158,7 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data); + KeyframeController(const Nif::NiKeyframeData *data); KeyframeController(); KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); @@ -183,10 +182,10 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); private: - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; + Nif::FloatKeyMapPtr mUTrans; + Nif::FloatKeyMapPtr mVTrans; + Nif::FloatKeyMapPtr mUScale; + Nif::FloatKeyMapPtr mVScale; std::set mTextureUnits; }; @@ -210,7 +209,7 @@ namespace NifOsg class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - Nif::FloatKeyMap mData; + Nif::FloatKeyMapPtr mData; public: AlphaController(const Nif::NiFloatData *data); @@ -225,7 +224,7 @@ namespace NifOsg class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - Nif::Vector3KeyMap mData; + Nif::Vector3KeyMapPtr mData; public: MaterialColorController(const Nif::NiPosData *data); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index edc011c545..1e69ee4f58 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -454,7 +454,6 @@ namespace NifOsg void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { - bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -464,24 +463,10 @@ namespace NifOsg const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); if(!key->data.empty()) { - if (seenKeyframeCtrl) - { - std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; - continue; - } - - // build the rotation part manually to avoid issues caused by scaling - osg::Matrixf mat; - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; - - osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr())); + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); setupController(key, callback, animflags); transformNode->addUpdateCallback(callback); - - seenKeyframeCtrl = true; } } else if (ctrl->recType == Nif::RC_NiVisController) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 16c2b692c2..25970c8627 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -142,7 +142,7 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpKey(mData.mKeyMap.mKeys, time, osg::Vec4f(1,1,1,1)); + osg::Vec4f color = interpKey(mData.mKeyMap->mKeys, time, osg::Vec4f(1,1,1,1)); particle->setColorRange(osgParticle::rangev4(color, color)); } From 6219a7bbfc6e9c4c611f5eac349dbcb8d684de63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:31:16 +0100 Subject: [PATCH 0045/1812] Add .kf loader --- components/nifosg/controller.cpp | 33 ++++++++ components/nifosg/controller.hpp | 37 +++++++-- components/nifosg/nifloader.cpp | 138 ++++++++++++++++++++++++++----- components/nifosg/nifloader.hpp | 20 +++-- 4 files changed, 196 insertions(+), 32 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 88802f81e0..ef3157773a 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -469,4 +469,37 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } +SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data, int sourceIndex) + : KeyframeController(data) + , mSourceIndex(sourceIndex) + , mEnabled(false) +{ +} + +SourcedKeyframeController::SourcedKeyframeController() + : mSourceIndex(0) + , mEnabled(false) +{ +} + +SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) + : KeyframeController(copy, copyop) + , mSourceIndex(copy.mSourceIndex) + , mEnabled(copy.mEnabled) +{ +} + +void SourcedKeyframeController::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + +void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (mEnabled) + KeyframeController::operator()(node, nv); // calls traverse + else + traverse(node, nv); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index eb9b95a814..17bf3ae75b 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -140,6 +140,17 @@ namespace NifOsg class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { + public: + KeyframeController(const Nif::NiKeyframeData *data); + KeyframeController(); + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, KeyframeController) + + virtual osg::Vec3f getTranslation(float time) const; + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + private: Nif::QuaternionKeyMapPtr mRotations; @@ -152,21 +163,33 @@ namespace NifOsg using ValueInterpolator::interpKey; - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); osg::Quat getXYZRotation(float time) const; + }; + // Specialization of KeyframeController that remembers a "source index" for the animation source + // it came from, and can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. + // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from + // the relevant animation source. + class SourcedKeyframeController : public KeyframeController + { public: - KeyframeController(const Nif::NiKeyframeData *data); - KeyframeController(); - KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(); + SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, KeyframeController) - - virtual osg::Vec3f getTranslation(float time) const; + META_Object(NifOsg, SourcedKeyframeController) virtual void operator() (osg::Node*, osg::NodeVisitor*); + + int getSourceIndex() const; + + void setEnabled(bool enabled); + + private: + int mSourceIndex; + bool mEnabled; }; // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1e69ee4f58..c73bcbc969 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -248,6 +248,43 @@ namespace } }; + + // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files + class LoadKfVisitor : public osg::NodeVisitor + { + public: + LoadKfVisitor(std::map map, int sourceIndex) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMap(map) + , mSourceIndex(sourceIndex) + { + } + + void apply(osg::Node &node) + { + std::map::const_iterator found = mMap.find(node.getName()); + if (found != mMap.end()) + { + const Nif::NiKeyframeController* keyframectrl = found->second; + + osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl, false)); + + // Insert in front of the callback list, to make sure UpdateBone is last. + // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. + osg::ref_ptr old = node.getUpdateCallback(); + node.setUpdateCallback(callback); + callback->setNestedCallback(old); + } + + traverse(node); + } + + private: + std::map mMap; + int mSourceIndex; + }; + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; @@ -270,38 +307,94 @@ namespace namespace NifOsg { - void Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex) { - mNif = nif; - - if (nif->numRoots() < 1) + if(nif->numRoots() < 1) { nif->warn("Found no root nodes"); return; } - const Nif::Record* r = nif->getRoot(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) + if(r->recType != Nif::RC_NiSequenceStreamHelper) { - nif->warn("First root was not a node, but a " + r->recName); + nif->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; + } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); + + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + { + nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); return; } - mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map(), 0, 0); + //extractTextKeys(static_cast(extra.getPtr()), textKeys); + + std::map controllerMap; + + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + { + nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } + + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + if(key->data.empty()) + continue; + + controllerMap[strdata->string] = key; + } + + LoadKfVisitor visitor(controllerMap, sourceIndex); + rootNode->accept(visitor); } - void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) { mNif = nif; if (nif->numRoots() < 1) { - nif->warn("Found no root nodes"); - return; + nif->fail("Found no root nodes"); + } + + const Nif::Record* r = nif->getRoot(0); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + { + nif->fail("First root was not a node, but a " + r->recName); + } + + mRootNode = parentNode; + + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + return created; + } + + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + { + mNif = nif; + + if (nif->numRoots() < 1) + { + //nif->warn("Found no root nodes"); + nif->fail("Found no root nodes"); } const Nif::Record* r = nif->getRoot(0); @@ -310,17 +403,18 @@ namespace NifOsg const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) { - nif->warn("First root was not a node, but a " + r->recName); - return; + //nif->warn("First root was not a node, but a " + r->recName); + nif->fail("First root was not a node, but a " + r->recName); } + osg::ref_ptr skel = new osgAnimation::Skeleton; + parentNode->addChild(skel); + mRootNode = parentNode; - osgAnimation::Skeleton* skel = new osgAnimation::Skeleton; - mSkeleton = skel; - mRootNode->addChild(mSkeleton); + handleNode(nifNode, skel, true, std::map(), 0, 0); - handleNode(nifNode, mSkeleton, true, std::map(), 0, 0); + return skel; } void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) @@ -342,7 +436,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode) { osg::ref_ptr transformNode; @@ -362,6 +456,7 @@ namespace NifOsg { transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. // UserData used for a variety of features: // - finding the correct emitter node for a particle system @@ -428,6 +523,8 @@ namespace NifOsg handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); } } + + return transformNode; } void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) @@ -645,6 +742,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid FindRecIndexVisitor find (partctrl->emitter->recIndex); mRootNode->accept(find); if (!find.mFound) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 5bd25f6ca7..18e3e7db8c 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -30,21 +30,32 @@ namespace NifOsg { class Controller; + typedef std::multimap TextKeyMap; + /// The main class responsible for loading NIF files into an OSG-Scenegraph. class Loader { public: - /// @param node The parent of the root node for the created NIF file. - void load(Nif::NIFFilePtr file, osg::Group* parentNode); + // TODO: add auto-detection for skinning. We will still need a "force skeleton" parameter + // though, when assembling from several files, i.e. equipment parts + /// Create a scene graph for the given NIF. Assumes no skinning is used. + /// @param node The parent of the new root node for the created scene graph. + osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode); - void loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + /// Create a scene graph for the given NIF. Assumes skinning will be used. + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + + /// Load keyframe controllers from the given kf file onto the given scene graph. + /// @param sourceIndex The source index for this animation source, used for identifying + /// which animation source a keyframe controller came from. + void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex); const VFS::Manager* resourceManager; private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); @@ -81,7 +92,6 @@ namespace NifOsg Nif::NIFFilePtr mNif; osg::Group* mRootNode; - osg::Group* mSkeleton; }; } From 6d85444d2664d66da75252f342c016e007e967a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:51:44 +0100 Subject: [PATCH 0046/1812] Add text key loading --- apps/nifosgtest/test.cpp | 1 - components/nifosg/nifloader.cpp | 95 +++++++++++++++++++++++++-------- components/nifosg/nifloader.hpp | 8 +-- 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 3e70c8cd22..c21f423bfc 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -111,7 +111,6 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c73bcbc969..c05bad5ae5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,12 +302,50 @@ namespace } return morphGeom; } + + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) + { + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + if(nextpos != std::string::npos) + { + do { + nextpos--; + } while(nextpos > pos && ::isspace(str[nextpos])); + nextpos++; + } + else if(::isspace(*str.rbegin())) + { + std::string::const_iterator last = str.end(); + do { + --last; + } while(last != str.begin() && ::isspace(*last)); + nextpos = std::distance(str.begin(), ++last); + } + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + } } namespace NifOsg { - void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex) + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { if(nif->numRoots() < 1) { @@ -334,7 +372,7 @@ namespace NifOsg return; } - //extractTextKeys(static_cast(extra.getPtr()), textKeys); + extractTextKeys(static_cast(extra.getPtr()), textKeys); std::map controllerMap; @@ -364,55 +402,45 @@ namespace NifOsg rootNode->accept(visitor); } - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { nif->fail("First root was not a node, but a " + r->recName); - } mRootNode = parentNode; - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0); + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); return created; } - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) { mNif = nif; if (nif->numRoots() < 1) - { - //nif->warn("Found no root nodes"); nif->fail("Found no root nodes"); - } const Nif::Record* r = nif->getRoot(0); assert(r != NULL); const Nif::Node* nifNode = dynamic_cast(r); if (nifNode == NULL) - { - //nif->warn("First root was not a node, but a " + r->recName); nif->fail("First root was not a node, but a " + r->recName); - } osg::ref_ptr skel = new osgAnimation::Skeleton; parentNode->addChild(skel); mRootNode = parentNode; - handleNode(nifNode, skel, true, std::map(), 0, 0); + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); return skel; } @@ -437,7 +465,7 @@ namespace NifOsg } osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode) + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) { osg::ref_ptr transformNode; if (nifNode->recType == Nif::RC_NiBillboardNode) @@ -458,6 +486,9 @@ namespace NifOsg } // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader @@ -467,6 +498,27 @@ namespace NifOsg transformNode->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + extractTextKeys(tk, *textKeys); + } + else if(e->recType == Nif::RC_NiStringExtraData) + { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); + // String markers may contain important information + // affecting the entire subtree of this obj + // TODO: implement show markers flag + if(sd->string == "MRK" /*&& !sShowMarkers*/) + { + // Marker objects. These meshes are only visible in the editor. + skipMeshes = true; + } + } + } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) animflags |= nifNode->flags; if (nifNode->recType == Nif::RC_NiBSParticleNode) @@ -476,7 +528,7 @@ namespace NifOsg // We still need to animate the hidden bones so the physics system can access them if (nifNode->recType == Nif::RC_RootCollisionNode) { - collisionNode = true; + skipMeshes = true; // Leave mask for UpdateVisitor enabled transformNode->setNodeMask(0x1); } @@ -486,12 +538,9 @@ namespace NifOsg if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) + if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) @@ -520,7 +569,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, collisionNode); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 18e3e7db8c..9fc262c70c 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -40,15 +40,15 @@ namespace NifOsg // though, when assembling from several files, i.e. equipment parts /// Create a scene graph for the given NIF. Assumes no skinning is used. /// @param node The parent of the new root node for the created scene graph. - osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Create a scene graph for the given NIF. Assumes skinning will be used. - osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode); + osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. /// @param sourceIndex The source index for this animation source, used for identifying /// which animation source a keyframe controller came from. - void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex); + void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); const VFS::Manager* resourceManager; @@ -56,7 +56,7 @@ namespace NifOsg /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool collisionNode=false); + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); From 5a582e7eb76c2be68c792b0c05811dfbd6af750c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 01:57:03 +0100 Subject: [PATCH 0047/1812] Reintroduce showMarkers flag --- apps/opencs/editor.cpp | 4 +++- components/nifosg/nifloader.cpp | 9 ++++++++- components/nifosg/nifloader.hpp | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 3c4ce6868e..83fcb3e37b 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include "model/doc/document.hpp" #include "model/world/data.hpp" @@ -24,7 +26,7 @@ CS::Editor::Editor () CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); mSettings.setModel (CSMSettings::UserSettings::instance()); - //NifOgre::Loader::setShowMarkers(true); + NifOsg::Loader::setShowMarkers(true); mVFS.reset(new VFS::Manager(mFsStrict)); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c05bad5ae5..a37a132615 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -345,6 +345,13 @@ namespace namespace NifOsg { + bool Loader::sShowMarkers = false; + + void Loader::setShowMarkers(bool show) + { + sShowMarkers = show; + } + void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { if(nif->numRoots() < 1) @@ -511,7 +518,7 @@ namespace NifOsg // String markers may contain important information // affecting the entire subtree of this obj // TODO: implement show markers flag - if(sd->string == "MRK" /*&& !sShowMarkers*/) + if(sd->string == "MRK" && !sShowMarkers) { // Marker objects. These meshes are only visible in the editor. skipMeshes = true; diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 9fc262c70c..8f9efe6b37 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,11 +7,14 @@ #include -#include - namespace osg { class Geometry; + class Group; + class Node; + class MatrixTransform; + class StateSet; + class Geode; } namespace osgAnimation { @@ -50,6 +53,11 @@ namespace NifOsg /// which animation source a keyframe controller came from. void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); + /// Set whether or not nodes marked as "MRK" should be shown. + /// These should be hidden ingame, but visible in the editior. + /// Default: false. + static void setShowMarkers(bool show); + const VFS::Manager* resourceManager; private: @@ -92,6 +100,8 @@ namespace NifOsg Nif::NIFFilePtr mNif; osg::Group* mRootNode; + + static bool sShowMarkers; }; } From d6dea31b883a1fc6883ad8164d626439d72b6b55 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 15:55:57 +0100 Subject: [PATCH 0048/1812] OpenCS: Use a CompositeViewer with multiple views instead of multiple viewers Fixes the rendering glitches, turns out that multiple osgViewers were never an intended use case. --- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 80 ++++++++++++++--------- apps/opencs/view/render/scenewidget.hpp | 27 ++++++-- 3 files changed, 74 insertions(+), 35 deletions(-) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 8802b5cf33..c3f8384353 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -15,7 +15,7 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data { //setNavigation (&mOrbit); - setCameraManipulator(new osgGA::TrackballManipulator); + mView->setCameraManipulator(new osgGA::TrackballManipulator); QAbstractItemModel *referenceables = mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 2dc5bdbc69..195e550a32 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -14,7 +14,7 @@ #include #include - +#include #include namespace CSVRender @@ -25,20 +25,11 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) , mRootNode(0) { -#if QT_VERSION >= 0x050000 - // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; -#else - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; -#endif - - setThreadingModel(threadingModel); - - // disable the default setting of viewer.done() by pressing Escape. - setKeyEventSetsDone(0); + osgViewer::CompositeViewer& viewer = CompositeViewer::get(); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); //ds->setNumMultiSamples(8); + osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->windowName = ""; traits->windowDecoration = true; @@ -54,43 +45,72 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) // Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate when running multiple QGLWidgets traits->vsync = false; - osgQt::GraphicsWindowQt* window = new osgQt::GraphicsWindowQt(traits.get()); + mView = new osgViewer::View; + + osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); layout->addWidget(window->getGLWidget()); setLayout(layout); - getCamera()->setGraphicsContext(window); - - getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); - getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); + mView->getCamera()->setGraphicsContext(window); + mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); + mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); + mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; - setSceneData(mRootNode); + mView->setSceneData(mRootNode); // Press S to reveal profiling stats - addEventHandler(new osgViewer::StatsHandler); + mView->addEventHandler(new osgViewer::StatsHandler); + + mView->getCamera()->setCullMask(~(0x1)); + + viewer.addView(mView); + viewer.setDone(false); + viewer.realize(); +} + +SceneWidget::~SceneWidget() +{ + CompositeViewer::get().removeView(mView); +} + +void SceneWidget::flagAsModified() +{ + mView->requestRedraw(); +} + +CompositeViewer::CompositeViewer() +{ +#if QT_VERSION >= 0x050000 + // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; +#else + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; +#endif + + setThreadingModel(threadingModel); + + // disable the default setting of viewer.done() by pressing Escape. + setKeyEventSetsDone(0); // Only render when the camera position changed, or content flagged dirty //setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); - getCamera()->setCullMask(~(0x1)); - connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); mTimer.start( 10 ); - - realize(); } -void SceneWidget::paintEvent(QPaintEvent *event) +CompositeViewer &CompositeViewer::get() +{ + static CompositeViewer sThis; + return sThis; +} + +void CompositeViewer::update() { frame(); } -void SceneWidget::flagAsModified() -{ - _requestRedraw = true; -} - } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 3784a5c597..adb10b10ac 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -8,7 +8,8 @@ #include "lightingnight.hpp" #include "lightingbright.hpp" -#include +#include +#include namespace osg { @@ -26,24 +27,42 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget, public osgViewer::Viewer + class SceneWidget : public QWidget { Q_OBJECT public: SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - - virtual void paintEvent( QPaintEvent* event ); + ~SceneWidget(); void flagAsModified(); protected: + osg::ref_ptr mView; + osg::Group* mRootNode; QTimer mTimer; }; + + + // There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with multiple views + class CompositeViewer : public QObject, public osgViewer::CompositeViewer + { + Q_OBJECT + public: + CompositeViewer(); + + static CompositeViewer& get(); + + QTimer mTimer; + + public slots: + void update(); + }; + } #endif From ff9e2b03a07dae636833f14855bb4e30092d3345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:10:18 +0100 Subject: [PATCH 0049/1812] Hide NIF loader details in the implementation file --- components/nifosg/nifloader.cpp | 1849 ++++++++++++++++--------------- components/nifosg/nifloader.hpp | 55 - 2 files changed, 944 insertions(+), 960 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a37a132615..c00b4abe11 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -285,24 +285,6 @@ namespace int mSourceIndex; }; - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) - { - osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; - morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // No normals available in the MorphData - morphGeom->setMorphNormals(false); - - const std::vector& morphs = morpher->data.getPtr()->mMorphs; - // Note we are not interested in morph 0, which just contains the original vertices - for (unsigned int i = 1; i < morphs.size(); ++i) - { - osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); - morphGeom->addMorphTarget(morphTarget, 0.f); - } - return morphGeom; - } - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -352,959 +334,1016 @@ namespace NifOsg sShowMarkers = show; } - void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) + class LoaderImpl { - if(nif->numRoots() < 1) + public: + const VFS::Manager* mResourceManager; + bool mShowMarkers; + + LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers) + : mResourceManager(resourceManager) + , mShowMarkers(showMarkers) { - nif->warn("Found no root nodes"); - return; } - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - if(r->recType != Nif::RC_NiSequenceStreamHelper) + void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) { - nif->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; - } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) - { - nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - std::map controllerMap; - - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + if(nif->numRoots() < 1) { - nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; + nif->warn("Found no root nodes"); + return; } - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; + const Nif::Record *r = nif->getRoot(0); + assert(r != NULL); - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - - if(key->data.empty()) - continue; - - controllerMap[strdata->string] = key; - } - - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); - } - - osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; - - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); - - const Nif::Record* r = nif->getRoot(0); - - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); - - mRootNode = parentNode; - - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); - return created; - } - - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) - { - mNif = nif; - - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); - - const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); - - osg::ref_ptr skel = new osgAnimation::Skeleton; - parentNode->addChild(skel); - - mRootNode = parentNode; - - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); - - return skel; - } - - void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) - { - const Nif::PropertyList& props = nifNode->props; - for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); - - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); - } - - osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) - { - osg::ref_ptr transformNode; - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode = new BillboardNode(toMatrix(nifNode->trafo)); - } - else if (createSkeleton) - { - osgAnimation::Bone* bone = new osgAnimation::Bone; - transformNode = bone; - bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setName(nifNode->name); - bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); - } - else - { - transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); - } - // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. - - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - - // UserData used for a variety of features: - // - finding the correct emitter node for a particle system - // - establishing connections to the animated collision shapes, which are handled in a separate loader - // - finding a random child NiNode in NiBspArrayController - // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to - // change only certain elements of the 4x4 transform - transformNode->getOrCreateUserDataContainer()->addUserObject( - new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); - - for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + if(r->recType != Nif::RC_NiSequenceStreamHelper) { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - extractTextKeys(tk, *textKeys); + nif->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; } - else if(e->recType == Nif::RC_NiStringExtraData) + const Nif::NiSequenceStreamHelper *seq = static_cast(r); + + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) { - const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); - // String markers may contain important information - // affecting the entire subtree of this obj - // TODO: implement show markers flag - if(sd->string == "MRK" && !sShowMarkers) + nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); + return; + } + + extractTextKeys(static_cast(extra.getPtr()), textKeys); + + std::map controllerMap; + + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) { - // Marker objects. These meshes are only visible in the editor. - skipMeshes = true; + nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } + + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + if(key->data.empty()) + continue; + + controllerMap[strdata->string] = key; + } + + LoadKfVisitor visitor(controllerMap, sourceIndex); + rootNode->accept(visitor); + } + + osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); + + const Nif::Record* r = nif->getRoot(0); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); + + osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); + return created; + } + + osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + { + if (nif->numRoots() < 1) + nif->fail("Found no root nodes"); + + const Nif::Record* r = nif->getRoot(0); + assert(r != NULL); + + const Nif::Node* nifNode = dynamic_cast(r); + if (nifNode == NULL) + nif->fail("First root was not a node, but a " + r->recName); + + osg::ref_ptr skel = new osgAnimation::Skeleton; + parentNode->addChild(skel); + + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + + return skel; + } + + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) + { + const Nif::PropertyList& props = nifNode->props; + for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); + + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + } + + + osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) + { + osg::ref_ptr transformNode; + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode = new BillboardNode(toMatrix(nifNode->trafo)); + } + else if (createSkeleton) + { + osgAnimation::Bone* bone = new osgAnimation::Bone; + transformNode = bone; + bone->setMatrix(toMatrix(nifNode->trafo)); + bone->setName(nifNode->name); + bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); + } + else + { + transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + } + + if (!rootNode) + rootNode = transformNode; + + // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. + + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + parentNode->insertChild(0, transformNode); + + // UserData used for a variety of features: + // - finding the correct emitter node for a particle system + // - establishing connections to the animated collision shapes, which are handled in a separate loader + // - finding a random child NiNode in NiBspArrayController + // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to + // change only certain elements of the 4x4 transform + transformNode->getOrCreateUserDataContainer()->addUserObject( + new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); + + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + extractTextKeys(tk, *textKeys); + } + else if(e->recType == Nif::RC_NiStringExtraData) + { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); + // String markers may contain important information + // affecting the entire subtree of this obj + // TODO: implement show markers flag + if(sd->string == "MRK" && !mShowMarkers) + { + // Marker objects. These meshes are only visible in the editor. + skipMeshes = true; + } + } + } + + if (nifNode->recType == Nif::RC_NiBSAnimationNode) + animflags |= nifNode->flags; + if (nifNode->recType == Nif::RC_NiBSParticleNode) + particleflags |= nifNode->flags; + + // Hide collision shapes, but don't skip the subgraph + // We still need to animate the hidden bones so the physics system can access them + if (nifNode->recType == Nif::RC_RootCollisionNode) + { + skipMeshes = true; + // Leave mask for UpdateVisitor enabled + transformNode->setNodeMask(0x1); + } + + // We could probably skip hidden nodes entirely if they don't have a VisController that + // might make them visible later + if (nifNode->flags & Nif::NiNode::Flag_Hidden) + transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled + + applyNodeProperties(nifNode, transformNode, boundTextures, animflags); + + if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) + { + const Nif::NiTriShape* triShape = static_cast(nifNode); + if (!createSkeleton || triShape->skin.empty()) + handleTriShape(triShape, transformNode, boundTextures, animflags); + else + handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); + + if (!nifNode->controller.empty()) + handleMeshControllers(nifNode, transformNode, boundTextures, animflags); + } + + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); + + if (!nifNode->controller.empty()) + handleNodeControllers(nifNode, transformNode, animflags); + + // Added last so the changes from KeyframeControllers are taken into account + if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) + bone->addUpdateCallback(new UpdateBone); + + const Nif::NiNode *ninode = dynamic_cast(nifNode); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();++i) + { + if(!children[i].empty()) + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + } + } + + return transformNode; + } + + void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + { + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); + std::set texUnits; + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + texUnits.insert(it->first); + + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); + + transformNode->addUpdateCallback(ctrl); } } } - if (nifNode->recType == Nif::RC_NiBSAnimationNode) - animflags |= nifNode->flags; - if (nifNode->recType == Nif::RC_NiBSParticleNode) - particleflags |= nifNode->flags; - - // Hide collision shapes, but don't skip the subgraph - // We still need to animate the hidden bones so the physics system can access them - if (nifNode->recType == Nif::RC_RootCollisionNode) + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { - skipMeshes = true; - // Leave mask for UpdateVisitor enabled - transformNode->setNodeMask(0x1); - } - - // We could probably skip hidden nodes entirely if they don't have a VisController that - // might make them visible later - if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled - - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - - if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) - { - const Nif::NiTriShape* triShape = static_cast(nifNode); - if (!createSkeleton || triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures, animflags); - else - handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); - - if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures, animflags); - } - - if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, animflags, particleflags); - - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); - - // Added last so the changes from KeyframeControllers are taken into account - if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) - bone->addUpdateCallback(new UpdateBone); - - const Nif::NiNode *ninode = dynamic_cast(nifNode); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();++i) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { - if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys); - } - } - - return transformNode; - } - - void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) - { - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); - std::set texUnits; - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - texUnits.insert(it->first); - - osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); - setupController(uvctrl, ctrl, animflags); - transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); - - transformNode->addUpdateCallback(ctrl); - } - } - } - - void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) - { - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiKeyframeController) { - osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); - setupController(key, callback, animflags); + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); + } + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); + + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); transformNode->addUpdateCallback(callback); } } - else if (ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - - osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); - setupController(visctrl, callback, animflags); - transformNode->addUpdateCallback(callback); - } } - } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) - { - for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiAlphaController) - { - const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); - osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); - setupController(alphactrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(ctrl); - } - else if (ctrl->recType == Nif::RC_NiMaterialColorController) - { - const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); - setupController(matctrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(ctrl); - } - else - std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; - } - } - void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) - { - for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiFlipController) + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { - const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); - std::vector > textures; - for (unsigned int i=0; imSources.length(); ++i) + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiAlphaController) { - Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; - if (st.empty()) - continue; - - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); - - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); - textures.push_back(osg::ref_ptr(result.getImage())); + const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); + setupController(alphactrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } - osg::ref_ptr callback(new FlipController(flipctrl, textures)); - setupController(ctrl.getPtr(), callback, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); - node->addUpdateCallback(callback); + else if (ctrl->recType == Nif::RC_NiMaterialColorController) + { + const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); + setupController(matctrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); + } + else + std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + } + } + + + void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + { + for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiFlipController) + { + const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); + std::vector > textures; + for (unsigned int i=0; imSources.length(); ++i) + { + Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; + if (st.empty()) + continue; + + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + + // TODO: replace with texture manager + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); + textures.push_back(osg::ref_ptr(result.getImage())); + } + osg::ref_ptr callback(new FlipController(flipctrl, textures)); + setupController(ctrl.getPtr(), callback, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(callback); + } + else + std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + } + } + + void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + { + osgParticle::ModularProgram* program = new osgParticle::ModularProgram; + attachTo->addChild(program); + program->setParticleSystem(partsys); + program->setReferenceFrame(rf); + for (; !e.empty(); e = e->extra) + { + if (e->recType == Nif::RC_NiParticleGrowFade) + { + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity* gr = static_cast(e.getPtr()); + GravityAffector* affector = new GravityAffector(gr); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + ParticleColorAffector* affector = new ParticleColorAffector(clrdata); + program->addOperator(affector); + } + else if (e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement? + } + else + std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + } + } + + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + { + osg::ref_ptr partsys (new ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(nifNode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else if(nifNode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(nifNode)->data.getPtr(); + else + return; + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; + return; + } + + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } + + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + + // TODO: also take into account the transform by placement in the scene + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); + + int i=0; + for (std::vector::const_iterator it = partctrl->particles.begin(); + iactiveCount && it != partctrl->particles.end(); ++it, ++i) + { + const Nif::NiParticleSystemController::Particle& particle = *it; + + ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); + + osgParticle::Particle* created = partsys->createParticle(&particletemplate); + created->setLifeTime(std::max(0.f, particle.lifespan)); + osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; + created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); + created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); + + osg::Vec4f partcolor (1.f,1.f,1.f,1.f); + if (particle.vertex < int(particledata->colors.size())) + partcolor = particledata->colors.at(particle.vertex); + + float size = particledata->sizes.at(particle.vertex) * partctrl->size; + + created->setSizeRange(osgParticle::rangef(size, size)); + } + + partsys->setQuota(partctrl->numParticles); + + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + // ---- emitter + + osg::ref_ptr emitter = new Emitter(targets); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + + osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; + if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) + counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); + else + counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); + + emitter->setCounter(counter); + + ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f, + partctrl->horizontalDir, partctrl->horizontalAngle, + partctrl->verticalDir, partctrl->verticalAngle, + partctrl->lifetime, partctrl->lifetimeRandom); + emitter->setShooter(shooter); + + osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; + placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); + placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); + placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); + + emitter->setPlacer(placer); + + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + + // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid + FindRecIndexVisitor find (partctrl->emitter->recIndex); + rootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order?" << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; + + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! + emitterNode->addChild(emitter); + + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); + + // affectors must be attached *after* the emitter in the scene graph for correct update order + handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + + std::vector materialProps; + collectMaterialProperties(nifNode, materialProps); + applyMaterialProperties(geode, materialProps, true, animflags); + + partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + + + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) + parentNode->addChild(geode); + else + { + osg::MatrixTransform* trans = new osg::MatrixTransform; + trans->setUpdateCallback(new InverseWorldMatrix); + trans->addChild(geode); + parentNode->addChild(trans); + } + + // particle system updater (after the emitters and affectors in the scene graph) + osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); + } + + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + { + const Nif::NiTriShapeData* data = triShape->data.getPtr(); + + const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); + if (skin) + { + // 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. + osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); + osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + + const Nif::NiSkinData *skinData = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); + + mat = mat * getWorldTransform(bones[b].getPtr()); + + const std::vector &weights = skinData->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; + (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); + if(newNormals->size() > index) + { + osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); + normal = (normal * mat) * weight; + (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); + } + } + } + // Interpolating normalized normals doesn't necessarily give you a normalized result + // Currently we're using GL_NORMALIZE, so this isn't needed + //for (unsigned int i=0;isize();++i) + // (*newNormals)[i].normalize(); + + geometry->setVertexArray(newVerts); + if (!data->normals.empty()) + geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); } else - std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; - } - } - - void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) - { - osg::ref_ptr partsys (new ParticleSystem); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); - - const Nif::NiAutoNormalParticlesData *particledata = NULL; - if(nifNode->recType == Nif::RC_NiAutoNormalParticles) - particledata = static_cast(nifNode)->data.getPtr(); - else if(nifNode->recType == Nif::RC_NiRotatingParticles) - particledata = static_cast(nifNode)->data.getPtr(); - else - return; - - const Nif::NiParticleSystemController* partctrl = NULL; - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - partctrl = static_cast(ctrl.getPtr()); - } - if (!partctrl) - { - std::cerr << "No particle controller found " << std::endl; - return; - } - - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } - - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; - - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - - int i=0; - for (std::vector::const_iterator it = partctrl->particles.begin(); - iactiveCount && it != partctrl->particles.end(); ++it, ++i) - { - const Nif::NiParticleSystemController::Particle& particle = *it; - - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); - - osgParticle::Particle* created = partsys->createParticle(&particletemplate); - created->setLifeTime(std::max(0.f, particle.lifespan)); - osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; - created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); - created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); - - osg::Vec4f partcolor (1.f,1.f,1.f,1.f); - if (particle.vertex < int(particledata->colors.size())) - partcolor = particledata->colors.at(particle.vertex); - - float size = particledata->sizes.at(particle.vertex) * partctrl->size; - - created->setSizeRange(osgParticle::rangef(size, size)); - } - - partsys->setQuota(partctrl->numParticles); - - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); - partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - - // ---- emitter - - osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - - osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; - if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) - counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); - else - counter->setNumberOfParticlesPerSecondToCreate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); - - emitter->setCounter(counter); - - ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom*0.5f, - partctrl->velocity + partctrl->velocityRandom*0.5f, - partctrl->horizontalDir, partctrl->horizontalAngle, - partctrl->verticalDir, partctrl->verticalAngle, - partctrl->lifetime, partctrl->lifetimeRandom); - emitter->setShooter(shooter); - - osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; - placer->setXRange(-partctrl->offsetRandom.x(), partctrl->offsetRandom.x()); - placer->setYRange(-partctrl->offsetRandom.y(), partctrl->offsetRandom.y()); - placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); - - emitter->setPlacer(placer); - - // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. - // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. - // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - - // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid - FindRecIndexVisitor find (partctrl->emitter->recIndex); - mRootNode->accept(find); - if (!find.mFound) - { - std::cerr << "can't find emitter node, wrong node order?" << std::endl; - return; - } - osg::Group* emitterNode = find.mFound; - - // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node - // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! - emitterNode->addChild(emitter); - - osg::ref_ptr callback(new ParticleSystemController(partctrl)); - setupController(partctrl, callback, animflags); - emitter->setUpdateCallback(callback); - - // ----------- affector (must be after emitters in the scene graph) - osgParticle::ModularProgram* program = new osgParticle::ModularProgram; - program->setParticleSystem(partsys); - program->setReferenceFrame(rf); - emitterNode->addChild(program); - for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra) - { - if (e->recType == Nif::RC_NiParticleGrowFade) { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); - program->addOperator(affector); + geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); + if (!data->normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); } - else if (e->recType == Nif::RC_NiGravity) + + for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) { - const Nif::NiGravity* gr = static_cast(e.getPtr()); - GravityAffector* affector = new GravityAffector(gr); - program->addOperator(affector); + int textureStage = it->first; + int uvSet = it->second; + if (uvSet >= (int)data->uvlist.size()) + { + // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently + //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + continue; + } + + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); } - else if (e->recType == Nif::RC_NiParticleColorModifier) - { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); - const Nif::NiColorData *clrdata = cl->data.getPtr(); - ParticleColorAffector* affector = new ParticleColorAffector(clrdata); - program->addOperator(affector); - } - else if (e->recType == Nif::RC_NiParticleRotation) - { - // TODO: Implement? - } - else - std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + + if (!data->colors.empty()) + geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); + + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, + data->triangles.size(), + (unsigned short*)&data->triangles[0])); + + // osg::Material properties are handled here for two reasons: + // - if there are no vertex colors, we need to disable colorMode. + // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them + // above the actual renderable would be tedious. + std::vector materialProps; + collectMaterialProperties(triShape, materialProps); + applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } - // ----------- + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + { + osg::ref_ptr geometry; + if(!triShape->controller.empty()) + { + Nif::ControllerPtr ctrl = triShape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); + break; + } + } while(!(ctrl=ctrl->next).empty()); + } - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(geode, materialProps, true, animflags); + if (!geometry.get()) + geometry = new osg::Geometry; - partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + geode->addDrawable(geometry); - if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); - else + } + + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { - osg::MatrixTransform* trans = new osg::MatrixTransform; - trans->setUpdateCallback(new InverseWorldMatrix); + osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; + morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); + // No normals available in the MorphData + morphGeom->setMorphNormals(false); + + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + // Note we are not interested in morph 0, which just contains the original vertices + for (unsigned int i = 1; i < morphs.size(); ++i) + { + osg::ref_ptr morphTarget = new osg::Geometry; + morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphGeom->addMorphTarget(morphTarget, 0.f); + } + return morphGeom; + } + + void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + { + osg::ref_ptr geode (new osg::Geode); + geode->setName(triShape->name); // name will be used for part filtering + osg::ref_ptr geometry (new osg::Geometry); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + + osg::ref_ptr rig(new osgAnimation::RigGeometry); + rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones + // For more accuracy the skinning should be relative to the parent of the first skinned bone, + // rather than the root bone. + osg::BoundingBox box = geometry->getBound(); + box.expandBy(box._min-(box._max-box._min)/2); + box.expandBy(box._max+(box._max-box._min)/2); + rig->setInitialBound(box); + + const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + + // Assign bone weights + osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + std::string boneName = bones[i].getPtr()->name; + + osgAnimation::VertexInfluence influence; + influence.setName(boneName); + const std::vector &weights = data->bones[i].weights; + influence.reserve(weights.size()); + for(size_t j = 0;j < weights.size();j++) + { + osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.push_back(indexWeight); + } + + map->insert(std::make_pair(boneName, influence)); + } + rig->setInfluenceMap(map); + + osg::ref_ptr trans(new osg::MatrixTransform); + trans->setUpdateCallback(new InvertBoneMatrix()); + + geode->addDrawable(rig); + trans->addChild(geode); parentNode->addChild(trans); } - // particle system updater (after the emitters and affectors in the scene graph) - osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; - updater->addParticleSystem(partsys); - parentNode->addChild(updater); - } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) - { - const Nif::NiTriShapeData* data = triShape->data.getPtr(); - - const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); - if (skin) + void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + osg::Node *node, std::map& boundTextures, int animflags) { - // 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. - osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); - osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); + osg::StateSet* stateset = node->getOrCreateStateSet(); - const Nif::NiSkinData *skinData = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); - - mat = mat * getWorldTransform(bones[b].getPtr()); - - const std::vector &weights = skinData->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; - (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); - if(newNormals->size() > index) - { - osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); - normal = (normal * mat) * weight; - (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); - } - } - } - // Interpolating normalized normals doesn't necessarily give you a normalized result - // Currently we're using GL_NORMALIZE, so this isn't needed - //for (unsigned int i=0;isize();++i) - // (*newNormals)[i].normalize(); - - geometry->setVertexArray(newVerts); - if (!data->normals.empty()) - geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); - } - else - { - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); - } - - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - { - int textureStage = it->first; - int uvSet = it->second; - if (uvSet >= (int)data->uvlist.size()) - { - // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently - //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; - continue; - } - - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); - } - - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); - - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)&data->triangles[0])); - - // osg::Material properties are handled here for two reasons: - // - if there are no vertex colors, we need to disable colorMode. - // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them - // above the actual renderable would be tedious. - std::vector materialProps; - collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); - } - - void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) - { - osg::ref_ptr geometry; - if(!triShape->controller.empty()) - { - Nif::ControllerPtr ctrl = triShape->controller; - do { - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); - setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); - break; - } - } while(!(ctrl=ctrl->next).empty()); - } - - if (!geometry.get()) - geometry = new osg::Geometry; - - osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - - geode->addDrawable(geometry); - - parentNode->addChild(geode); - } - - void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) - { - osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering - osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - - osg::ref_ptr rig(new osgAnimation::RigGeometry); - rig->setSourceGeometry(geometry); - // Slightly expand the bounding box to account for movement of the bones - // For more accuracy the skinning should be relative to the parent of the first skinned bone, - // rather than the root bone. - osg::BoundingBox box = geometry->getBound(); - box.expandBy(box._min-(box._max-box._min)/2); - box.expandBy(box._max+(box._max-box._min)/2); - rig->setInitialBound(box); - - const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); - - // Assign bone weights - osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) - { - std::string boneName = bones[i].getPtr()->name; - - osgAnimation::VertexInfluence influence; - influence.setName(boneName); - const std::vector &weights = data->bones[i].weights; - influence.reserve(weights.size()); - for(size_t j = 0;j < weights.size();j++) - { - osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); - influence.push_back(indexWeight); - } - - map->insert(std::make_pair(boneName, influence)); - } - rig->setInfluenceMap(map); - - osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix()); - - geode->addDrawable(rig); - - trans->addChild(geode); - parentNode->addChild(trans); - } - - void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures, int animflags) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); - - switch (property->recType) - { - case Nif::RC_NiStencilProperty: - { - const Nif::NiStencilProperty* stencilprop = static_cast(property); - osg::FrontFace* frontFace = new osg::FrontFace; - switch (stencilprop->data.drawMode) - { - case 1: - frontFace->setMode(osg::FrontFace::CLOCKWISE); - break; - case 0: - case 2: - default: - frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); - break; - } - - stateset->setAttribute(frontFace, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - - // Stencil settings not enabled yet, not sure if the original engine is actually using them, - // since they might conflict with Morrowind's stencil shadows. - /* - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); - - stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - */ - } - case Nif::RC_NiWireframeProperty: - { - const Nif::NiWireframeProperty* wireprop = static_cast(property); - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL - : osg::PolygonMode::LINE); - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - break; - } - case Nif::RC_NiZBufferProperty: - { - const Nif::NiZBufferProperty* zprop = static_cast(property); - // VER_MW doesn't support a DepthFunction according to NifSkope - osg::Depth* depth = new osg::Depth; - depth->setWriteMask((zprop->flags>>1)&1); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - break; - } - // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed - case Nif::RC_NiMaterialProperty: - case Nif::RC_NiVertexColorProperty: - case Nif::RC_NiSpecularProperty: - { - // Handled in handleTriShape so we know whether vertex colors are available - break; - } - case Nif::RC_NiAlphaProperty: - { - const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; - if (alphaprop->flags&1) - { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); - - bool noSort = (alphaprop->flags>>13)&1; - if (!noSort) - { - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - } - } - else - { - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); - } - - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; - if((alphaprop->flags>>9)&1) - { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); - } - else - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); - break; - } - case Nif::RC_NiTexturingProperty: - { - const Nif::NiTexturingProperty* texprop = static_cast(property); - for (int i=0; itextures[i].inUse) - { - if (i != Nif::NiTexturingProperty::BaseTexture - && i != Nif::NiTexturingProperty::GlowTexture - && i != Nif::NiTexturingProperty::DarkTexture - && i != Nif::NiTexturingProperty::DetailTexture) - { - std::cerr << "Warning: unhandled texture stage " << i << std::endl; - continue; - } - - const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; - if(tex.texture.empty()) - { - std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; - continue; - } - const Nif::NiSourceTexture *st = tex.texture.getPtr(); - if (!st->external) - { - std::cerr << "Warning: unhandled internal texture " << std::endl; - continue; - } - - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); - - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); - osg::Image* image = result.getImage(); - osg::Texture2D* texture2d = new osg::Texture2D; - texture2d->setUnRefImageDataAfterApply(true); - texture2d->setImage(image); - - unsigned int clamp = static_cast(tex.clamp); - int wrapT = (clamp) & 0x1; - int wrapS = (clamp >> 1) & 0x1; - - texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); - texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); - - if (i == Nif::NiTexturingProperty::GlowTexture) - { - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::ADD); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); - } - else if (i == Nif::NiTexturingProperty::DarkTexture) - { - // untested - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::MODULATE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); - } - else if (i == Nif::NiTexturingProperty::DetailTexture) - { - // untested - osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; - texEnv->setScale_RGB(2.f); - texEnv->setCombine_Alpha(GL_MODULATE); - texEnv->setOperand0_Alpha(GL_SRC_ALPHA); - texEnv->setOperand1_Alpha(GL_SRC_ALPHA); - texEnv->setSource0_Alpha(GL_PREVIOUS); - texEnv->setSource1_Alpha(GL_TEXTURE); - texEnv->setCombine_RGB(GL_MODULATE); - texEnv->setOperand0_RGB(GL_SRC_COLOR); - texEnv->setOperand1_RGB(GL_SRC_COLOR); - texEnv->setSource0_RGB(GL_PREVIOUS); - texEnv->setSource1_RGB(GL_TEXTURE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); - } - - boundTextures[i] = tex.uvSet; - } - else if (boundTextures.find(i) != boundTextures.end()) - { - stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); - boundTextures.erase(i); - } - handleTextureControllers(texprop, node, stateset, animflags); - } - break; - } - case Nif::RC_NiDitherProperty: - { - stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - break; - } - default: - std::cerr << "Unhandled " << property->recName << std::endl; - break; - } - } - - void Loader::applyMaterialProperties(osg::Node* node, const std::vector& properties, - bool hasVertexColors, int animflags) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); - - int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; - mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty - for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) - { - const Nif::Property* property = *it; switch (property->recType) { - case Nif::RC_NiSpecularProperty: + case Nif::RC_NiStencilProperty: { - specFlags = property->flags; - break; - } - case Nif::RC_NiMaterialProperty: - { - const Nif::NiMaterialProperty* matprop = static_cast(property); - - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); - mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); - - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); - mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); - - if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, stateset, animflags); - - break; - } - case Nif::RC_NiVertexColorProperty: - { - const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) + const Nif::NiStencilProperty* stencilprop = static_cast(property); + osg::FrontFace* frontFace = new osg::FrontFace; + switch (stencilprop->data.drawMode) { - case 0: - mat->setColorMode(osg::Material::OFF); - break; case 1: - mat->setColorMode(osg::Material::EMISSION); + frontFace->setMode(osg::FrontFace::CLOCKWISE); break; + case 0: case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + default: + frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); break; } + + stateset->setAttribute(frontFace, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + // Stencil settings not enabled yet, not sure if the original engine is actually using them, + // since they might conflict with Morrowind's stencil shadows. + /* + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + + stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + */ } + case Nif::RC_NiWireframeProperty: + { + const Nif::NiWireframeProperty* wireprop = static_cast(property); + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL + : osg::PolygonMode::LINE); + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + break; + } + case Nif::RC_NiZBufferProperty: + { + const Nif::NiZBufferProperty* zprop = static_cast(property); + // VER_MW doesn't support a DepthFunction according to NifSkope + osg::Depth* depth = new osg::Depth; + depth->setWriteMask((zprop->flags>>1)&1); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + break; + } + // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed + case Nif::RC_NiMaterialProperty: + case Nif::RC_NiVertexColorProperty: + case Nif::RC_NiSpecularProperty: + { + // Handled in handleTriShape so we know whether vertex colors are available + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) + { + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) + { + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + } + } + else + { + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } + + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + break; + } + case Nif::RC_NiTexturingProperty: + { + const Nif::NiTexturingProperty* texprop = static_cast(property); + for (int i=0; itextures[i].inUse) + { + if (i != Nif::NiTexturingProperty::BaseTexture + && i != Nif::NiTexturingProperty::GlowTexture + && i != Nif::NiTexturingProperty::DarkTexture + && i != Nif::NiTexturingProperty::DetailTexture) + { + std::cerr << "Warning: unhandled texture stage " << i << std::endl; + continue; + } + + const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; + if(tex.texture.empty()) + { + std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + continue; + } + const Nif::NiSourceTexture *st = tex.texture.getPtr(); + if (!st->external) + { + std::cerr << "Warning: unhandled internal texture " << std::endl; + continue; + } + + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + + // TODO: replace with texture manager + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); + osg::Image* image = result.getImage(); + osg::Texture2D* texture2d = new osg::Texture2D; + texture2d->setUnRefImageDataAfterApply(true); + texture2d->setImage(image); + + unsigned int clamp = static_cast(tex.clamp); + int wrapT = (clamp) & 0x1; + int wrapS = (clamp >> 1) & 0x1; + + texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); + texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + + if (i == Nif::NiTexturingProperty::GlowTexture) + { + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::ADD); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DarkTexture) + { + // untested + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + else if (i == Nif::NiTexturingProperty::DetailTexture) + { + // untested + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setScale_RGB(2.f); + texEnv->setCombine_Alpha(GL_MODULATE); + texEnv->setOperand0_Alpha(GL_SRC_ALPHA); + texEnv->setOperand1_Alpha(GL_SRC_ALPHA); + texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource1_Alpha(GL_TEXTURE); + texEnv->setCombine_RGB(GL_MODULATE); + texEnv->setOperand0_RGB(GL_SRC_COLOR); + texEnv->setOperand1_RGB(GL_SRC_COLOR); + texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource1_RGB(GL_TEXTURE); + stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + } + + boundTextures[i] = tex.uvSet; + } + else if (boundTextures.find(i) != boundTextures.end()) + { + stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); + boundTextures.erase(i); + } + handleTextureControllers(texprop, node, stateset, animflags); + } + break; + } + case Nif::RC_NiDitherProperty: + { + stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON + : osg::StateAttribute::OFF); + break; + } + default: + std::cerr << "Unhandled " << property->recName << std::endl; + break; } } - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + void applyMaterialProperties(osg::Node* node, const std::vector& properties, + bool hasVertexColors, int animflags) + { + osg::StateSet* stateset = node->getOrCreateStateSet(); - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); + // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + if (!matprop->controller.empty()) + handleMaterialControllers(matprop, node, stateset, animflags); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } + + }; + + osg::Node* Loader::load(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + return loader.load(file, parentNode, textKeys); } + + osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + return loader.loadAsSkeleton(file, parentNode, textKeys); + } + + void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) + { + LoaderImpl loader(resourceManager, sShowMarkers); + loader.loadKf(kf, rootNode, sourceIndex, textKeys); + } + } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 8f9efe6b37..7ccbbfd2cc 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -9,24 +9,8 @@ namespace osg { - class Geometry; class Group; class Node; - class MatrixTransform; - class StateSet; - class Geode; -} -namespace osgAnimation -{ - class Bone; -} - -namespace Nif -{ - class Node; - class NiTriShape; - class Property; - class Controller; } namespace NifOsg @@ -62,45 +46,6 @@ namespace NifOsg private: - /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys); - - void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); - - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - - void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - - void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - - void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, - osg::Node* node, std::map& boundTextures, int animflags); - - void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int animflags, int particleflags); - - // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); - - // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map& boundTextures, int animflags); - - // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); - - // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. - void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - - void applyMaterialProperties(osg::Node* node, const std::vector& properties, - bool hasVertexColors, int animflags); - - // Set up the default input and controller function for the given controller. - void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags); - - Nif::NIFFilePtr mNif; - - osg::Group* mRootNode; - static bool sShowMarkers; }; From 36ad40827b43d233162ab9c63e5a03e1dbdad64c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:17:40 +0100 Subject: [PATCH 0050/1812] Move parent node attachment out of nifloader --- apps/nifosgtest/test.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- components/nifosg/nifloader.cpp | 29 ++++++++++++++--------------- components/nifosg/nifloader.hpp | 9 ++++----- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index c21f423bfc..0da95d13d4 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -114,7 +114,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; - loader.loadAsSkeleton(nif, newNode); + newNode->addChild(loader.loadAsSkeleton(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f21e8dd4da..f48fcc4402 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - loader.loadAsSkeleton(file, mBaseNode); + mBaseNode->addChild(loader.loadAsSkeleton(file)); //mObject->setVisibilityFlags (Element_Reference); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c00b4abe11..60e94c67a8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -403,7 +403,7 @@ namespace NifOsg rootNode->accept(visitor); } - osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -414,11 +414,11 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::Node* created = handleNode(nifNode, parentNode, false, std::map(), 0, 0, false, textKeys); + osg::Node* created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); return created; } - osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) + osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -431,9 +431,7 @@ namespace NifOsg nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr skel = new osgAnimation::Skeleton; - parentNode->addChild(skel); - - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); return skel; } @@ -458,7 +456,7 @@ namespace NifOsg } - osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -484,9 +482,6 @@ namespace NifOsg // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - parentNode->insertChild(0, transformNode); - // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader @@ -567,7 +562,11 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + { + // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) + transformNode->insertChild(0, + handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); + } } } @@ -1328,16 +1327,16 @@ namespace NifOsg }; - osg::Node* Loader::load(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) { LoaderImpl loader(resourceManager, sShowMarkers); - return loader.load(file, parentNode, textKeys); + return loader.load(file, textKeys); } - osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys) + osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) { LoaderImpl loader(resourceManager, sShowMarkers); - return loader.loadAsSkeleton(file, parentNode, textKeys); + return loader.loadAsSkeleton(file, textKeys); } void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7ccbbfd2cc..d38b88f975 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,16 +7,15 @@ #include +#include + namespace osg { - class Group; class Node; } namespace NifOsg { - class Controller; - typedef std::multimap TextKeyMap; /// The main class responsible for loading NIF files into an OSG-Scenegraph. @@ -27,10 +26,10 @@ namespace NifOsg // though, when assembling from several files, i.e. equipment parts /// Create a scene graph for the given NIF. Assumes no skinning is used. /// @param node The parent of the new root node for the created scene graph. - osg::Node* load(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); + osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Create a scene graph for the given NIF. Assumes skinning will be used. - osg::Node* loadAsSkeleton(Nif::NIFFilePtr file, osg::Group* parentNode, TextKeyMap* textKeys = NULL); + osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. /// @param sourceIndex The source index for this animation source, used for identifying From 018115601af6f9149d48c73ecc90a80d86ca4d0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:49:33 +0100 Subject: [PATCH 0051/1812] Move particle emitter/affector handling to separate functions --- components/nifosg/nifloader.cpp | 113 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 60e94c67a8..b41bc075f2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -442,12 +442,13 @@ namespace NifOsg for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); @@ -455,7 +456,6 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -623,7 +623,6 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -651,7 +650,6 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -724,11 +722,14 @@ namespace NifOsg } } - - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl, + osgParticle::ParticleProcessor::ReferenceFrame rf) { - osg::ref_ptr partsys (new ParticleSystem); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + // TODO: also take into account the transform by placement in the scene (should be done post-load) + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -738,35 +739,6 @@ namespace NifOsg else return; - const Nif::NiParticleSystemController* partctrl = NULL; - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - partctrl = static_cast(ctrl.getPtr()); - } - if (!partctrl) - { - std::cerr << "No particle controller found " << std::endl; - return; - } - - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } - - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; - - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - int i=0; for (std::vector::const_iterator it = partctrl->particles.begin(); iactiveCount && it != partctrl->particles.end(); ++it, ++i) @@ -789,18 +761,17 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + } - partsys->setQuota(partctrl->numParticles); - - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); - partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - - // ---- emitter + osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + { + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) @@ -823,6 +794,43 @@ namespace NifOsg placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); emitter->setPlacer(placer); + return emitter; + } + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + { + osg::ref_ptr partsys (new ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; + return; + } + + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + + handleParticleInitialState(nifNode, partsys, partctrl, rf); + + partsys->setQuota(partctrl->numParticles); + + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -859,6 +867,11 @@ namespace NifOsg partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + // particle system updater (after the emitters and affectors in the scene graph) + // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way + osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -869,11 +882,6 @@ namespace NifOsg trans->addChild(geode); parentNode->addChild(trans); } - - // particle system updater (after the emitters and affectors in the scene graph) - osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; - updater->addParticleSystem(partsys); - parentNode->addChild(updater); } void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) @@ -1061,7 +1069,7 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + void handleProperty(const Nif::Property *property, osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1088,6 +1096,7 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); + // TODO: // Stencil settings not enabled yet, not sure if the original engine is actually using them, // since they might conflict with Morrowind's stencil shadows. /* From 376f0f3ac1e5f1c48d05060ea2d00dc12b95f3fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 17:49:06 +0100 Subject: [PATCH 0052/1812] Small cleanup --- components/nifosg/nifloader.cpp | 1 - components/nifosg/nifloader.hpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b41bc075f2..6a2523120c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -503,7 +503,6 @@ namespace NifOsg const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - // TODO: implement show markers flag if(sd->string == "MRK" && !mShowMarkers) { // Marker objects. These meshes are only visible in the editor. diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index d38b88f975..43eb8da783 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -19,6 +19,8 @@ namespace NifOsg typedef std::multimap TextKeyMap; /// The main class responsible for loading NIF files into an OSG-Scenegraph. + /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters + /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. class Loader { public: From 1affa497d55da9a9f35804517b36f45dac8f72ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 19:18:48 +0100 Subject: [PATCH 0053/1812] Delete the old nifogre loader --- components/CMakeLists.txt | 4 - components/nifogre/controller.hpp | 111 -- components/nifogre/material.cpp | 442 -------- components/nifogre/material.hpp | 51 - components/nifogre/mesh.cpp | 412 ------- components/nifogre/mesh.hpp | 55 - components/nifogre/ogrenifloader.cpp | 1492 -------------------------- components/nifogre/ogrenifloader.hpp | 151 --- components/nifogre/particles.cpp | 773 ------------- components/nifogre/particles.hpp | 50 - components/nifogre/skeleton.cpp | 179 --- components/nifogre/skeleton.hpp | 62 -- components/ogreinit/ogreinit.cpp | 32 - components/ogreinit/ogreinit.hpp | 3 - 14 files changed, 3817 deletions(-) delete mode 100644 components/nifogre/controller.hpp delete mode 100644 components/nifogre/material.cpp delete mode 100644 components/nifogre/material.hpp delete mode 100644 components/nifogre/mesh.cpp delete mode 100644 components/nifogre/mesh.hpp delete mode 100644 components/nifogre/ogrenifloader.cpp delete mode 100644 components/nifogre/ogrenifloader.hpp delete mode 100644 components/nifogre/particles.cpp delete mode 100644 components/nifogre/particles.hpp delete mode 100644 components/nifogre/skeleton.cpp delete mode 100644 components/nifogre/skeleton.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e0ddeb2548..48de580bc4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,10 +50,6 @@ add_component_dir (nifosg # nifcache # ) -#add_component_dir (nifogre -# ogrenifloader skeleton material mesh particles controller -# ) - #add_component_dir (nifbullet # bulletnifloader # ) diff --git a/components/nifogre/controller.hpp b/components/nifogre/controller.hpp deleted file mode 100644 index cc750ea65e..0000000000 --- a/components/nifogre/controller.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_CONTROLLER_H -#define COMPONENTS_NIFOGRE_CONTROLLER_H - -#include -#include -#include - -namespace NifOgre -{ - - class ValueInterpolator - { - protected: - float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const - { - if (keys.size() == 0) - return def; - - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::FloatKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::FloatKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::FloatKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; - } - - Ogre::Vector3 interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const - { - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::Vector3Key* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::Vector3KeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::Vector3Key* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); - } - else - return keys.rbegin()->second.mValue; - } - }; - - // FIXME: Should not be here. - class DefaultFunction : public Ogre::ControllerFunction - { - private: - float mFrequency; - float mPhase; - float mStartTime; - public: - float mStopTime; - - public: - DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) - : Ogre::ControllerFunction(deltaInput) - , mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) - { - if(mDeltaInput) - mDeltaCount = mPhase; - } - - virtual Ogre::Real calculate(Ogre::Real value) - { - if(mDeltaInput) - { - if (mStopTime - mStartTime == 0.f) - return 0.f; - - mDeltaCount += value*mFrequency; - if(mDeltaCount < mStartTime) - mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, - mStopTime - mStartTime); - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; - } - - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; - } - }; - -} - -#endif diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp deleted file mode 100644 index 90930bca8e..0000000000 --- a/components/nifogre/material.cpp +++ /dev/null @@ -1,442 +0,0 @@ -#include "material.hpp" - -#include -#include -#include -#include - -#include - -#include -#include - -#include - - -namespace NifOgre -{ - -// Conversion of blend / test mode from NIF -static const char *getBlendFactor(int mode) -{ - switch(mode) - { - case 0: return "one"; - case 1: return "zero"; - case 2: return "src_colour"; - case 3: return "one_minus_src_colour"; - case 4: return "dest_colour"; - case 5: return "one_minus_dest_colour"; - case 6: return "src_alpha"; - case 7: return "one_minus_src_alpha"; - case 8: return "dest_alpha"; - case 9: return "one_minus_dest_alpha"; - case 10: return "src_alpha_saturate"; - } - std::cerr<< "Unexpected blend mode: "<setProperty(textureSlotName + "UVSet", sh::makeProperty(new sh::IntValue(tex.uvSet))); - const std::string clampMode = textureSlotName + "ClampMode"; - switch (tex.clamp) - { - case 0: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp clamp"))); - break; - case 1: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp wrap"))); - break; - case 2: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap clamp"))); - break; - case 3: - default: - material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap wrap"))); - break; - } -} - -Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - const Nif::NiStencilProperty *stencilprop, - bool &needTangents, bool particleMaterial) -{ - Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); - Ogre::MaterialPtr material = matMgr.getByName(name); - if(!material.isNull()) - return name; - - Ogre::Vector3 ambient(1.0f); - Ogre::Vector3 diffuse(1.0f); - Ogre::Vector3 specular(0.0f); - Ogre::Vector3 emissive(0.0f); - float glossiness = 0.0f; - float alpha = 1.0f; - int alphaFlags = 0; - int alphaTest = 0; - int vertMode = 2; - //int lightMode = 1; - int depthFlags = 3; - // Default should be 1, but Bloodmoon's models are broken - int specFlags = 0; - int wireFlags = 0; - int drawMode = 1; - Ogre::String texName[7]; - - bool vertexColour = (shapedata->colors.size() != 0); - - // Texture - if(texprop) - { - for(int i = 0;i < 7;i++) - { - if(!texprop->textures[i].inUse) - continue; - if(texprop->textures[i].texture.empty()) - { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); - continue; - } - - const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); - if(st->external) - texName[i] = Misc::ResourceHelpers::correctTexturePath(st->filename); - else - warn("Found internal texture, ignoring."); - } - - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType != Nif::RC_NiFlipController) // Handled in ogrenifloader - warn("Unhandled texture controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Alpha modifiers - if(alphaprop) - { - alphaFlags = alphaprop->flags; - alphaTest = alphaprop->data.threshold; - - Nif::ControllerPtr ctrls = alphaprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled alpha controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Vertex color handling - if(vertprop) - { - vertMode = vertprop->data.vertmode; - // FIXME: Handle lightmode? - //lightMode = vertprop->data.lightmode; - - Nif::ControllerPtr ctrls = vertprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(zprop) - { - depthFlags = zprop->flags; - // Depth function??? - - Nif::ControllerPtr ctrls = zprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled depth controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(specprop) - { - specFlags = specprop->flags; - - Nif::ControllerPtr ctrls = specprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled specular controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(wireprop) - { - wireFlags = wireprop->flags; - - Nif::ControllerPtr ctrls = wireprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(stencilprop) - { - drawMode = stencilprop->data.drawMode; - if (stencilprop->data.enabled) - warn("Unhandled stencil test in "+name); - - Nif::ControllerPtr ctrls = stencilprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled stencil controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Material - if(matprop) - { - ambient = matprop->data.ambient; - diffuse = matprop->data.diffuse; - specular = matprop->data.specular; - emissive = matprop->data.emissive; - glossiness = matprop->data.glossiness; - alpha = matprop->data.alpha; - - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType != Nif::RC_NiAlphaController && ctrls->recType != Nif::RC_NiMaterialColorController) - warn("Unhandled material controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if (particleMaterial) - { - alpha = 1.f; // Apparently ignored, might be overridden by particle vertex colors? - } - - { - // Generate a hash out of all properties that can affect the material. - size_t h = 0; - boost::hash_combine(h, ambient.x); - boost::hash_combine(h, ambient.y); - boost::hash_combine(h, ambient.z); - boost::hash_combine(h, diffuse.x); - boost::hash_combine(h, diffuse.y); - boost::hash_combine(h, diffuse.z); - boost::hash_combine(h, alpha); - boost::hash_combine(h, specular.x); - boost::hash_combine(h, specular.y); - boost::hash_combine(h, specular.z); - boost::hash_combine(h, glossiness); - boost::hash_combine(h, emissive.x); - boost::hash_combine(h, emissive.y); - boost::hash_combine(h, emissive.z); - for(int i = 0;i < 7;i++) - { - if(!texName[i].empty()) - { - boost::hash_combine(h, texName[i]); - boost::hash_combine(h, texprop->textures[i].clamp); - boost::hash_combine(h, texprop->textures[i].uvSet); - } - } - boost::hash_combine(h, drawMode); - boost::hash_combine(h, vertexColour); - boost::hash_combine(h, alphaFlags); - boost::hash_combine(h, alphaTest); - boost::hash_combine(h, vertMode); - boost::hash_combine(h, depthFlags); - boost::hash_combine(h, specFlags); - boost::hash_combine(h, wireFlags); - - std::map::iterator itr = sMaterialMap.find(h); - if (itr != sMaterialMap.end()) - { - // a suitable material exists already - use it - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(itr->second); - needTangents = !sh::retrieveValue(instance->getProperty("normalMap"), instance).get().empty(); - return itr->second; - } - // not found, create a new one - sMaterialMap.insert(std::make_pair(h, name)); - } - - // No existing material like this. Create a new one. - sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); - if(vertMode == 0 || !vertexColour) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); - } - else if(vertMode == 1) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); - } - else if(vertMode == 2) - { - instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); - } - else - std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); - } - - if(wireFlags) - { - instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); - } - - if (drawMode == 1) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("clockwise"))); - else if (drawMode == 2) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("anticlockwise"))); - else if (drawMode == 3) - instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("none"))); - - instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); - instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); - instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); - instance->setProperty("darkMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DarkTexture])); - if (!texName[Nif::NiTexturingProperty::BaseTexture].empty()) - { - instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "diffuseMap", texprop->textures[Nif::NiTexturingProperty::BaseTexture]); - } - if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) - { - instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "emissiveMap", texprop->textures[Nif::NiTexturingProperty::GlowTexture]); - } - if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) - { - instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "detailMap", texprop->textures[Nif::NiTexturingProperty::DetailTexture]); - } - if (!texName[Nif::NiTexturingProperty::DarkTexture].empty()) - { - instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true))); - setTextureProperties(instance, "darkMap", texprop->textures[Nif::NiTexturingProperty::DarkTexture]); - } - - bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty() - && texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos; - instance->setProperty("use_parallax", sh::makeProperty(new sh::BooleanValue(useParallax))); - - for(int i = 0;i < 7;i++) - { - if(i == Nif::NiTexturingProperty::BaseTexture || - i == Nif::NiTexturingProperty::DetailTexture || - i == Nif::NiTexturingProperty::DarkTexture || - i == Nif::NiTexturingProperty::BumpTexture || - i == Nif::NiTexturingProperty::GlowTexture) - continue; - if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i) + " in " + name); - } - - if (vertexColour) - instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); - - // Override alpha flags based on our override list (transparency-overrides.cfg) - if ((alphaFlags&1) && !texName[0].empty()) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); - if (result.first) - { - alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ - alphaTest = result.second; - depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on - } - } - - // Add transparency if NiAlphaProperty was present - if((alphaFlags&1)) - { - std::string blend_mode; - blend_mode += getBlendFactor((alphaFlags>>1)&0xf); - blend_mode += " "; - blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); - } - - if((alphaFlags>>9)&1) - { -#ifndef ANDROID - std::string reject; - reject += getTestMode((alphaFlags>>10)&0x7); - reject += " "; - reject += Ogre::StringConverter::toString(alphaTest); - instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); -#else - // alpha test not supported in OpenGL ES 2, use manual implementation in shader - instance->setProperty("alphaTestMode", sh::makeProperty(new sh::IntValue((alphaFlags>>10)&0x7))); - instance->setProperty("alphaTestValue", sh::makeProperty(new sh::FloatValue(alphaTest/255.f))); -#endif - } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - - // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( - ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); - - instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); - // depth_func??? - - if (!texName[0].empty()) - NifOverrides::Overrides::getMaterialOverrides(texName[0], instance); - - // Don't use texName, as it may be overridden - needTangents = !sh::retrieveValue(instance->getProperty("normalMap"), instance).get().empty(); - - return name; -} - -std::map NIFMaterialLoader::sMaterialMap; - -} diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp deleted file mode 100644 index 6be52d1a56..0000000000 --- a/components/nifogre/material.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP -#define COMPONENTS_NIFOGRE_MATERIAL_HPP - -#include -#include -#include -#include - -#include - -namespace Nif -{ - class ShapeData; - class NiTexturingProperty; - class NiMaterialProperty; - class NiAlphaProperty; - class NiVertexColorProperty; - class NiZBufferProperty; - class NiSpecularProperty; - class NiWireframeProperty; - class NiStencilProperty; -} - -namespace NifOgre -{ - -class NIFMaterialLoader { - static void warn(const std::string &msg) - { - std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; - } - - static std::map sMaterialMap; - -public: - static Ogre::String getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - const Nif::NiStencilProperty *stencilprop, - bool &needTangents, bool particleMaterial=false); -}; - -} - -#endif diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp deleted file mode 100644 index 85c3a7b65c..0000000000 --- a/components/nifogre/mesh.cpp +++ /dev/null @@ -1,412 +0,0 @@ -#include "mesh.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "material.hpp" - -namespace NifOgre -{ - -// Helper class that computes the bounding box and of a mesh -class BoundsFinder -{ - struct MaxMinFinder - { - float max, min; - - MaxMinFinder() - { - min = std::numeric_limits::infinity(); - max = -min; - } - - void add(float f) - { - if (f > max) max = f; - if (f < min) min = f; - } - - // Return Max(max**2, min**2) - float getMaxSquared() - { - float m1 = max*max; - float m2 = min*min; - if (m1 >= m2) return m1; - return m2; - } - }; - - MaxMinFinder X, Y, Z; - -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for (int i=0;idata.getPtr(); - const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); - std::vector srcVerts = data->vertices; - std::vector srcNorms = data->normals; - Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; - bool vertShadowBuffer = false; - - if(skin != NULL) - { - vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; - vertShadowBuffer = true; - - // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be - // explicitly attached later. - mesh->setSkeletonName(mName); - - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); - std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bones[b]->getWorldTransform() * mat; - - const std::vector &weights = data->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - newVerts.at(index) += (mat*srcVerts[index]) * weight; - if(newNorms.size() > index) - { - Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); - vec4 = mat*vec4 * weight; - newNorms[index] += Ogre::Vector3(&vec4[0]); - } - } - } - - srcVerts = newVerts; - srcNorms = newNorms; - } - else - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(skelMgr->getByName(mName).isNull()) - { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) - { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); - } - } - } - - // Set the bounding box first - BoundsFinder bounds; - bounds.add(&srcVerts[0][0], srcVerts.size()); - if(!bounds.isValid()) - { - float v[3] = { 0.0f, 0.0f, 0.0f }; - bounds.add(&v[0], 1); - } - - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, - bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - - // This function is just one long stream of Ogre-barf, but it works - // great. - Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr vbuf; - Ogre::HardwareIndexBufferSharedPtr ibuf; - Ogre::VertexBufferBinding *bind; - Ogre::VertexDeclaration *decl; - int nextBuf = 0; - - Ogre::SubMesh *sub = mesh->createSubMesh(); - - // Add vertices - sub->useSharedVertices = false; - sub->vertexData = new Ogre::VertexData(); - sub->vertexData->vertexStart = 0; - sub->vertexData->vertexCount = srcVerts.size(); - - decl = sub->vertexData->vertexDeclaration; - bind = sub->vertexData->vertexBufferBinding; - if(srcVerts.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex normals - if(srcNorms.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex colors - const std::vector &colors = data->colors; - if(colors.size()) - { - Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(colors.size()); - for(size_t i = 0;i < colorsRGB.size();i++) - { - Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); - rs->convertColourValue(clr, &colorsRGB[i]); - } - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - bind->setBinding(nextBuf++, vbuf); - } - - // Texture UV coordinates - size_t numUVs = data->uvlist.size(); - if (numUVs) - { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - - for(size_t i = 0; i < numUVs; i++) - decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); - - vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), - Ogre::HardwareBuffer::HBU_STATIC); - - std::vector allUVs; - allUVs.reserve(srcVerts.size()*numUVs); - for (size_t vert = 0; vertuvlist[i][vert]); - - vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - const std::vector &srcIdx = data->triangles; - if(srcIdx.size()) - { - ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC); - ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = srcIdx.size(); - sub->indexData->indexStart = 0; - } - - // Assign bone weights for this TriShape - if(skin != NULL) - { - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) - { - Ogre::VertexBoneAssignment boneInf; - boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); - - const std::vector &weights = data->bones[i].weights; - for(size_t j = 0;j < weights.size();j++) - { - boneInf.vertexIndex = weights[j].vertex; - boneInf.weight = weights[j].weight; - sub->addBoneAssignment(boneInf); - } - } - } - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - bool needTangents = false; - - shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, stencilprop, needTangents); - if(matname.length() > 0) - sub->setMaterialName(matname); - - // build tangents if the material needs them - if (needTangents) - { - unsigned short src,dest; - if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) - mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); - } - - - if(!shape->controller.empty()) - { - Nif::ControllerPtr ctrl = shape->controller; - do { - // Load GeomMorpherController into an Ogre::Pose and Animation - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - const Nif::NiGeomMorpherController *geom = - static_cast(ctrl.getPtr()); - - const std::vector& morphs = geom->data.getPtr()->mMorphs; - // Note we are not interested in morph 0, which just contains the original vertices - for (unsigned int i = 1; i < morphs.size(); ++i) - { - Ogre::Pose* pose = mesh->createPose(i); - const Nif::NiMorphData::MorphData& data = morphs[i]; - for (unsigned int v = 0; v < data.mVertices.size(); ++v) - pose->addVertex(v, data.mVertices[v]); - - Ogre::String animationID = Ogre::StringConverter::toString(ctrl->recIndex) - + "_" + Ogre::StringConverter::toString(i); - Ogre::VertexAnimationTrack* track = - mesh->createAnimation(animationID, 0) - ->createVertexTrack(1, Ogre::VAT_POSE); - Ogre::VertexPoseKeyFrame* keyframe = track->createVertexPoseKeyFrame(0); - keyframe->addPoseReference(i-1, 1); - } - - break; - } - } while(!(ctrl=ctrl->next).empty()); - } -} - - -NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) - : mName(name), mGroup(group), mShapeIndex(idx) -{ -} - -void NIFMeshLoader::loadResource(Ogre::Resource *resource) -{ - Ogre::Mesh *mesh = static_cast(resource); - OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); - - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName); - if(mShapeIndex >= nif->numRecords()) - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(!skelMgr->getByName(mName).isNull()) - mesh->setSkeletonName(mName); - return; - } - - const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, static_cast(record)); -} - - -void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) -{ - NIFMeshLoader::LoaderMap::iterator loader; - loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); - mesh->setAutoBuildEdgeLists(false); -} - -} diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp deleted file mode 100644 index 731e49c903..0000000000 --- a/components/nifogre/mesh.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_MESH_HPP -#define COMPONENTS_NIFOGRE_MESH_HPP - -#include -#include -#include -#include - -#include - -namespace Nif -{ - class NiTriShape; -} - -namespace NifOgre -{ - -/** Manual resource loader for NiTriShapes. This is the main class responsible - * for translating the internal NIF meshes into something Ogre can use. - */ -class NIFMeshLoader : Ogre::ManualResourceLoader -{ - static void warn(const std::string &msg) - { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; - } - - static void fail(const std::string &msg) - { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; - abort(); - } - - std::string mName; - std::string mGroup; - size_t mShapeIndex; - - // Convert NiTriShape to Ogre::SubMesh - void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - - NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); - - virtual void loadResource(Ogre::Resource *resource); - -public: - static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); -}; - -} - -#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp deleted file mode 100644 index 17df7a3cdc..0000000000 --- a/components/nifogre/ogrenifloader.cpp +++ /dev/null @@ -1,1492 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - 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 - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include "ogrenifloader.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "skeleton.hpp" -#include "material.hpp" -#include "mesh.hpp" -#include "controller.hpp" -#include "particles.hpp" - -namespace -{ - - void getAllNiNodes(const Nif::Node* node, std::vector& out) - { - const Nif::NiNode* ninode = dynamic_cast(node); - if (ninode) - { - out.push_back(ninode); - for (unsigned int i=0; ichildren.length(); ++i) - if (!ninode->children[i].empty()) - getAllNiNodes(ninode->children[i].getPtr(), out); - } - } - -} - -namespace NifOgre -{ - -Ogre::MaterialPtr MaterialControllerManager::getWritableMaterial(Ogre::MovableObject *movable) -{ - if (mClonedMaterials.find(movable) != mClonedMaterials.end()) - return mClonedMaterials[movable]; - - else - { - Ogre::MaterialPtr mat; - if (Ogre::Entity* ent = dynamic_cast(movable)) - mat = ent->getSubEntity(0)->getMaterial(); - else if (Ogre::ParticleSystem* partSys = dynamic_cast(movable)) - mat = Ogre::MaterialManager::getSingleton().getByName(partSys->getMaterialName()); - - static int count=0; - Ogre::String newName = mat->getName() + Ogre::StringConverter::toString(count++); - sh::Factory::getInstance().createMaterialInstance(newName, mat->getName()); - // Make sure techniques are created - sh::Factory::getInstance()._ensureMaterial(newName, "Default"); - mat = Ogre::MaterialManager::getSingleton().getByName(newName); - - mClonedMaterials[movable] = mat; - - if (Ogre::Entity* ent = dynamic_cast(movable)) - ent->getSubEntity(0)->setMaterial(mat); - else if (Ogre::ParticleSystem* partSys = dynamic_cast(movable)) - partSys->setMaterialName(mat->getName()); - - return mat; - } -} - -MaterialControllerManager::~MaterialControllerManager() -{ - for (std::map::iterator it = mClonedMaterials.begin(); it != mClonedMaterials.end(); ++it) - { - sh::Factory::getInstance().destroyMaterialInstance(it->second->getName()); - } -} - -ObjectScene::~ObjectScene() -{ - for(size_t i = 0;i < mLights.size();i++) - { - Ogre::Light *light = mLights[i]; - // If parent is a scene node, it was created specifically for this light. Destroy it now. - if(light->isAttached() && !light->isParentTagPoint()) - mSceneMgr->destroySceneNode(light->getParentSceneNode()); - mSceneMgr->destroyLight(light); - } - for(size_t i = 0;i < mParticles.size();i++) - mSceneMgr->destroyParticleSystem(mParticles[i]); - for(size_t i = 0;i < mEntities.size();i++) - mSceneMgr->destroyEntity(mEntities[i]); - mControllers.clear(); - mLights.clear(); - mParticles.clear(); - mEntities.clear(); - mSkelBase = NULL; -} - -void ObjectScene::setVisibilityFlags (unsigned int flags) -{ - for (std::vector::iterator iter (mEntities.begin()); iter!=mEntities.end(); - ++iter) - (*iter)->setVisibilityFlags (flags); - - for (std::vector::iterator iter (mParticles.begin()); - iter!=mParticles.end(); ++iter) - (*iter)->setVisibilityFlags (flags); - - for (std::vector::iterator iter (mLights.begin()); iter!=mLights.end(); - ++iter) - (*iter)->setVisibilityFlags (flags); -} - -void ObjectScene::rotateBillboardNodes(Ogre::Camera *camera) -{ - for (std::vector::iterator it = mBillboardNodes.begin(); it != mBillboardNodes.end(); ++it) - { - assert(mSkelBase); - Ogre::Node* node = *it; - node->_setDerivedOrientation(mSkelBase->getParentNode()->_getDerivedOrientation().Inverse() * - camera->getRealOrientation()); - } -} - -void ObjectScene::_notifyAttached() -{ - // convert initial particle positions to world space for world-space particle systems - // this can't be done on creation because the particle system is not in its correct world space position yet - for (std::vector::iterator it = mParticles.begin(); it != mParticles.end(); ++it) - { - Ogre::ParticleSystem* psys = *it; - if (psys->getKeepParticlesInLocalSpace()) - continue; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = p->mPosition; - Ogre::Vector3& direction = p->mDirection; -#else - Ogre::Vector3& position = p->position; - Ogre::Vector3& direction = p->direction; -#endif - - position = - (psys->getParentNode()->_getDerivedOrientation() * - (psys->getParentNode()->_getDerivedScale() * position)) - + psys->getParentNode()->_getDerivedPosition(); - direction = - (psys->getParentNode()->_getDerivedOrientation() * direction); - } - } -} - -// Animates a texture -class FlipController -{ -public: - class Value : public Ogre::ControllerValue - { - private: - Ogre::MovableObject* mMovable; - int mTexSlot; - float mDelta; - std::vector mTextures; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiFlipController *ctrl, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mMaterialControllerMgr(materialControllerMgr) - { - mTexSlot = ctrl->mTexSlot; - mDelta = ctrl->mDelta; - for (unsigned int i=0; imSources.length(); ++i) - { - const Nif::NiSourceTexture* tex = ctrl->mSources[i].getPtr(); - if (!tex->external) - std::cerr << "Warning: Found internal texture, ignoring." << std::endl; - mTextures.push_back(Misc::ResourceHelpers::correctTexturePath(tex->filename)); - } - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if (mDelta == 0) - return; - int curTexture = int(time / mDelta) % mTextures.size(); - - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::Pass::TextureUnitStateIterator textures = pass->getTextureUnitStateIterator(); - while (textures.hasMoreElements()) - { - Ogre::TextureUnitState *texture = textures.getNext(); - if ((texture->getName() == "diffuseMap" && mTexSlot == Nif::NiTexturingProperty::BaseTexture) - || (texture->getName() == "normalMap" && mTexSlot == Nif::NiTexturingProperty::BumpTexture) - || (texture->getName() == "detailMap" && mTexSlot == Nif::NiTexturingProperty::DetailTexture) - || (texture->getName() == "darkMap" && mTexSlot == Nif::NiTexturingProperty::DarkTexture) - || (texture->getName() == "emissiveMap" && mTexSlot == Nif::NiTexturingProperty::GlowTexture)) - texture->setTextureName(mTextures[curTexture]); - } - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class AlphaController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::FloatKeyMap mData; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiFloatData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mData(data->mKeyList) - , mMaterialControllerMgr(materialControllerMgr) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - float value = interpKey(mData.mKeys, time); - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = value; - pass->setDiffuse(diffuse); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class MaterialColorController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::Vector3KeyMap mData; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject *movable, const Nif::NiPosData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mData(data->mKeyList) - , mMaterialControllerMgr(materialControllerMgr) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - Ogre::Vector3 value = interpKey(mData.mKeys, time); - Ogre::MaterialPtr mat = mMaterialControllerMgr->getWritableMaterial(mMovable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.r = value.x; - diffuse.g = value.y; - diffuse.b = value.z; - pass->setDiffuse(diffuse); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class VisController -{ -public: - class Value : public NodeTargetValue - { - private: - std::vector mData; - - bool calculate(Ogre::Real time) const - { - if(mData.size() == 0) - return true; - - for(size_t i = 1;i < mData.size();i++) - { - if(mData[i].time > time) - return mData[i-1].isSet; - } - return mData.back().isSet; - } - - static void setVisible(Ogre::Node *node, int vis) - { - // Skinned meshes are attached to the scene node, not the bone. - // We use the Node's user data to connect it with the mesh. - Ogre::Any customData = node->getUserObjectBindings().getUserAny(); - - if (!customData.isEmpty()) - Ogre::any_cast(customData)->setVisible(vis); - - Ogre::TagPoint *tag = dynamic_cast(node); - if(tag != NULL) - { - Ogre::MovableObject *obj = tag->getChildObject(); - if(obj != NULL) - obj->setVisible(vis); - } - - Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); - while(iter.hasMoreElements()) - { - node = iter.getNext(); - setVisible(node, vis); - } - } - - public: - Value(Ogre::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } - - virtual Ogre::Quaternion getRotation(float time) const - { return Ogre::Quaternion(); } - - virtual Ogre::Vector3 getTranslation(float time) const - { return Ogre::Vector3(0.0f); } - - virtual Ogre::Vector3 getScale(float time) const - { return Ogre::Vector3(1.0f); } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - bool vis = calculate(time); - setVisible(mNode, vis); - } - }; - - typedef DefaultFunction Function; -}; - -class KeyframeController -{ -public: - class Value : public NodeTargetValue, public ValueInterpolator - { - private: - const Nif::QuaternionKeyMap* mRotations; - const Nif::FloatKeyMap* mXRotations; - const Nif::FloatKeyMap* mYRotations; - const Nif::FloatKeyMap* mZRotations; - const Nif::Vector3KeyMap* mTranslations; - const Nif::FloatKeyMap* mScales; - Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid - - using ValueInterpolator::interpKey; - - static Ogre::Quaternion interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) - { - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::QuaternionKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::QuaternionKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::QuaternionKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - return Ogre::Quaternion::nlerp(a, aLastKey->mValue, aKey->mValue); - } - else - return keys.rbegin()->second.mValue; - } - - Ogre::Quaternion getXYZRotation(float time) const - { - float xrot = interpKey(mXRotations->mKeys, time); - float yrot = interpKey(mYRotations->mKeys, time); - float zrot = interpKey(mZRotations->mKeys, time); - Ogre::Quaternion xr(Ogre::Radian(xrot), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(yrot), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(zrot), Ogre::Vector3::UNIT_Z); - return (zr*yr*xr); - } - - public: - /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - Value(Ogre::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data) - : NodeTargetValue(target) - , mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) - { } - - virtual Ogre::Quaternion getRotation(float time) const - { - if(mRotations->mKeys.size() > 0) - return interpKey(mRotations->mKeys, time); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - return getXYZRotation(time); - return mNode->getOrientation(); - } - - virtual Ogre::Vector3 getTranslation(float time) const - { - if(mTranslations->mKeys.size() > 0) - return interpKey(mTranslations->mKeys, time); - return mNode->getPosition(); - } - - virtual Ogre::Vector3 getScale(float time) const - { - if(mScales->mKeys.size() > 0) - return Ogre::Vector3(interpKey(mScales->mKeys, time)); - return mNode->getScale(); - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if(mRotations->mKeys.size() > 0) - mNode->setOrientation(interpKey(mRotations->mKeys, time)); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - mNode->setOrientation(getXYZRotation(time)); - if(mTranslations->mKeys.size() > 0) - mNode->setPosition(interpKey(mTranslations->mKeys, time)); - if(mScales->mKeys.size() > 0) - mNode->setScale(Ogre::Vector3(interpKey(mScales->mKeys, time))); - } - }; - - typedef DefaultFunction Function; -}; - -class UVController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::MovableObject* mMovable; - Nif::FloatKeyMap mUTrans; - Nif::FloatKeyMap mVTrans; - Nif::FloatKeyMap mUScale; - Nif::FloatKeyMap mVScale; - MaterialControllerManager* mMaterialControllerMgr; - - public: - Value(Ogre::MovableObject* movable, const Nif::NiUVData *data, MaterialControllerManager* materialControllerMgr) - : mMovable(movable) - , mUTrans(data->mKeyList[0]) - , mVTrans(data->mKeyList[1]) - , mUScale(data->mKeyList[2]) - , mVScale(data->mKeyList[3]) - , mMaterialControllerMgr(materialControllerMgr) - { } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 1.0f; - } - - virtual void setValue(Ogre::Real value) - { - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); - - Ogre::MaterialPtr material = mMaterialControllerMgr->getWritableMaterial(mMovable); - - Ogre::Material::TechniqueIterator techs = material->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); - tex->setTextureScroll(uTrans, vTrans); - tex->setTextureScale(uScale, vScale); - } - } - } - }; - - typedef DefaultFunction Function; -}; - -class ParticleSystemController -{ -public: - class Value : public Ogre::ControllerValue - { - private: - Ogre::ParticleSystem *mParticleSys; - float mEmitStart; - float mEmitStop; - - public: - Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) - : mParticleSys(psys) - , mEmitStart(pctrl->startTime) - , mEmitStop(pctrl->stopTime) - { - } - - Ogre::Real getValue() const - { return 0.0f; } - - void setValue(Ogre::Real value) - { - mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); - } - }; - - typedef DefaultFunction Function; -}; - -class GeomMorpherController -{ -public: - class Value : public Ogre::ControllerValue, public ValueInterpolator - { - private: - Ogre::Entity *mEntity; - std::vector mMorphs; - size_t mControllerIndex; - - std::vector mVertices; - - public: - Value(Ogre::Entity *ent, const Nif::NiMorphData *data, size_t controllerIndex) - : mEntity(ent) - , mMorphs(data->mMorphs) - , mControllerIndex(controllerIndex) - { - } - - virtual Ogre::Real getValue() const - { - // Should not be called - return 0.0f; - } - - virtual void setValue(Ogre::Real time) - { - if (mMorphs.size() <= 1) - return; - int i = 1; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) - { - float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, time); - val = std::max(0.f, std::min(1.f, val)); - - Ogre::String animationID = Ogre::StringConverter::toString(mControllerIndex) - + "_" + Ogre::StringConverter::toString(i); - - Ogre::AnimationState* state = mEntity->getAnimationState(animationID); - state->setEnabled(val > 0); - state->setWeight(val); - } - } - }; - - typedef DefaultFunction Function; -}; - - -/** Object creator for NIFs. This is the main class responsible for creating - * "live" Ogre objects (entities, particle systems, controllers, etc) from - * their NIF equivalents. - */ -class NIFObjectLoader -{ - static bool sShowMarkers; -public: - static void setShowMarkers(bool show) - { - sShowMarkers = show; - } -private: - - static void warn(const std::string &msg) - { - std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; - } - - static void createEntity(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, ObjectScenePtr scene, - const Nif::Node *node, int flags, int animflags) - { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - // Enable skeleton-based bounding boxes. With the static bounding box, - // the animation may cause parts to go outside the box and cause culling problems. - if (entity->hasSkeleton()) - entity->setUpdateBoundingBoxFromSkeleton(true); -#endif - - entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); - - scene->mEntities.push_back(entity); - if(scene->mSkelBase) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - trgtbone->getUserObjectBindings().setUserAny(Ogre::Any(static_cast(entity))); - - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(scene->mSkelBase); - else - scene->mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(entity, uv->data.getPtr(), &scene->mMaterialControllerMgr)); - - UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiGeomMorpherController) - { - const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value( - entity, geom->data.getPtr(), geom->recIndex)); - - GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - - createMaterialControllers(shape, entity, animflags, scene); - } - - static void createMaterialControllers (const Nif::Node* node, Ogre::MovableObject* movable, int animflags, ObjectScenePtr scene) - { - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - - if(matprop) - { - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType == Nif::RC_NiAlphaController) - { - const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if (ctrls->recType == Nif::RC_NiMaterialColorController) - { - const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - - ctrls = ctrls->next; - } - } - if (texprop) - { - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - if (ctrls->recType == Nif::RC_NiFlipController) - { - const Nif::NiFlipController *flipCtrl = static_cast(ctrls.getPtr()); - - - Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( - movable, flipCtrl, &scene->mMaterialControllerMgr)); - FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - - ctrls = ctrls->next; - } - } - } - - static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, - const Nif::NiParticleSystemController *partctrl, Ogre::Bone* bone, - const std::string& skelBaseName) - { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, - partctrl->velocity + partctrl->velocityRandom*0.5f); - - if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) - emitter->setEmissionRate(partctrl->emitRate); - else - emitter->setEmissionRate(partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom/2)); - - emitter->setTimeToLive(std::max(0.f, partctrl->lifetime), - std::max(0.f, partctrl->lifetime + partctrl->lifetimeRandom)); - emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); - emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); - emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); - emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees())); - emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees())); - emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees())); - emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees())); - - Nif::ExtraPtr e = partctrl->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiParticleGrowFade) - { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - - Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); - affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); - affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); - } - else if(e->recType == Nif::RC_NiGravity) - { - const Nif::NiGravity *gr = static_cast(e.getPtr()); - - Ogre::ParticleAffector *affector = partsys->addAffector("Gravity"); - affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce)); - affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point"); - affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); - affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); - affector->setParameter("skelbase", skelBaseName); - affector->setParameter("bone", bone->getName()); - } - else if(e->recType == Nif::RC_NiParticleColorModifier) - { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); - const Nif::NiColorData *clrdata = cl->data.getPtr(); - - Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); - size_t num_colors = std::min(6, clrdata->mKeyMap.mKeys.size()); - unsigned int i=0; - for (Nif::Vector4KeyMap::MapType::const_iterator it = clrdata->mKeyMap.mKeys.begin(); it != clrdata->mKeyMap.mKeys.end() && i < num_colors; ++it,++i) - { - Ogre::ColourValue color; - color.r = it->second.mValue[0]; - color.g = it->second.mValue[1]; - color.b = it->second.mValue[2]; - color.a = it->second.mValue[3]; - affector->setParameter("colour"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(color)); - affector->setParameter("time"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(it->first)); - } - } - else if(e->recType == Nif::RC_NiParticleRotation) - { - // TODO: Implement (Ogre::RotationAffector?) - } - else - warn("Unhandled particle modifier "+e->recName); - e = e->extra; - } - } - - static void createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneNode *sceneNode, ObjectScenePtr scene, - const Nif::Node *partnode, int flags, int partflags, int animflags) - { - const Nif::NiAutoNormalParticlesData *particledata = NULL; - if(partnode->recType == Nif::RC_NiAutoNormalParticles) - particledata = static_cast(partnode)->data.getPtr(); - else if(partnode->recType == Nif::RC_NiRotatingParticles) - particledata = static_cast(partnode)->data.getPtr(); - else - throw std::runtime_error("Unexpected particle node type"); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - - Ogre::ParticleSystem *partsys = sceneNode->getCreator()->createParticleSystem(); - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - const Nif::NiStencilProperty *stencilprop = NULL; - bool needTangents = false; - - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, stencilprop, needTangents, - // MW doesn't light particles, but the MaterialProperty - // used still has lighting, so that must be ignored. - true)); - - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace)); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - scene->mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); - - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) - { - if((ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - float size = partctrl->size*2; - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - size = std::max(size, 0.00001f); - partsys->setDefaultDimensions(size, size); - - if(!partctrl->emitter.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - // Set the emitter bone(s) as user data on the particle system - // so the emitters/affectors can access it easily. - std::vector bones; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - std::vector nodes; - getAllNiNodes(partctrl->emitter.getPtr(), nodes); - if (nodes.empty()) - throw std::runtime_error("Emitter for NiBSPArrayController must be a NiNode"); - for (unsigned int i=0; imSkelBase->getSkeleton()->getBone( - NIFSkeletonLoader::lookupOgreBoneHandle(name, nodes[i]->recIndex))); - } - } - else - { - bones.push_back(trgtbone); - } - NiNodeHolder holder; - holder.mBones = bones; - partsys->getUserObjectBindings().setUserAny(Ogre::Any(holder)); - createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName()); - } - - createParticleInitialState(partsys, particledata, partctrl); - - Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - - ParticleSystemController::Function* function = - OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - - // Emitting state will be overwritten on frame update by the ParticleSystemController, - // but set up an initial value anyway so the user can fast-forward particle systems - // immediately after creation if desired. - partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay); - } - ctrl = ctrl->next; - } - - partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); - scene->mParticles.push_back(partsys); - - createMaterialControllers(partnode, partsys, animflags, scene); - } - - static void createParticleInitialState(Ogre::ParticleSystem* partsys, const Nif::NiAutoNormalParticlesData* particledata, - const Nif::NiParticleSystemController* partctrl) - { - partsys->_update(0.f); // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better - int i=0; - for (std::vector::const_iterator it = partctrl->particles.begin(); - iactiveCount && it != partctrl->particles.end(); ++it, ++i) - { - const Nif::NiParticleSystemController::Particle& particle = *it; - - Ogre::Particle* created = partsys->createParticle(); - if (!created) - break; - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = created->mPosition; - Ogre::Vector3& direction = created->mDirection; - Ogre::ColourValue& colour = created->mColour; - float& totalTimeToLive = created->mTotalTimeToLive; - float& timeToLive = created->mTimeToLive; -#else - Ogre::Vector3& position = created->position; - Ogre::Vector3& direction = created->direction; - Ogre::ColourValue& colour = created->colour; - float& totalTimeToLive = created->totalTimeToLive; - float& timeToLive = created->timeToLive; -#endif - - direction = particle.velocity; - position = particledata->vertices.at(particle.vertex); - - if (particle.vertex < int(particledata->colors.size())) - { - Ogre::Vector4 partcolour = particledata->colors.at(particle.vertex); - colour = Ogre::ColourValue(partcolour.x, partcolour.y, partcolour.z, partcolour.w); - } - else - colour = Ogre::ColourValue(1.f, 1.f, 1.f, 1.f); - float size = particledata->sizes.at(particle.vertex); - created->setDimensions(size, size); - totalTimeToLive = std::max(0.f, particle.lifespan); - timeToLive = std::max(0.f, particle.lifespan - particle.lifetime); - } - partsys->_update(0.f); // now apparently needs another update, otherwise it won't render in the first frame. TODO: patch Ogre to handle this better - } - - static void createNodeControllers(const Nif::NIFFilePtr& nif, const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags) - { - do { - if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - - VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - // The keyframe controller will control this bone manually - trgtbone->setManuallyControlled(true); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); - scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - Ogre::ControllerFunctionRealPtr func(function); - - scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - } - ctrl = ctrl->next; - } while(!ctrl.empty()); - } - - - static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) - { - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - if(nextpos != std::string::npos) - { - do { - nextpos--; - } while(nextpos > pos && ::isspace(str[nextpos])); - nextpos++; - } - else if(::isspace(*str.rbegin())) - { - std::string::const_iterator last = str.end(); - do { - --last; - } while(last != str.begin() && ::isspace(*last)); - nextpos = std::distance(str.begin(), ++last); - } - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - } - - - static void createObjects(const Nif::NIFFilePtr& nif, const std::string &name, const std::string &group, - Ogre::SceneNode *sceneNode, const Nif::Node *node, - ObjectScenePtr scene, int flags, int animflags, int partflags, bool isRootCollisionNode=false) - { - // Do not create objects for the collision shape (includes all children) - if(node->recType == Nif::RC_RootCollisionNode) - isRootCollisionNode = true; - - if(node->recType == Nif::RC_NiBSAnimationNode) - animflags |= node->flags; - else if(node->recType == Nif::RC_NiBSParticleNode) - partflags |= node->flags; - else - flags |= node->flags; - - if (node->recType == Nif::RC_NiBillboardNode) - { - // TODO: figure out what the flags mean. - // NifSkope has names for them, but doesn't implement them. - // Change mBillboardNodes to map - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - Ogre::Bone* bone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - bone->setManuallyControlled(true); - scene->mBillboardNodes.push_back(bone); - } - - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - - extractTextKeys(tk, scene->mTextKeys); - } - else if(e->recType == Nif::RC_NiStringExtraData) - { - const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); - // String markers may contain important information - // affecting the entire subtree of this obj - if(sd->string == "MRK" && !sShowMarkers) - { - // Marker objects. These meshes are only visible in the - // editor. - flags |= 0x80000000; - } - } - - e = e->extra; - } - - if(!node->controller.empty()) - createNodeControllers(nif, name, node->controller, scene, animflags); - - if (!isRootCollisionNode) - { - if(node->recType == Nif::RC_NiCamera) - { - /* Ignored */ - } - - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) - { - createEntity(name, group, sceneNode->getCreator(), scene, node, flags, animflags); - } - - if((node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) - { - createParticleSystem(name, group, sceneNode, scene, node, flags, partflags, animflags); - } - } - - 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()) - createObjects(nif, name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags, isRootCollisionNode); - } - } - } - - static void createSkelBase(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectScenePtr scene) - { - /* This creates an empty mesh to which a skeleton gets attached. This - * is to ensure we have an entity with a skeleton instance, even if all - * other entities are attached to bones and not skinned. */ - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(name).isNull()) - NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); - - scene->mSkelBase = sceneMgr->createEntity(name); - scene->mEntities.push_back(scene->mSkelBase); - } - -public: - static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0) - { - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node *node = dynamic_cast(r); - if(node == NULL) - { - nif->warn("First root in "+name+" was not a node, but a "+ - r->recName+"."); - return; - } - - if(Ogre::SkeletonManager::getSingleton().resourceExists(name) || - !NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) - { - // Create a base skeleton entity if this NIF needs one - createSkelBase(name, group, sceneNode->getCreator(), node, scene); - } - createObjects(nif, name, group, sceneNode, node, scene, flags, 0, 0); - } - - static void loadKf(Ogre::Skeleton *skel, const std::string &name, - TextKeyMap &textKeys, std::vector > &ctrls) - { - Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return; - } - - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - if(r->recType != Nif::RC_NiSequenceStreamHelper) - { - nif->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; - } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) - { - nif->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) - { - nif->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; - } - - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - - if(key->data.empty()) - continue; - if(!skel->hasBone(strdata->string)) - continue; - - Ogre::Bone *trgtbone = skel->getBone(strdata->string); - Ogre::ControllerValueRealPtr srcval; - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - - ctrls.push_back(Ogre::Controller(srcval, dstval, func)); - } - } -}; - - -ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group); - - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(!entity->isAttached()) - parentNode->attachObject(entity); - } - - scene->_notifyAttached(); - - return scene; -} - -ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, - const std::string& bonefilter, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group); - - bool isskinned = false; - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *ent = scene->mEntities[i]; - if(scene->mSkelBase != ent && ent->hasSkeleton()) - { - isskinned = true; - break; - } - } - - Ogre::Vector3 scale(1.0f); - if(bonename.find("Left") != std::string::npos) - scale.x *= -1.0f; - - if(isskinned) - { - // accepts anything named "filter*" or "tri filter*" - std::string filter = "@shape=tri "+bonefilter; - std::string filter2 = "@shape="+bonefilter; - Misc::StringUtils::toLower(filter); - Misc::StringUtils::toLower(filter2); - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(entity->hasSkeleton()) - { - if(entity == scene->mSkelBase || - entity->getMesh()->getName().find(filter) != std::string::npos - || entity->getMesh()->getName().find(filter2) != std::string::npos) - parentNode->attachObject(entity); - } - else - { - if(entity->getMesh()->getName().find(filter) == std::string::npos - || entity->getMesh()->getName().find(filter2) == std::string::npos) - entity->detachFromParent(); - } - } - } - else - { - for(size_t i = 0;i < scene->mEntities.size();i++) - { - Ogre::Entity *entity = scene->mEntities[i]; - if(!entity->isAttached()) - { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); - tag->setScale(scale); - } - } - } - - scene->_notifyAttached(); - - return scene; -} - - -ObjectScenePtr Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) -{ - ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator())); - - Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode, scene, name, group, 0xC0000000); - - if(scene->mSkelBase) - parentNode->attachObject(scene->mSkelBase); - - return scene; -} - - -void Loader::createKfControllers(Ogre::Entity *skelBase, - const std::string &name, - TextKeyMap &textKeys, - std::vector > &ctrls) -{ - NIFObjectLoader::loadKf(skelBase->getSkeleton(), name, textKeys, ctrls); -} - -bool Loader::sShowMarkers = false; -bool NIFObjectLoader::sShowMarkers = false; - -void Loader::setShowMarkers(bool show) -{ - sShowMarkers = show; - NIFObjectLoader::setShowMarkers(show); -} - - -} // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp deleted file mode 100644 index c135326448..0000000000 --- a/components/nifogre/ogrenifloader.hpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - 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 - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#ifndef OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP -#define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP - -#include -#include -#include - -#include -#include -#include - - -// FIXME: This namespace really doesn't do anything Nif-specific. Any supportable -// model format should go through this. -namespace NifOgre -{ - -/** - * @brief Clones materials as necessary to not make controllers affect other objects (that share the original material). - */ -class MaterialControllerManager -{ -public: - ~MaterialControllerManager(); - - /// @attention if \a movable is an Entity, it needs to have *one* SubEntity - Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable); - -private: - std::map mClonedMaterials; -}; - -typedef std::multimap TextKeyMap; -static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; -struct ObjectScene { - Ogre::Entity *mSkelBase; - std::vector mEntities; - std::vector mParticles; - std::vector mLights; - - // Nodes that should always face the camera when rendering - std::vector mBillboardNodes; - - Ogre::SceneManager* mSceneMgr; - - // The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length. - float mMaxControllerLength; - - TextKeyMap mTextKeys; - - MaterialControllerManager mMaterialControllerMgr; - - std::vector > mControllers; - - ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mMaxControllerLength(0), mSceneMgr(sceneMgr) - { } - - ~ObjectScene(); - - // Rotate nodes in mBillboardNodes so they face the given camera - void rotateBillboardNodes(Ogre::Camera* camera); - - void setVisibilityFlags (unsigned int flags); - - // This is called internally by the OgreNifLoader once all elements of the - // scene have been attached to their respective nodes. - void _notifyAttached(); -}; - -typedef Ogre::SharedPtr ObjectScenePtr; - - -class Loader -{ -public: - static ObjectScenePtr createObjects(Ogre::Entity *parent, const std::string &bonename, - const std::string& filter, - Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - static ObjectScenePtr createObjects(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - static ObjectScenePtr createObjectBase(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); - - /// Set whether or not nodes marked as "MRK" should be shown. - /// These should be hidden ingame, but visible in the editior. - /// Default: false. - static void setShowMarkers(bool show); - - static void createKfControllers(Ogre::Entity *skelBase, - const std::string &name, - TextKeyMap &textKeys, - std::vector > &ctrls); - -private: - static bool sShowMarkers; -}; - -// FIXME: Should be with other general Ogre extensions. -template -class NodeTargetValue : public Ogre::ControllerValue -{ -protected: - Ogre::Node *mNode; - -public: - NodeTargetValue(Ogre::Node *target) : mNode(target) - { } - - virtual Ogre::Quaternion getRotation(T value) const = 0; - virtual Ogre::Vector3 getTranslation(T value) const = 0; - virtual Ogre::Vector3 getScale(T value) const = 0; - - void setNode(Ogre::Node *target) - { mNode = target; } - Ogre::Node *getNode() const - { return mNode; } -}; -typedef Ogre::SharedPtr > NodeTargetValueRealPtr; - -} - -#endif diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp deleted file mode 100644 index 4fec2d29eb..0000000000 --- a/components/nifogre/particles.cpp +++ /dev/null @@ -1,773 +0,0 @@ -#include "particles.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FIXME: "Nif" isn't really an appropriate emitter name. */ -class NifEmitter : public Ogre::ParticleEmitter -{ -public: - std::vector mEmitterBones; - Ogre::Bone* mParticleBone; - - Ogre::ParticleSystem* getPartSys() { return mParent; } - - /** Command object for the emitter width (see Ogre::ParamCommand).*/ - class CmdWidth : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getWidth()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter height (see Ogre::ParamCommand).*/ - class CmdHeight : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getHeight()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter depth (see Ogre::ParamCommand).*/ - class CmdDepth : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - return Ogre::StringConverter::toString(static_cast(target)->getDepth()); - } - void doSet(void *target, const Ogre::String &val) - { - static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ - class CmdVerticalDir : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ - class CmdVerticalAngle : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ - class CmdHorizontalDir : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ - class CmdHorizontalAngle : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const NifEmitter *self = static_cast(target); - return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); - } - void doSet(void *target, const Ogre::String &val) - { - NifEmitter *self = static_cast(target); - self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); - } - }; - - - NifEmitter(Ogre::ParticleSystem *psys) - : Ogre::ParticleEmitter(psys) - , mEmitterBones(Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones) - { - assert (!mEmitterBones.empty()); - Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); - mParticleBone = static_cast(tag->getParent()); - initDefaults("Nif"); - } - - /** See Ogre::ParticleEmitter. */ - unsigned short _getEmissionCount(Ogre::Real timeElapsed) - { - // Use basic constant emission - return genConstantEmissionCount(timeElapsed); - } - - /** See Ogre::ParticleEmitter. */ - void _initParticle(Ogre::Particle *particle) - { - Ogre::Vector3 xOff, yOff, zOff; - - // Call superclass - ParticleEmitter::_initParticle(particle); - - xOff = Ogre::Math::SymmetricRandom() * mXRange; - yOff = Ogre::Math::SymmetricRandom() * mYRange; - zOff = Ogre::Math::SymmetricRandom() * mZRange; - -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = particle->mPosition; - Ogre::Vector3& direction = particle->mDirection; - Ogre::ColourValue& colour = particle->mColour; - Ogre::Real& totalTimeToLive = particle->mTotalTimeToLive; - Ogre::Real& timeToLive = particle->mTimeToLive; -#else - Ogre::Vector3& position = particle->position; - Ogre::Vector3& direction = particle->direction; - Ogre::ColourValue& colour = particle->colour; - Ogre::Real& totalTimeToLive = particle->totalTimeToLive; - Ogre::Real& timeToLive = particle->timeToLive; -#endif - - Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); - - position = xOff + yOff + zOff + - mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() - - mParticleBone->_getDerivedPosition()); - - // Generate complex data by reference - genEmissionColour(colour); - - // NOTE: We do not use mDirection/mAngle for the initial direction. - Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); - Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); - direction = (mParticleBone->_getDerivedOrientation().Inverse() - * emitterBone->_getDerivedOrientation() * - Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * - Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * - Ogre::Vector3::UNIT_Z; - - genEmissionVelocity(direction); - - // Generate simpler data - timeToLive = totalTimeToLive = genEmissionTTL(); - } - - /** Overloaded to update the trans. matrix */ - void setDirection(const Ogre::Vector3 &dir) - { - ParticleEmitter::setDirection(dir); - genAreaAxes(); - } - - /** Sets the size of the area from which particles are emitted. - @param - size Vector describing the size of the area. The area extends - around the center point by half the x, y and z components of - this vector. The box is aligned such that it's local Z axis points - along it's direction (see setDirection) - */ - void setSize(const Ogre::Vector3 &size) - { - mSize = size; - genAreaAxes(); - } - - /** Sets the size of the area from which particles are emitted. - @param x,y,z - Individual axis lengths describing the size of the area. The area - extends around the center point by half the x, y and z components - of this vector. The box is aligned such that it's local Z axis - points along it's direction (see setDirection) - */ - void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) - { - mSize.x = x; - mSize.y = y; - mSize.z = z; - genAreaAxes(); - } - - /** Sets the width (local x size) of the emitter. */ - void setWidth(Ogre::Real width) - { - mSize.x = width; - genAreaAxes(); - } - /** Gets the width (local x size) of the emitter. */ - Ogre::Real getWidth(void) const - { return mSize.x; } - /** Sets the height (local y size) of the emitter. */ - void setHeight(Ogre::Real height) - { - mSize.y = height; - genAreaAxes(); - } - /** Gets the height (local y size) of the emitter. */ - Ogre::Real getHeight(void) const - { return mSize.y; } - /** Sets the depth (local y size) of the emitter. */ - void setDepth(Ogre::Real depth) - { - mSize.z = depth; - genAreaAxes(); - } - /** Gets the depth (local y size) of the emitter. */ - Ogre::Real getDepth(void) const - { return mSize.z; } - - void setVerticalDirection(Ogre::Radian vdir) - { mVerticalDir = vdir; } - Ogre::Radian getVerticalDirection(void) const - { return mVerticalDir; } - - void setVerticalAngle(Ogre::Radian vangle) - { mVerticalAngle = vangle; } - Ogre::Radian getVerticalAngle(void) const - { return mVerticalAngle; } - - void setHorizontalDirection(Ogre::Radian hdir) - { mHorizontalDir = hdir; } - Ogre::Radian getHorizontalDirection(void) const - { return mHorizontalDir; } - - void setHorizontalAngle(Ogre::Radian hangle) - { mHorizontalAngle = hangle; } - Ogre::Radian getHorizontalAngle(void) const - { return mHorizontalAngle; } - - -protected: - /// Size of the area - Ogre::Vector3 mSize; - - Ogre::Radian mVerticalDir; - Ogre::Radian mVerticalAngle; - Ogre::Radian mHorizontalDir; - Ogre::Radian mHorizontalAngle; - - /// Local axes, not normalised, their magnitude reflects area size - Ogre::Vector3 mXRange, mYRange, mZRange; - - /// Internal method for generating the area axes - void genAreaAxes(void) - { - Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); - mXRange = mLeft * (mSize.x * 0.5f); - mYRange = mUp * (mSize.y * 0.5f); - mZRange = mDirection * (mSize.z * 0.5f); - } - - /** Internal for initializing some defaults and parameters - @return True if custom parameters need initialising - */ - bool initDefaults(const Ogre::String &t) - { - // Defaults - mDirection = Ogre::Vector3::UNIT_Z; - mUp = Ogre::Vector3::UNIT_Y; - setSize(100.0f, 100.0f, 100.0f); - mType = t; - - // Set up parameters - if(createParamDictionary(mType + "Emitter")) - { - addBaseParameters(); - Ogre::ParamDictionary *dict = getParamDictionary(); - - // Custom params - dict->addParameter(Ogre::ParameterDef("width", - "Width of the shape in world coordinates.", - Ogre::PT_REAL), - &msWidthCmd); - dict->addParameter(Ogre::ParameterDef("height", - "Height of the shape in world coordinates.", - Ogre::PT_REAL), - &msHeightCmd); - dict->addParameter(Ogre::ParameterDef("depth", - "Depth of the shape in world coordinates.", - Ogre::PT_REAL), - &msDepthCmd); - - dict->addParameter(Ogre::ParameterDef("vertical_direction", - "Vertical direction of emitted particles (in degrees).", - Ogre::PT_REAL), - &msVerticalDirCmd); - dict->addParameter(Ogre::ParameterDef("vertical_angle", - "Vertical direction variance of emitted particles (in degrees).", - Ogre::PT_REAL), - &msVerticalAngleCmd); - dict->addParameter(Ogre::ParameterDef("horizontal_direction", - "Horizontal direction of emitted particles (in degrees).", - Ogre::PT_REAL), - &msHorizontalDirCmd); - dict->addParameter(Ogre::ParameterDef("horizontal_angle", - "Horizontal direction variance of emitted particles (in degrees).", - Ogre::PT_REAL), - &msHorizontalAngleCmd); - - return true; - } - return false; - } - - /// Command objects - static CmdWidth msWidthCmd; - static CmdHeight msHeightCmd; - static CmdDepth msDepthCmd; - static CmdVerticalDir msVerticalDirCmd; - static CmdVerticalAngle msVerticalAngleCmd; - static CmdHorizontalDir msHorizontalDirCmd; - static CmdHorizontalAngle msHorizontalAngleCmd; -}; -NifEmitter::CmdWidth NifEmitter::msWidthCmd; -NifEmitter::CmdHeight NifEmitter::msHeightCmd; -NifEmitter::CmdDepth NifEmitter::msDepthCmd; -NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; -NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; -NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; -NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; - -Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleEmitter *emitter = OGRE_NEW NifEmitter(psys); - mEmitters.push_back(emitter); - return emitter; -} - - -class GrowFadeAffector : public Ogre::ParticleAffector -{ -public: - /** Command object for grow_time (see Ogre::ParamCommand).*/ - class CmdGrowTime : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GrowFadeAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getGrowTime()); - } - void doSet(void *target, const Ogre::String &val) - { - GrowFadeAffector *self = static_cast(target); - self->setGrowTime(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for fade_time (see Ogre::ParamCommand).*/ - class CmdFadeTime : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GrowFadeAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getFadeTime()); - } - void doSet(void *target, const Ogre::String &val) - { - GrowFadeAffector *self = static_cast(target); - self->setFadeTime(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Default constructor. */ - GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) - { - mGrowTime = 0.0f; - mFadeTime = 0.0f; - - mType = "GrowFade"; - - // Init parameters - if(createParamDictionary("GrowFadeAffector")) - { - Ogre::ParamDictionary *dict = getParamDictionary(); - - Ogre::String grow_title("grow_time"); - Ogre::String fade_title("fade_time"); - Ogre::String grow_descr("Time from begin to reach full size."); - Ogre::String fade_descr("Time from end to shrink."); - - dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); - dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); - } - } - - /** See Ogre::ParticleAffector. */ - void _initParticle(Ogre::Particle *particle) - { -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - const Ogre::Real life_time = particle->mTotalTimeToLive; - Ogre::Real particle_time = particle->mTimeToLive; -#else - const Ogre::Real life_time = particle->totalTimeToLive; - Ogre::Real particle_time = particle->timeToLive; -#endif - Ogre::Real width = mParent->getDefaultWidth(); - Ogre::Real height = mParent->getDefaultHeight(); - if(life_time-particle_time < mGrowTime) - { - Ogre::Real scale = (life_time-particle_time) / mGrowTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - if(particle_time < mFadeTime) - { - Ogre::Real scale = particle_time / mFadeTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - particle->setDimensions(width, height); - } - - /** See Ogre::ParticleAffector. */ - void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - const Ogre::Real life_time = p->mTotalTimeToLive; - Ogre::Real particle_time = p->mTimeToLive; -#else - const Ogre::Real life_time = p->totalTimeToLive; - Ogre::Real particle_time = p->timeToLive; -#endif - Ogre::Real width = mParent->getDefaultWidth(); - Ogre::Real height = mParent->getDefaultHeight(); - if(life_time-particle_time < mGrowTime) - { - Ogre::Real scale = (life_time-particle_time) / mGrowTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - if(particle_time < mFadeTime) - { - Ogre::Real scale = particle_time / mFadeTime; - assert (scale >= 0); - // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail - scale = std::max(scale, 0.00001f); - width *= scale; - height *= scale; - } - p->setDimensions(width, height); - } - } - - void setGrowTime(Ogre::Real time) - { - mGrowTime = time; - } - Ogre::Real getGrowTime() const - { return mGrowTime; } - - void setFadeTime(Ogre::Real time) - { - mFadeTime = time; - } - Ogre::Real getFadeTime() const - { return mFadeTime; } - - static CmdGrowTime msGrowCmd; - static CmdFadeTime msFadeCmd; - -protected: - Ogre::Real mGrowTime; - Ogre::Real mFadeTime; -}; -GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; -GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; - -Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleAffector *p = new GrowFadeAffector(psys); - mAffectors.push_back(p); - return p; -} - - -class GravityAffector : public Ogre::ParticleAffector -{ - enum ForceType { - Type_Wind, - Type_Point - }; - -public: - Ogre::Bone* mEmitterBone; - Ogre::Bone* mParticleBone; - - Ogre::ParticleSystem* getPartSys() { return mParent; } - - /** Command object for force (see Ogre::ParamCommand).*/ - class CmdForce : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getForce()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setForce(Ogre::StringConverter::parseReal(val)); - } - }; - - /** Command object for force_type (see Ogre::ParamCommand).*/ - class CmdForceType : public Ogre::ParamCommand - { - static ForceType getTypeFromString(const Ogre::String &type) - { - if(type == "wind") - return Type_Wind; - if(type == "point") - return Type_Point; - OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, - "CmdForceType::getTypeFromString"); - } - - static Ogre::String getStringFromType(ForceType type) - { - switch(type) - { - case Type_Wind: return "wind"; - case Type_Point: return "point"; - } - OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), - "CmdForceType::getStringFromType"); - } - - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return getStringFromType(self->getForceType()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setForceType(getTypeFromString(val)); - } - }; - - /** Command object for direction (see Ogre::ParamCommand).*/ - class CmdDirection : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getDirection()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setDirection(Ogre::StringConverter::parseVector3(val)); - } - }; - - /** Command object for position (see Ogre::ParamCommand).*/ - class CmdPosition : public Ogre::ParamCommand - { - public: - Ogre::String doGet(const void *target) const - { - const GravityAffector *self = static_cast(target); - return Ogre::StringConverter::toString(self->getPosition()); - } - void doSet(void *target, const Ogre::String &val) - { - GravityAffector *self = static_cast(target); - self->setPosition(Ogre::StringConverter::parseVector3(val)); - } - }; - - - /** Default constructor. */ - GravityAffector(Ogre::ParticleSystem *psys) - : ParticleAffector(psys) - , mForce(0.0f) - , mForceType(Type_Wind) - , mPosition(0.0f) - , mDirection(0.0f) - { - std::vector bones = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones; - assert (!bones.empty()); - mEmitterBone = bones[0]; - Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); - mParticleBone = static_cast(tag->getParent()); - - mType = "Gravity"; - - // Init parameters - if(createParamDictionary("GravityAffector")) - { - Ogre::ParamDictionary *dict = getParamDictionary(); - - Ogre::String force_title("force"); - Ogre::String force_descr("Amount of force applied to particles."); - Ogre::String force_type_title("force_type"); - Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); - Ogre::String direction_title("direction"); - Ogre::String direction_descr("Direction of wind forces."); - Ogre::String position_title("position"); - Ogre::String position_descr("Position of point forces."); - - dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); - dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); - dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); - dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); - } - } - - /** See Ogre::ParticleAffector. */ - void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - switch(mForceType) - { - case Type_Wind: - applyWindForce(psys, timeElapsed); - break; - case Type_Point: - applyPointForce(psys, timeElapsed); - break; - } - } - - void setForce(Ogre::Real force) - { mForce = force; } - Ogre::Real getForce() const - { return mForce; } - - void setForceType(ForceType type) - { mForceType = type; } - ForceType getForceType() const - { return mForceType; } - - void setDirection(const Ogre::Vector3 &dir) - { mDirection = dir; } - const Ogre::Vector3 &getDirection() const - { return mDirection; } - - void setPosition(const Ogre::Vector3 &pos) - { mPosition = pos; } - const Ogre::Vector3 &getPosition() const - { return mPosition; } - - static CmdForce msForceCmd; - static CmdForceType msForceTypeCmd; - static CmdDirection msDirectionCmd; - static CmdPosition msPositionCmd; - -protected: - void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - p->mDirection += vec; -#else - p->direction += vec; -#endif - } - } - - void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) - { - const Ogre::Real force = mForce * timeElapsed; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3 position = p->mPosition; -#else - Ogre::Vector3 position = p->position; -#endif - - Ogre::Vector3 vec = (mPosition - position).normalisedCopy() * force; -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - p->mDirection += vec; -#else - p->direction += vec; -#endif - } - } - - - float mForce; - - ForceType mForceType; - - Ogre::Vector3 mPosition; - Ogre::Vector3 mDirection; -}; -GravityAffector::CmdForce GravityAffector::msForceCmd; -GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; -GravityAffector::CmdDirection GravityAffector::msDirectionCmd; -GravityAffector::CmdPosition GravityAffector::msPositionCmd; - -Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) -{ - Ogre::ParticleAffector *p = new GravityAffector(psys); - mAffectors.push_back(p); - return p; -} diff --git a/components/nifogre/particles.hpp b/components/nifogre/particles.hpp deleted file mode 100644 index 6efc669fe7..0000000000 --- a/components/nifogre/particles.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OENGINE_OGRE_PARTICLES_H -#define OENGINE_OGRE_PARTICLES_H - -#include -#include - -/** Factory class for NifEmitter. */ -class NifEmitterFactory : public Ogre::ParticleEmitterFactory -{ -public: - /** See ParticleEmitterFactory */ - Ogre::String getName() const - { return "Nif"; } - - /** See ParticleEmitterFactory */ - Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); -}; - -/** Factory class for GrowFadeAffector. */ -class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory -{ - /** See Ogre::ParticleAffectorFactory */ - Ogre::String getName() const - { return "GrowFade"; } - - /** See Ogre::ParticleAffectorFactory */ - Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); -}; - -/** Factory class for GravityAffector. */ -class GravityAffectorFactory : public Ogre::ParticleAffectorFactory -{ - /** See Ogre::ParticleAffectorFactory */ - Ogre::String getName() const - { return "Gravity"; } - - /** See Ogre::ParticleAffectorFactory */ - Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); -}; - -struct NiNodeHolder -{ - std::vector mBones; - - // Ogre::Any needs this for some reason - friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r) - { return o; } -}; - -#endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp deleted file mode 100644 index db6a753c52..0000000000 --- a/components/nifogre/skeleton.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "skeleton.hpp" - -#include -#include -#include -#include - -#include -#include -#include - -namespace NifOgre -{ - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) -{ - Ogre::Bone *bone; - if (node->name.empty()) - { - // HACK: use " " instead of empty name, otherwise Ogre will replace it with an auto-generated - // name in SkeletonInstance::cloneBoneAndChildren. - static const char* emptyname = " "; - if (!skel->hasBone(emptyname)) - bone = skel->createBone(emptyname); - else - bone = skel->createBone(); - } - else - { - if(!skel->hasBone(node->name)) - bone = skel->createBone(node->name); - else - bone = skel->createBone(); - } - - if(parent) parent->addChild(bone); - mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); - bone->setBindingPose(); - - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ - node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ - node->recType == Nif::RC_NiBillboardNode || /* Handled in the object loader */ - node->recType == Nif::RC_NiBSParticleNode || - node->recType == Nif::RC_NiCamera || - node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiBSPArrayController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiKeyframeController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) - warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); - ctrl = ctrl->next; - } - - 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(), bone); - } - } -} - -void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) -{ - Ogre::Skeleton *skel = dynamic_cast(resource); - OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - - Nif::NIFFilePtr nif(Nif::Cache::getInstance().load(skel->getName())); - const Nif::Node *node = static_cast(nif->getRoot(0)); - - try { - buildBones(skel, node); - } - catch(std::exception &e) { - std::cerr<< "Exception while loading "<getName() <boneTrafo) - return true; - - if(!node->controller.empty()) - { - Nif::ControllerPtr ctrl = node->controller; - do { - if(ctrl->recType == Nif::RC_NiKeyframeController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - return true; - } while(!(ctrl=ctrl->next).empty()); - } - - if (node->name == "AttachLight" || node->name == "ArrowBone") - return true; - - if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) - { - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(needSkeleton(children[i].getPtr())) - return true; - } - } - return false; - } - if(node->recType == Nif::RC_NiTriShape) - return false; - - return true; -} - -Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) -{ - bool forceskel = false; - std::string::size_type extpos = name.rfind('.'); - if(extpos != std::string::npos && name.compare(extpos, name.size()-extpos, ".nif") == 0) - { - Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton(); - forceskel = resMgr.resourceExistsInAnyGroup(name.substr(0, extpos)+".kf"); - } - - if(forceskel || needSkeleton(node)) - { - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - return skelMgr.create(name, group, true, &sLoaders[name]); - } - - return Ogre::SkeletonPtr(); -} - -// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be -// used when the bone name is insufficient as this is a relatively slow lookup -int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) -{ - LoaderMap::const_iterator loader = sLoaders.find(nifname); - if(loader != sLoaders.end()) - { - std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); - if(entry != loader->second.mNifToOgreHandleMap.end()) - return entry->second; - } - throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); -} - -NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; - -} diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp deleted file mode 100644 index 9ec3a0c825..0000000000 --- a/components/nifogre/skeleton.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef COMPONENTS_NIFOGRE_SKELETON_HPP -#define COMPONENTS_NIFOGRE_SKELETON_HPP - -#include -#include -#include - -#include - -#include "ogrenifloader.hpp" - -namespace Nif -{ - class NiTextKeyExtraData; - class Node; - class NiKeyframeController; -} - -namespace NifOgre -{ - -/** Manual resource loader for NIF skeletons. This is the main class - responsible for translating the internal NIF skeleton structure into - something Ogre can use (includes animations and node TextKeyData). - */ -class NIFSkeletonLoader : public Ogre::ManualResourceLoader -{ - static void warn(const std::string &msg) - { - std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; - } - - static void fail(const std::string &msg) - { - std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; - abort(); - } - - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); - - static bool needSkeleton(const Nif::Node *node); - - // Lookup to retrieve an Ogre bone handle for a given Nif record index - std::map mNifToOgreHandleMap; - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - -public: - void loadResource(Ogre::Resource *resource); - - static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); - - // Looks up an Ogre Bone handle ID from a NIF's record index. Should only - // be used when the bone name is insufficient as this is a relatively slow - // lookup - static int lookupOgreBoneHandle(const std::string &nifname, int idx); -}; - -} - -#endif diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 574b67f19d..e8ca2e8bd9 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -15,8 +15,6 @@ #include #endif -#include - #include #include @@ -118,8 +116,6 @@ namespace OgreInit loadPlugins(); #endif - loadParticleFactories(); - return mRoot; } @@ -128,16 +124,6 @@ namespace OgreInit delete mRoot; delete Ogre::LogManager::getSingletonPtr(); - std::vector::iterator ei; - for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei) - OGRE_DELETE (*ei); - mEmitterFactories.clear(); - - std::vector::iterator ai; - for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();++ai) - OGRE_DELETE (*ai); - mAffectorFactories.clear(); - #ifdef ENABLE_PLUGIN_GL delete mGLPlugin; mGLPlugin = NULL; @@ -221,22 +207,4 @@ namespace OgreInit if (!Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot)) throw std::runtime_error("Required Plugin_ParticleFX for Ogre not found!"); } - - void OgreInit::loadParticleFactories() - { - Ogre::ParticleEmitterFactory *emitter; - emitter = OGRE_NEW NifEmitterFactory(); - Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); - mEmitterFactories.push_back(emitter); - - Ogre::ParticleAffectorFactory *affector; - affector = OGRE_NEW GrowFadeAffectorFactory(); - Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); - mAffectorFactories.push_back(affector); - - affector = OGRE_NEW GravityAffectorFactory(); - Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); - mAffectorFactories.push_back(affector); - } - } diff --git a/components/ogreinit/ogreinit.hpp b/components/ogreinit/ogreinit.hpp index 9613421f7b..d1743950f2 100644 --- a/components/ogreinit/ogreinit.hpp +++ b/components/ogreinit/ogreinit.hpp @@ -48,13 +48,10 @@ namespace OgreInit ~OgreInit(); private: - std::vector mEmitterFactories; - std::vector mAffectorFactories; Ogre::Root* mRoot; void loadStaticPlugins(); void loadPlugins(); - void loadParticleFactories(); #ifdef ENABLE_PLUGIN_CgProgramManager Ogre::CgPlugin* mCgPlugin; From baa152328a8ad8efe3a2e3499a7c412e827c2642 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 01:32:36 +0100 Subject: [PATCH 0054/1812] Crash fix --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6a2523120c..2ed91d4676 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -414,7 +414,7 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::Node* created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); return created; } From 9141a8d8014a236eec3c2e557bf71731ef05deb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 22:52:20 +0100 Subject: [PATCH 0055/1812] Fully implement NiStencilProperty (Feature #1057) --- apps/nifosgtest/test.cpp | 3 ++ components/nif/property.hpp | 2 +- components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 0da95d13d4..253b5f99dc 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -102,6 +102,9 @@ int main(int argc, char** argv) Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); + // For NiStencilProperty + osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); + osgViewer::Viewer viewer; osg::ref_ptr root(new osg::Group()); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 2633b16c59..96156c6d83 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -221,7 +221,7 @@ struct S_StencilProperty 4 TEST_GREATER 5 TEST_NOT_EQUAL 6 TEST_GREATER_EQUAL - 7 TEST_ALWAYS + 7 TEST_NEVER (though nifskope comment says TEST_ALWAYS, but ingame it is TEST_NEVER) */ int compareFunc; unsigned stencilRef; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2ed91d4676..45619b21b9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -116,6 +116,40 @@ namespace } } + osg::Stencil::Function getStencilFunction(int func) + { + switch (func) + { + case 0: return osg::Stencil::NEVER; + case 1: return osg::Stencil::LESS; + case 2: return osg::Stencil::EQUAL; + case 3: return osg::Stencil::LEQUAL; + case 4: return osg::Stencil::GREATER; + case 5: return osg::Stencil::NOTEQUAL; + case 6: return osg::Stencil::GEQUAL; + case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER + default: + std::cerr << "Unexpected stencil function: " << func << std::endl; + return osg::Stencil::NEVER; + } + } + + osg::Stencil::Operation getStencilOperation(int op) + { + switch (op) + { + case 0: return osg::Stencil::KEEP; + case 1: return osg::Stencil::ZERO; + case 2: return osg::Stencil::REPLACE; + case 3: return osg::Stencil::INCR; + case 4: return osg::Stencil::DECR; + case 5: return osg::Stencil::INVERT; + default: + std::cerr << "Unexpected stencil operation: " << op << std::endl; + return osg::Stencil::KEEP; + } + } + // Collect all properties affecting the given node that should be applied to an osg::Material. void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) { @@ -1095,16 +1129,17 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); - // TODO: - // Stencil settings not enabled yet, not sure if the original engine is actually using them, - // since they might conflict with Morrowind's stencil shadows. - /* - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + if (stencilprop->data.enabled != 0) + { + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(getStencilFunction(stencilprop->data.compareFunc), stencilprop->data.stencilRef, stencilprop->data.stencilMask); + stencil->setStencilFailOperation(getStencilOperation(stencilprop->data.failAction)); + stencil->setStencilPassAndDepthFailOperation(getStencilOperation(stencilprop->data.zFailAction)); + stencil->setStencilPassAndDepthPassOperation(getStencilOperation(stencilprop->data.zPassAction)); - stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - */ + stateset->setAttributeAndModes(stencil, osg::StateAttribute::ON); + } + break; } case Nif::RC_NiWireframeProperty: { From 9ee99a751c21d84c8bee7211ed25bd62a8a5ca3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 23:40:37 +0100 Subject: [PATCH 0056/1812] Stop warning about NiDitherProperty, ignore NiShadeProperty (unused) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 45619b21b9..199fdb9843 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1294,10 +1294,10 @@ namespace NifOsg } break; } + // unused by mw + case Nif::RC_NiShadeProperty: case Nif::RC_NiDitherProperty: { - stateset->setMode(GL_DITHER, property->flags != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); break; } default: From b072e803ce10b6e777cfffddcacdc453235e7513 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 23:54:48 +0100 Subject: [PATCH 0057/1812] Use correct ambient/diffuse default values when no NiMaterialProperty exists --- components/nifosg/nifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 199fdb9843..ea59b9bd2a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1314,7 +1314,11 @@ namespace NifOsg int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + + // NIF material defaults don't match OpenGL defaults + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; From 20866b44f7a3074e90b0b40e18cc5e3372ee71dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 00:54:45 +0100 Subject: [PATCH 0058/1812] FlipController fix, DetailTexture & DarkTexture tested --- components/nifosg/controller.cpp | 5 ++++- components/nifosg/controller.hpp | 1 - components/nifosg/nifloader.cpp | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index ef3157773a..0e1f15f0f2 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -433,9 +433,12 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(stateset->getAttribute(osg::StateAttribute::TEXTURE)); + osg::Texture2D* tex = dynamic_cast(stateset->getTextureAttribute(mTexSlot, osg::StateAttribute::TEXTURE)); if (tex) tex->setImage(mTextures[curTexture].get()); + else + std::cout << "FlipController: can't find target slot" << std::endl; + } traverse(node, nv); } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 17bf3ae75b..c6ef74d2a5 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -259,7 +259,6 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - // untested class FlipController : public osg::NodeCallback, public Controller { private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ea59b9bd2a..d05758f2e3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1260,14 +1260,12 @@ namespace NifOsg } else if (i == Nif::NiTexturingProperty::DarkTexture) { - // untested osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::MODULATE); stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DetailTexture) { - // untested osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; texEnv->setScale_RGB(2.f); texEnv->setCombine_Alpha(GL_MODULATE); From c179977f206b35fef854dbfdf8d4b8cd2a4df9d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 01:58:41 +0100 Subject: [PATCH 0059/1812] Fix quaternion rotation order --- components/nifosg/controller.cpp | 2 +- components/nifosg/particle.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 0e1f15f0f2..a31263d8bf 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -135,7 +135,7 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); - return (zr*yr*xr); + return (xr*yr*zr); } osg::Vec3f KeyframeController::getTranslation(float time) const diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 25970c8627..899ce75376 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -77,7 +77,7 @@ void ParticleShooter::shoot(osgParticle::Particle *particle) const float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = osg::Quat(hdir, osg::Vec3f(0,0,1)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(vdir2, osg::Vec3f(1,0,0)) + osg::Vec3f dir = (osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); From 6d9deaa38643586b18dd35aa6ebd5096bef2c120 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 04:57:01 +0100 Subject: [PATCH 0060/1812] Implement planar collider for particles (Fixes #2149) --- components/nif/controlled.cpp | 10 ++++++-- components/nif/controlled.hpp | 5 ++++ components/nif/controller.cpp | 7 +++--- components/nif/controller.hpp | 3 ++- components/nifosg/nifloader.cpp | 41 +++++++++++++++++++------------- components/nifosg/particle.cpp | 42 +++++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 19 +++++++++++++++ 7 files changed, 104 insertions(+), 23 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 526b2eca32..9db0c4a6f8 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -65,8 +65,14 @@ namespace Nif { Controlled::read(nif); - // (I think) 4 floats + 4 vectors - nif->skip(4*16); + mBounceFactor = nif->getFloat(); + /*unknown*/nif->getFloat(); + + for (int i=0;i<10;++i) + /*unknown*/nif->getFloat(); + + mPlaneNormal = nif->getVector3(); + mPlaneDistance = nif->getFloat(); } void NiParticleRotation::read(NIFStream *nif) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index ac75c35086..36d90b03dd 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -103,6 +103,11 @@ class NiPlanarCollider : public Controlled { public: void read(NIFStream *nif); + + float mBounceFactor; + + osg::Vec3f mPlaneNormal; + float mPlaneDistance; }; class NiParticleRotation : public Controlled diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 376a1fe123..f391325439 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -76,8 +76,8 @@ namespace Nif } nif->getUInt(); /* -1? */ - extra.read(nif); - nif->getUInt(); /* -1? */ + affectors.read(nif); + colliders.read(nif); nif->getChar(); } @@ -85,7 +85,8 @@ namespace Nif { Controller::post(nif); emitter.post(nif); - extra.post(nif); + affectors.post(nif); + colliders.post(nif); } void NiMaterialColorController::read(NIFStream *nif) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 73344e77bf..0861dfa6b6 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -72,7 +72,8 @@ public: int activeCount; std::vector particles; - ExtraPtr extra; + ExtraPtr affectors; + ExtraPtr colliders; void read(NIFStream *nif); void post(NIFFile *nif); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d05758f2e3..a2fd8e39ad 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,39 +719,44 @@ namespace NifOsg } } - void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - for (; !e.empty(); e = e->extra) + for (; !affectors.empty(); affectors = affectors->extra) { - if (e->recType == Nif::RC_NiParticleGrowFade) + if (affectors->recType == Nif::RC_NiParticleGrowFade) { - const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); - GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime); - program->addOperator(affector); + const Nif::NiParticleGrowFade *gf = static_cast(affectors.getPtr()); + program->addOperator(new GrowFadeAffector(gf->growTime, gf->fadeTime)); } - else if (e->recType == Nif::RC_NiGravity) + else if (affectors->recType == Nif::RC_NiGravity) { - const Nif::NiGravity* gr = static_cast(e.getPtr()); - GravityAffector* affector = new GravityAffector(gr); - program->addOperator(affector); + const Nif::NiGravity* gr = static_cast(affectors.getPtr()); + program->addOperator(new GravityAffector(gr)); } - else if (e->recType == Nif::RC_NiParticleColorModifier) + else if (affectors->recType == Nif::RC_NiParticleColorModifier) { - const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiParticleColorModifier *cl = static_cast(affectors.getPtr()); const Nif::NiColorData *clrdata = cl->data.getPtr(); - ParticleColorAffector* affector = new ParticleColorAffector(clrdata); - program->addOperator(affector); + program->addOperator(new ParticleColorAffector(clrdata)); } - else if (e->recType == Nif::RC_NiParticleRotation) + else if (affectors->recType == Nif::RC_NiParticleRotation) { // TODO: Implement? } else - std::cerr << "Unhandled particle modifier " << e->recName << std::endl; + std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; + } + for (; !colliders.empty(); colliders = colliders->extra) + { + if (colliders->recType == Nif::RC_NiPlanarCollider) + { + const Nif::NiPlanarCollider* planarcollider = static_cast(colliders.getPtr()); + program->addOperator(new PlanarCollider(planarcollider)); + } } } @@ -888,7 +893,9 @@ namespace NifOsg emitter->setUpdateCallback(callback); // affectors must be attached *after* the emitter in the scene graph for correct update order - handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf); + // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct + // localToWorldMatrix for transforming to particle space + handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 899ce75376..0afbf5e95f 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -303,4 +303,46 @@ void FindRecIndexVisitor::apply(osg::Node &searchNode) traverse(searchNode); } +PlanarCollider::PlanarCollider(const Nif::NiPlanarCollider *collider) + : mBounceFactor(collider->mBounceFactor) + , mPlane(-collider->mPlaneNormal, collider->mPlaneDistance) +{ +} + +PlanarCollider::PlanarCollider() + : mBounceFactor(0.f) +{ +} + +PlanarCollider::PlanarCollider(const PlanarCollider ©, const osg::CopyOp ©op) + : osgParticle::Operator(copy, copyop) + , mBounceFactor(copy.mBounceFactor) + , mPlane(copy.mPlane) + , mPlaneInParticleSpace(copy.mPlaneInParticleSpace) +{ +} + +void PlanarCollider::beginOperate(osgParticle::Program *program) +{ + mPlaneInParticleSpace = mPlane; + if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF) + mPlaneInParticleSpace.transform(program->getLocalToWorldMatrix()); +} + +void PlanarCollider::operate(osgParticle::Particle *particle, double dt) +{ + float dotproduct = particle->getVelocity() * mPlaneInParticleSpace.getNormal(); + + if (dotproduct > 0) + { + osg::BoundingSphere bs(particle->getPosition(), 0.f); + if (mPlaneInParticleSpace.intersect(bs) == 1) + { + osg::Vec3 reflectedVelocity = particle->getVelocity() - mPlaneInParticleSpace.getNormal() * (2 * dotproduct); + reflectedVelocity *= mBounceFactor; + particle->setVelocity(reflectedVelocity); + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 01e06f471f..99db3c83aa 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -17,6 +17,7 @@ namespace Nif { class NiGravity; + class NiPlanarCollider; } namespace NifOsg @@ -92,6 +93,24 @@ namespace NifOsg float mLifetimeRandom; }; + class PlanarCollider : public osgParticle::Operator + { + public: + PlanarCollider(const Nif::NiPlanarCollider* collider); + PlanarCollider(); + PlanarCollider(const PlanarCollider& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, PlanarCollider) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + + private: + float mBounceFactor; + osg::Plane mPlane; + osg::Plane mPlaneInParticleSpace; + }; + class GrowFadeAffector : public osgParticle::Operator { public: From 60ede8dede80328492e072fb5814690ef06961d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 05:14:07 +0100 Subject: [PATCH 0061/1812] Stop warning about NiFogProperty (unused in MW) --- components/nifosg/nifloader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2fd8e39ad..c6927cfade 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1302,6 +1302,7 @@ namespace NifOsg // unused by mw case Nif::RC_NiShadeProperty: case Nif::RC_NiDitherProperty: + case Nif::RC_NiFogProperty: { break; } From 46cbec9a4a406904a80905fe2209c92b15ecb70c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 15:39:41 +0100 Subject: [PATCH 0062/1812] Add skinning auto-detection in nifosg loader --- apps/nifosgtest/test.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- components/nif/niffile.cpp | 11 +++++++++++ components/nif/niffile.hpp | 8 ++++++++ components/nif/node.hpp | 2 ++ components/nifosg/nifloader.cpp | 5 ++++- components/nifosg/nifloader.hpp | 6 ++---- 7 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 253b5f99dc..0f2e43a563 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -117,7 +117,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; - newNode->addChild(loader.loadAsSkeleton(nif)); + newNode->addChild(loader.load(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f48fcc4402..bd44ba5772 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -60,7 +60,7 @@ void CSVRender::Object::update() Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - mBaseNode->addChild(loader.loadAsSkeleton(file)); + mBaseNode->addChild(loader.load(file)); //mObject->setVisibilityFlags (Element_Reference); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f7d864198e..a73985cfb1 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -12,6 +12,7 @@ NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) , mStream(stream) + , mUseSkinning(false) { parse(); } @@ -208,4 +209,14 @@ void NIFFile::parse() records[i]->post(this); } +void NIFFile::setUseSkinning(bool skinning) +{ + mUseSkinning = skinning; +} + +bool NIFFile::getUseSkinning() const +{ + return mUseSkinning; +} + } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 9f08f3f1d9..ae5aca5acc 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -32,6 +32,8 @@ class NIFFile /// Root list. This is a select portion of the pointers from records std::vector roots; + bool mUseSkinning; + /// Parse the file void parse(); @@ -83,6 +85,12 @@ public: /// Number of roots size_t numRoots() const { return roots.size(); } + /// Set whether there is skinning contained in this NIF file. + /// @note This is just a hint for users of the NIF file and has no effect on the loading procedure. + void setUseSkinning(bool skinning); + + bool getUseSkinning() const; + /// Get the name of the file std::string getFilename(){ return filename; } }; diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 7f94c0d05b..b47c052811 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -166,6 +166,8 @@ struct NiTriShape : Node Node::post(nif); data.post(nif); skin.post(nif); + if (!skin.empty()) + nif->setUseSkinning(true); } }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c6927cfade..3c15b57ae0 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -297,7 +297,7 @@ namespace void apply(osg::Node &node) { std::map::const_iterator found = mMap.find(node.getName()); - if (found != mMap.end()) + if (node.asTransform() && found != mMap.end()) { const Nif::NiKeyframeController* keyframectrl = found->second; @@ -439,6 +439,9 @@ namespace NifOsg osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) { + if (nif->getUseSkinning()) + return loadAsSkeleton(nif, textKeys); + if (nif->numRoots() < 1) nif->fail("Found no root nodes"); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 43eb8da783..87d1a0a99f 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -24,13 +24,11 @@ namespace NifOsg class Loader { public: - // TODO: add auto-detection for skinning. We will still need a "force skeleton" parameter - // though, when assembling from several files, i.e. equipment parts - /// Create a scene graph for the given NIF. Assumes no skinning is used. + /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); - /// Create a scene graph for the given NIF. Assumes skinning will be used. + /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); /// Load keyframe controllers from the given kf file onto the given scene graph. From 96d51f0bb70f9583635891d72905048a723c6d00 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 16:34:51 +0100 Subject: [PATCH 0063/1812] NiParticleRotation seems to be unused --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3c15b57ae0..a15ad7416d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -748,7 +748,7 @@ namespace NifOsg } else if (affectors->recType == Nif::RC_NiParticleRotation) { - // TODO: Implement? + // unused? } else std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; From e938fa4a9d832cffd69003fbb7f0d43a49c554f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 18:12:04 +0100 Subject: [PATCH 0064/1812] Implement extrapolation mode in ControllerFunction (Bug #1871) --- components/nifosg/controller.cpp | 59 ++++++++++++++++++-------------- components/nifosg/controller.hpp | 15 ++++---- components/nifosg/nifloader.cpp | 4 +-- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a31263d8bf..6aa9205532 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -18,50 +18,59 @@ namespace NifOsg { -ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) - : mDeltaInput(deltaInput) - , mFrequency(ctrl->frequency) +ControllerFunction::ControllerFunction(const Nif::Controller *ctrl) + : mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) - , mDeltaCount(0.f) + , mExtrapolationMode(static_cast((ctrl->flags&0x6) >> 1)) { - if(mDeltaInput) - mDeltaCount = mPhase; } float ControllerFunction::calculate(float value) { - if(mDeltaInput) + float time = mFrequency * value + mPhase; + if (time >= mStartTime && time <= mStopTime) + return time; + switch (mExtrapolationMode) { - if (mStopTime - mStartTime == 0.f) - return 0.f; - - mDeltaCount += value*mFrequency; - if(mDeltaCount < mStartTime) - mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, - mStopTime - mStartTime); - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + case Cycle: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; + return mStartTime + remainder; } + case Reverse: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; + + // Even number of cycles? + if ( ( static_cast(std::fabs( std::floor( cycles ) )) % 2 ) == 0 ) + return mStartTime + remainder; + + return mStopTime - remainder; + } + case Constant: + default: + return std::min(mStopTime, std::max(mStartTime, time)); + } } FrameTimeSource::FrameTimeSource() - : mLastTime(0.0) { } float FrameTimeSource::getValue(osg::NodeVisitor *nv) { - // TODO: dt could be computed globally instead of once per instance - double time = nv->getFrameStamp()->getReferenceTime(); - float dt = static_cast(time - mLastTime); - mLastTime = time; - return dt; + return nv->getFrameStamp()->getReferenceTime(); } KeyframeController::KeyframeController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c6ef74d2a5..7579735cac 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -81,17 +81,20 @@ namespace NifOsg float mFrequency; float mPhase; float mStartTime; - bool mDeltaInput; - float mDeltaCount; - public: float mStopTime; + enum ExtrapolationMode + { + Cycle = 0, + Reverse = 1, + Constant = 2 + }; + ExtrapolationMode mExtrapolationMode; public: - ControllerFunction(const Nif::Controller *ctrl, bool deltaInput); + ControllerFunction(const Nif::Controller *ctrl); float calculate(float value); }; - typedef ControllerFunction DefaultFunction; class ControllerSource { @@ -104,8 +107,6 @@ namespace NifOsg public: FrameTimeSource(); virtual float getValue(osg::NodeVisitor* nv); - private: - double mLastTime; }; class Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a15ad7416d..17a669312e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,7 +302,7 @@ namespace const Nif::NiKeyframeController* keyframectrl = found->second; osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl, false)); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl)); // Insert in front of the callback list, to make sure UpdateBone is last. // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. @@ -490,7 +490,7 @@ namespace NifOsg //if (autoPlay) toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, From caa93f767b18731285d7d29d34319b0a3e9d0b5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 18:41:37 +0100 Subject: [PATCH 0065/1812] Skip creating meshes for hidden nodes with no VisControllers There's quite a bit of garbage in base_anim.nif, so this change should result in a much leaner scene graph. --- components/nifosg/nifloader.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 17a669312e..bdd40e2453 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -562,10 +562,20 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - // We could probably skip hidden nodes entirely if they don't have a VisController that + // We can skip creating meshes for hidden nodes if they don't have a VisController that // might make them visible later if (nifNode->flags & Nif::NiNode::Flag_Hidden) - transformNode->setNodeMask(0x1); // Leave mask for UpdateVisitor enabled + { + bool hasVisController = false; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + hasVisController = (ctrl->recType == Nif::RC_NiVisController); + + if (!hasVisController) + skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating collision shapes + + // now hide this node, but leave the mask for UpdateVisitor enabled so that KeyframeController works + transformNode->setNodeMask(0x1); + } applyNodeProperties(nifNode, transformNode, boundTextures, animflags); From aedafe651a52701d44de32b9cf52a857a39c0d2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 19:08:09 +0100 Subject: [PATCH 0066/1812] OpenCS: delete physicssystem, will be replaced with OSG picking --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/doc/document.cpp | 12 +- apps/opencs/model/doc/document.hpp | 8 - apps/opencs/view/render/cell.cpp | 13 +- apps/opencs/view/render/cell.hpp | 9 +- apps/opencs/view/render/mousestate.cpp | 463 ------------------ apps/opencs/view/render/mousestate.hpp | 91 ---- apps/opencs/view/render/object.cpp | 26 +- apps/opencs/view/render/object.hpp | 2 - .../view/render/pagedworldspacewidget.cpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 23 +- apps/opencs/view/render/worldspacewidget.hpp | 9 +- apps/opencs/view/world/physicssystem.cpp | 325 ------------ apps/opencs/view/world/physicssystem.hpp | 94 ---- 15 files changed, 26 insertions(+), 1059 deletions(-) delete mode 100644 apps/opencs/view/render/mousestate.cpp delete mode 100644 apps/opencs/view/render/mousestate.hpp delete mode 100644 apps/opencs/view/world/physicssystem.cpp delete mode 100644 apps/opencs/view/world/physicssystem.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6976aec422..4f6b2a875d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -66,7 +66,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator ) opencs_units (view/widget @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay mousestate + lightingbright object cell terrainstorage textoverlay ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2a5fa77465..7f3d98d0cb 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -9,8 +9,6 @@ #include #endif -#include "../../view/world/physicssystem.hpp" - void CSMDoc::Document::addGmsts() { static const char *gmstFloats[] = @@ -2255,7 +2253,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSaving (*this, mProjectPath, encoding), - mRunner (mProjectPath), mPhysics(boost::shared_ptr()) + mRunner (mProjectPath) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2471,11 +2469,3 @@ void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); } - -boost::shared_ptr CSMDoc::Document::getPhysics () -{ - if(!mPhysics) - mPhysics = boost::shared_ptr (new CSVWorld::PhysicsSystem()); - - return mPhysics; -} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 2d42e99034..292b292dfd 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -46,11 +46,6 @@ namespace CSMWorld class ResourcesManager; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSMDoc { class Document : public QObject @@ -70,7 +65,6 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; - boost::shared_ptr mPhysics; // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. @@ -145,8 +139,6 @@ namespace CSMDoc QTextDocument *getRunLog(); - boost::shared_ptr getPhysics(); - signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 72ceb654a1..28ce1dd6cc 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,7 +10,6 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" -#include "../world/physicssystem.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -60,8 +59,8 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0) + const std::string& id, const Ogre::Vector3& origin) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mX(0), mY(0) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -89,16 +88,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; - mPhysics->addHeightField(sceneManager, - esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); + //mPhysics->addHeightField(sceneManager, + // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } } CSVRender::Cell::~Cell() { - if (mTerrain.get()) - mPhysics->removeHeightField(mSceneMgr, mX, mY); + //if (mTerrain.get()) + // mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 73d7949482..8c7d7e23ae 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -28,11 +28,6 @@ namespace CSMWorld class Data; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Cell @@ -42,7 +37,6 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; - boost::shared_ptr mPhysics; Ogre::SceneManager *mSceneMgr; int mX; int mY; @@ -59,8 +53,7 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, - boost::shared_ptr physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp deleted file mode 100644 index 8edd9d58fc..0000000000 --- a/apps/opencs/view/render/mousestate.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include "mousestate.hpp" - -#include -#include -#include -#include - -#include -#include -#include - -#include "../../model/settings/usersettings.hpp" -#include "../../model/world/commands.hpp" -#include "../../model/world/idtable.hpp" -#include "../../model/world/universalid.hpp" -#include "../world/physicssystem.hpp" - -#include "elements.hpp" -#include "worldspacewidget.hpp" - -namespace CSVRender -{ - // mouse picking - // FIXME: need to virtualise mouse buttons - // - // State machine: - // - // [default] mousePressEvent->check if the mouse is pointing at an object - // if yes, create collision planes then go to [grab] - // else check for terrain - // - // [grab] mouseReleaseEvent->if same button and new obj, go to [edit] - // mouseMoveEvent->if same button, go to [drag] - // other mouse events or buttons, go back to [default] (i.e. like 'cancel') - // - // [drag] mouseReleaseEvent->if same button, place the object at the new - // location, update the document then go to [edit] - // mouseMoveEvent->update position to the user based on ray to the collision - // planes and render the object at the new location, but do not update - // the document yet - // - // [edit] TODO, probably fine positional adjustments or rotations; clone/delete? - // - // - // press press (obj) - // [default] --------> [grab] <-------------------- [edit] - // ^ (obj) | | ------> [drag] -----> ^ - // | | | move ^ | release | - // | | | | | | - // | | | +-+ | - // | | | move | - // +----------------+ +--------------------------+ - // release release - // (same obj) (new obj) - // - // - - MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(0/*parent->getSceneManager()*/) - , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) - , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) - , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) - { - const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); - - mColIndexPosX = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); - mColIndexPosY = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); - mColIndexPosZ = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); - - mIdTableModel = static_cast( - mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference)); - - mMouseEventTimer = new QElapsedTimer(); - mMouseEventTimer->invalidate(); - - std::pair planeRes = planeAxis(); - mPlane = new Ogre::Plane(planeRes.first, 0); - Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("mouse", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - *mPlane, - 300000,300000, // FIXME: use far clip dist? - 1,1, // segments - true, // normals - 1, // numTexCoordSets - 1,1, // uTile, vTile - planeRes.second // upVector - ); - } - - MouseState::~MouseState () - { - delete mMouseEventTimer; - delete mPlane; - } - - void MouseState::mouseMoveEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - { - // check if min elapsed time to stop false detection of drag - if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms - break; - - mMouseEventTimer->invalidate(); - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - } - case Mouse_Drag: - { - if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? - { - mOldPos = event->pos(); - - // ray test against the plane to provide feedback to the user the - // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); - mCurrentMousePos = planeResult.second; - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); - updateSceneWidgets(); - } - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; // error event, ignore - } - /* NO_DEFAULT_CASE */ - } - } - - void MouseState::mousePressEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - break; - } - case Mouse_Edit: - case Mouse_Default: - { - if(event->buttons() & Qt::RightButton) - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first == "") - break; - - mGrabbedSceneNode = result.first; - // ray test agaist the plane to get a starting position of the - // mouse in relation to the object position - std::pair planeRes = planeAxis(); - mPlane->redefine(planeRes.first, result.second); - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - mOrigMousePos = planeResult.second; - mCurrentMousePos = planeResult.second; - mOffset = 0.0f; - } - - mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition(); - mMouseEventTimer->start(); - - mMouseState = Mouse_Grab; - } - break; - } - /* NO_DEFAULT_CASE */ - } - } - - void MouseState::mouseReleaseEvent (QMouseEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first != "") - { - if(result.first == mCurrentObj) - { - // unselect object - mMouseState = Mouse_Default; - mCurrentObj = ""; - } - else - { - // select object - mMouseState = Mouse_Edit; - mCurrentObj = result.first; - - } - } - break; - } - case Mouse_Drag: - { - // final placement - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - // use the saved scene node name since the physics model has not moved yet - std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); - - mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y)); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); - mParent->mDocument.getUndoStack().endMacro(); - - // FIXME: highlight current object? - //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? - mCurrentObj = ""; // whether the object is selected - - mMouseState = Mouse_Edit; - - // reset states - mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event - mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space - mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space - mGrabbedSceneNode = ""; // id of the object - mOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - // probably terrain, check - std::pair result = terrainUnderCursor(event->x(), event->y()); - if(result.first != "") - { - // FIXME: terrain editing goes here - } - break; - } - /* NO_DEFAULT_CASE */ - } - mMouseEventTimer->invalidate(); - } - - void MouseState::mouseDoubleClickEvent (QMouseEvent *event) - { - event->ignore(); - //mPhysics->toggleDebugRendering(mSceneManager); - //mParent->flagAsModified(); - } - - bool MouseState::wheelEvent (QWheelEvent *event) - { - switch(mMouseState) - { - case Mouse_Grab: - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - case Mouse_Drag: - { - // move the object along the z axis during Mouse_Drag or Mouse_Grab - if (event->delta()) - { - // seems positive is up and negative is down - mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option? - - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); - updateSceneWidgets(); - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - return false; - } - /* NO_DEFAULT_CASE */ - } - - return true; - } - - void MouseState::cancelDrag() - { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - // cancel operation & return the object to the original position - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(mOrigObjPos); - // update all SceneWidgets and their SceneManagers - mPhysics->moveSceneNodes(mGrabbedSceneNode, mOrigObjPos); - updateSceneWidgets(); - - // reset states - mMouseState = Mouse_Default; - mCurrentMousePos = Ogre::Vector3(); - mOrigMousePos = Ogre::Vector3(); - mOrigObjPos = Ogre::Vector3(); - mGrabbedSceneNode = ""; - mCurrentObj = ""; - mOldPos = QPoint(0, 0); - mMouseEventTimer->invalidate(); - mOffset = 0.0f; - - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; - } - /* NO_DEFAULT_CASE */ - } - } - - //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down - //plane Y, upvector X, mOffset y : y-z plane, wheel left/right - //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further - std::pair MouseState::planeAxis() - { - const bool screenCoord = true; - Ogre::Vector3 dir = getCamera()->getDerivedDirection(); - - QString wheelDir = "Closer/Further"; - if(wheelDir == "Left/Right") - { - if(screenCoord) - return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedUp()); - else - return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z); - } - else if(wheelDir == "Up/Down") - { - if(screenCoord) - return std::make_pair(getCamera()->getDerivedUp(), Ogre::Vector3(-dir.x, -dir.y, -dir.z)); - else - return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X); - } - else - { - if(screenCoord) - return std::make_pair(Ogre::Vector3(-dir.x, -dir.y, -dir.z), getCamera()->getDerivedRight()); - else - return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); - } - } - - std::pair MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) - { - // using a really small value seems to mess up with the projections - float nearClipDistance = getCamera()->getNearClipDistance(); // save existing - getCamera()->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( - (float) pos.x() / getViewport()->getActualWidth(), - (float) pos.y() / getViewport()->getActualHeight()); - getCamera()->setNearClipDistance(nearClipDistance); // restore - std::pair planeResult = mouseRay.intersects(plane); - - if(planeResult.first) - return std::make_pair(true, mouseRay.getPoint(planeResult.second)); - else - return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small - } - - std::pair MouseState::terrainUnderCursor(const int mouseX, const int mouseY) - { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - // FIXME: is there a better way to distinguish terrain from objects? - QString name = QString(result.first.c_str()); - if(name.contains(QRegExp("^HeightField"))) - { - return result; - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) - { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - // NOTE: anything not terrain is assumed to be an object - QString name = QString(result.first.c_str()); - if(!name.contains(QRegExp("^HeightField"))) - { - uint32_t visibilityMask = getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && mSceneManager->hasSceneNode(result.first)) - { - return result; - } - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - void MouseState::updateSceneWidgets() - { - std::map sceneWidgets = mPhysics->sceneWidgets(); - - std::map::iterator iter = sceneWidgets.begin(); - for(; iter != sceneWidgets.end(); ++iter) - { - //(*iter).second->updateScene(); - } - } - - Ogre::Camera *MouseState::getCamera() - { - return 0;//mParent->getCamera(); - } - - Ogre::Viewport *MouseState::getViewport() - { - return 0;//mParent->getCamera()->getViewport(); - } -} diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp deleted file mode 100644 index 70e18427f3..0000000000 --- a/apps/opencs/view/render/mousestate.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef OPENCS_VIEW_MOUSESTATE_H -#define OPENCS_VIEW_MOUSESTATE_H - -#include -#include -#include -#include - -class QElapsedTimer; -class QMouseEvent; -class QWheelEvent; - -namespace Ogre -{ - class Plane; - class SceneManager; - class Camera; - class Viewport; -} - -namespace CSVWorld -{ - class PhysicsSystem; -} - -namespace CSMWorld -{ - class IdTable; -} - -namespace CSVRender -{ - class WorldspaceWidget; - - class MouseState - { - enum MouseStates - { - Mouse_Grab, - Mouse_Drag, - Mouse_Edit, - Mouse_Default - }; - MouseStates mMouseState; - - WorldspaceWidget *mParent; - boost::shared_ptr mPhysics; - Ogre::SceneManager *mSceneManager; // local copy - - QPoint mOldPos; - std::string mCurrentObj; - std::string mGrabbedSceneNode; - QElapsedTimer *mMouseEventTimer; - Ogre::Plane *mPlane; - Ogre::Vector3 mOrigObjPos; - Ogre::Vector3 mOrigMousePos; - Ogre::Vector3 mCurrentMousePos; - float mOffset; - - CSMWorld::IdTable *mIdTableModel; - int mColIndexPosX; - int mColIndexPosY; - int mColIndexPosZ; - - public: - - MouseState(WorldspaceWidget *parent); - ~MouseState(); - - void mouseMoveEvent (QMouseEvent *event); - void mousePressEvent (QMouseEvent *event); - void mouseReleaseEvent (QMouseEvent *event); - void mouseDoubleClickEvent (QMouseEvent *event); - bool wheelEvent (QWheelEvent *event); - - void cancelDrag(); - - private: - - std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); - std::pair terrainUnderCursor(const int mouseX, const int mouseY); - std::pair objectUnderCursor(const int mouseX, const int mouseY); - std::pair planeAxis(); - void updateSceneWidgets(); - - Ogre::Camera *getCamera(); // friend access - Ogre::Viewport *getViewport(); // friend access - }; -} - -#endif // OPENCS_VIEW_MOUSESTATE_H diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index bd44ba5772..9bc7aa2605 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -6,8 +6,6 @@ #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" -#include "../world/physicssystem.hpp" - #include #include "elements.hpp" @@ -63,25 +61,6 @@ void CSVRender::Object::update() mBaseNode->addChild(loader.load(file)); //mObject->setVisibilityFlags (Element_Reference); - - /* - if (mPhysics && !mReferenceId.empty()) - { - const CSMWorld::CellRef& reference = getReference(); - - // position - Ogre::Vector3 position; - if (!mForceBaseToZero) - position = Ogre::Vector3(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]); - - // orientation - Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); - } - */ } } @@ -121,9 +100,8 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const } CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, - const std::string& id, bool referenceable, boost::shared_ptr physics, - bool forceBaseToZero) -: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero), mPhysics(physics) + const std::string& id, bool referenceable, bool forceBaseToZero) +: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::Group; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 8e9598bbf2..431867d6b5 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -40,7 +40,6 @@ namespace CSVRender osg::Group* mParentNode; const VFS::Manager* mVFS; bool mForceBaseToZero; - boost::shared_ptr mPhysics; /// Not implemented Object (const Object&); @@ -64,7 +63,6 @@ namespace CSVRender Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, - boost::shared_ptr physics = boost::shared_ptr (), bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 84a5a5665b..ca4678d497 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -112,7 +112,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { #if 0 Cell *cell = new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace), mDocument.getPhysics()); + iter->getId (mWorldspace)); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 3be791f231..fd63567c78 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); + //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); + //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5ae5c8177f..68a3acdb91 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -16,13 +16,11 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" -#include "../world/physicssystem.hpp" - #include "elements.hpp" #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(boost::shared_ptr()), mMouse(0), +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mMouse(0), mInteractionMask (0) { setAcceptDrops(true); @@ -55,15 +53,12 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - mPhysics = document.getPhysics(); // create physics if one doesn't exist - //mPhysics->addSceneManager(getSceneManager(), this); - mMouse = new MouseState(this); + //mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { - delete mMouse; - //mPhysics->removeSceneManager(getSceneManager()); + //delete mMouse; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -370,7 +365,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) { - mMouse->mouseMoveEvent(event); + //mMouse->mouseMoveEvent(event); } SceneWidget::mouseMoveEvent(event); } @@ -379,7 +374,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) { - mMouse->mousePressEvent(event); + //mMouse->mousePressEvent(event); } //SceneWidget::mousePressEvent(event); } @@ -395,7 +390,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) return; } */ - mMouse->mouseReleaseEvent(event); + //mMouse->mouseReleaseEvent(event); } SceneWidget::mouseReleaseEvent(event); } @@ -404,14 +399,14 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - mMouse->mouseDoubleClickEvent(event); + //mMouse->mouseDoubleClickEvent(event); } //SceneWidget::mouseDoubleClickEvent(event); } void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - if(!mMouse->wheelEvent(event)) + //if(!mMouse->wheelEvent(event)) SceneWidget::wheelEvent(event); } @@ -419,7 +414,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { - mMouse->cancelDrag(); + //mMouse->cancelDrag(); } else SceneWidget::keyPressEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index b19197e36b..ea344f04aa 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -4,7 +4,6 @@ #include #include "scenewidget.hpp" -#include "mousestate.hpp" #include "navigation1st.hpp" #include "navigationfree.hpp" @@ -25,13 +24,10 @@ namespace CSVWidget class SceneToolRun; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { + class MouseState; + class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -42,7 +38,6 @@ namespace CSVRender CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - boost::shared_ptr mPhysics; MouseState *mMouse; unsigned int mInteractionMask; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp deleted file mode 100644 index 4e23c185ae..0000000000 --- a/apps/opencs/view/world/physicssystem.cpp +++ /dev/null @@ -1,325 +0,0 @@ -#include "physicssystem.hpp" - -#include - -#include -#include -#include - -#include -#include -#include "../../model/settings/usersettings.hpp" -#include "../render/elements.hpp" - -namespace CSVWorld -{ - PhysicsSystem::PhysicsSystem() - { - // Create physics. shapeLoader is deleted by the physic engine - //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); - //mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - mEngine = 0; - } - - PhysicsSystem::~PhysicsSystem() - { - delete mEngine; - } - - // looks up the scene manager based on the scene node name (inefficient) - // NOTE: referenceId is assumed to be unique per document - // NOTE: searching is done here rather than after rayTest, hence slower to load but - // faster to find (guessing, not verified w/ perf test) - void PhysicsSystem::addObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) - { - Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); - if(sceneManager) - { - // update maps (NOTE: sometimes replaced) - mSceneNodeToRefId[sceneNodeName] = referenceId; - mSceneNodeToMesh[sceneNodeName] = mesh; - mRefIdToSceneNode[referenceId][sceneManager] = sceneNodeName; - } - else - { - std::cerr << "Attempt to add an object without a corresponding SceneManager: " - + referenceId + " : " + sceneNodeName << std::endl; - return; - } - - // update physics, only one physics model per referenceId - if(mEngine->getRigidBody(referenceId, true) == NULL) - { - mEngine->createAndAdjustRigidBody(mesh, - referenceId, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); - } - } - - // normal delete (e.g closing a scene subview or ~Object()) - // the scene node is destroyed so the mappings should be removed - // - // TODO: should think about using some kind of reference counting within RigidBody - void PhysicsSystem::removeObject(const std::string &sceneNodeName) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - - if(referenceId != "") - { - mSceneNodeToRefId.erase(sceneNodeName); - mSceneNodeToMesh.erase(sceneNodeName); - - // find which SceneManager has this object - Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); - if(!sceneManager) - { - std::cerr << "Attempt to remove an object without a corresponding SceneManager: " - + sceneNodeName << std::endl; - return; - } - - // illustration: erase the object "K" from the object map - // - // RidigBody SubView Ogre - // --------------- -------------- ------------- - // ReferenceId "A" (SceneManager X SceneNode "J") - // (SceneManager Y SceneNode "K") <--- erase - // (SceneManager Z SceneNode "L") - // - // ReferenceId "B" (SceneManager X SceneNode "M") - // (SceneManager Y SceneNode "N") <--- notice not deleted - // (SceneManager Z SceneNode "O") - std::map >::iterator itRef = - mRefIdToSceneNode.begin(); - for(; itRef != mRefIdToSceneNode.end(); ++itRef) - { - if((*itRef).second.find(sceneManager) != (*itRef).second.end()) - { - (*itRef).second.erase(sceneManager); - break; - } - } - - // check whether the physics model should be deleted - if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) - { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - } - } - } - - // Object::clear() is called when reference data is changed. It clears all - // contents of the SceneNode and removes the physics object - // - // A new physics object will be created and assigned to this sceneNodeName by - // Object::update() - void PhysicsSystem::removePhysicsObject(const std::string &sceneNodeName) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - - if(referenceId != "") - { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - } - } - - void PhysicsSystem::replaceObject(const std::string &sceneNodeName, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) - { - std::string referenceId = mSceneNodeToRefId[sceneNodeName]; - std::string mesh = mSceneNodeToMesh[sceneNodeName]; - - if(referenceId != "") - { - // delete the physics object - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - - // create a new physics object - mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - 0, 0, true, placeable); - - // update other scene managers if they have the referenceId - // FIXME: rotation or scale not updated - moveSceneNodeImpl(sceneNodeName, referenceId, position); - } - } - - // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects - void PhysicsSystem::moveObject(const std::string &sceneNodeName, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) - { - mEngine->adjustRigidBody(mEngine->getRigidBody(sceneNodeName, true /*raycasting*/), - position, rotation); - } - - void PhysicsSystem::moveSceneNodeImpl(const std::string sceneNodeName, - const std::string referenceId, const Ogre::Vector3 &position) - { - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - std::string name = refIdToSceneNode(referenceId, (*iter).first); - if(name != sceneNodeName && (*iter).first->hasSceneNode(name)) - { - (*iter).first->getSceneNode(name)->setPosition(position); - } - } - } - - void PhysicsSystem::moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position) - { - moveSceneNodeImpl(sceneNodeName, sceneNodeToRefId(sceneNodeName), position); - } - - void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager, - float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) - { - std::string name = "HeightField_" - + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); - - if(mTerrain.find(name) == mTerrain.end()) - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); - - mTerrain.insert(std::pair(name, sceneManager)); - } - - void PhysicsSystem::removeHeightField(Ogre::SceneManager *sceneManager, int x, int y) - { - std::string name = "HeightField_" - + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); - - if(mTerrain.count(name) == 1) - mEngine->removeHeightField(x, y); - - std::multimap::iterator iter = mTerrain.begin(); - for(; iter != mTerrain.end(); ++iter) - { - if((*iter).second == sceneManager) - { - mTerrain.erase(iter); - break; - } - } - } - - // sceneMgr: to lookup the scene node name from the object's referenceId - // camera: primarily used to get the visibility mask for the viewport - // - // returns the found object's scene node name and its position in the world space - // - // WARNING: far clip distance is a global setting, if it changes in future - // this method will need to be updated - std::pair PhysicsSystem::castRay(float mouseX, - float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera) - { - // NOTE: there could be more than one camera for the scene manager - // TODO: check whether camera belongs to sceneMgr - if(!sceneMgr || !camera || !camera->getViewport()) - return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception - - // using a really small value seems to mess up with the projections - float nearClipDistance = camera->getNearClipDistance(); // save existing - camera->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); - camera->setNearClipDistance(nearClipDistance); // restore - - Ogre::Vector3 from = ray.getOrigin(); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); - Ogre::Vector3 to = ray.getPoint(farClipDist); - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - uint32_t visibilityMask = camera->getViewport()->getVisibilityMask(); - bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - Ogre::Vector3 norm; // not used - std::pair result = - mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); - - // result.first is the object's referenceId - if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); - else - { - std::string name = refIdToSceneNode(result.first, sceneMgr); - if(name == "") - name = result.first; - else - name = refIdToSceneNode(result.first, sceneMgr); - - return std::make_pair(name, ray.getPoint(farClipDist*result.second)); - } - } - - std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) - { - return mRefIdToSceneNode[referenceId][sceneMgr]; - } - - std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName) - { - return mSceneNodeToRefId[sceneNodeName]; - } - - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget *sceneWidget) - { - mSceneWidgets[sceneMgr] = sceneWidget; - - mEngine->createDebugDraw(sceneMgr); - } - - std::map PhysicsSystem::sceneWidgets() - { - return mSceneWidgets; - } - - void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) - { - mEngine->removeDebugDraw(sceneMgr); - - mSceneWidgets.erase(sceneMgr); - } - - Ogre::SceneManager *PhysicsSystem::findSceneManager(std::string sceneNodeName) - { - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - if((*iter).first->hasSceneNode(sceneNodeName)) - { - return (*iter).first; - } - } - - return NULL; - } - - void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) - { - // FIXME: should check if sceneMgr is in the list - if(!sceneMgr) - return; - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) - { - std::cerr << "Turn on mouse-picking debug option to see collision shapes." << std::endl; - return; - } - - mEngine->toggleDebugRendering(sceneMgr); - mEngine->stepDebug(sceneMgr); - } -} diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp deleted file mode 100644 index 0036bf769d..0000000000 --- a/apps/opencs/view/world/physicssystem.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef CSV_WORLD_PHYSICSSYSTEM_H -#define CSV_WORLD_PHYSICSSYSTEM_H - -#include -#include - -namespace Ogre -{ - class Vector3; - class Quaternion; - class SceneManager; - class Camera; -} - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -namespace CSVRender -{ - class SceneWidget; -} - -namespace CSVWorld -{ - class PhysicsSystem - { - std::map mSceneNodeToRefId; - std::map > mRefIdToSceneNode; - std::map mSceneNodeToMesh; - std::map mSceneWidgets; - OEngine::Physic::PhysicEngine* mEngine; - std::multimap mTerrain; - - public: - - PhysicsSystem(); - ~PhysicsSystem(); - - void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); - - void removeSceneManager(Ogre::SceneManager *sceneMgr); - - void addObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - bool placeable=false); - - void removeObject(const std::string &sceneNodeName); - void removePhysicsObject(const std::string &sceneNodeName); - - void replaceObject(const std::string &sceneNodeName, - float scale, const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, bool placeable=false); - - void moveObject(const std::string &sceneNodeName, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); - - void moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position); - - void addHeightField(Ogre::SceneManager *sceneManager, - float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts); - - void removeHeightField(Ogre::SceneManager *sceneManager, int x, int y); - - void toggleDebugRendering(Ogre::SceneManager *sceneMgr); - - // return the object's SceneNode name and position for the given SceneManager - std::pair castRay(float mouseX, - float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); - - std::string sceneNodeToRefId(std::string sceneNodeName); - - // for multi-scene manager per physics engine - std::map sceneWidgets(); - - private: - - void moveSceneNodeImpl(const std::string sceneNodeName, - const std::string referenceId, const Ogre::Vector3 &position); - - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - - std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); - - Ogre::SceneManager *findSceneManager(std::string sceneNodeName); - }; -} - -#endif // CSV_WORLD_PHYSICSSYSTEM_H From 72400747f24722a2f05fb9015f23b40cf107da69 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 23:35:10 +0100 Subject: [PATCH 0067/1812] OpenCS: preliminary port of cell rendering to OSG --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 5 + apps/opencs/model/world/data.hpp | 7 + apps/opencs/model/world/resources.cpp | 2 - apps/opencs/model/world/resourcesmanager.cpp | 11 + apps/opencs/model/world/resourcesmanager.hpp | 5 + apps/opencs/view/render/cell.cpp | 26 +- apps/opencs/view/render/cell.hpp | 12 +- apps/opencs/view/render/object.cpp | 48 +-- apps/opencs/view/render/object.hpp | 5 +- .../view/render/pagedworldspacewidget.cpp | 173 +-------- .../view/render/pagedworldspacewidget.hpp | 7 - apps/opencs/view/render/previewwidget.cpp | 5 +- apps/opencs/view/render/scenewidget.cpp | 4 + apps/opencs/view/render/textoverlay.cpp | 359 ------------------ apps/opencs/view/render/textoverlay.hpp | 66 ---- .../view/render/unpagedworldspacewidget.cpp | 11 +- apps/opencs/view/render/worldspacewidget.cpp | 4 - 18 files changed, 97 insertions(+), 655 deletions(-) delete mode 100644 apps/opencs/view/render/textoverlay.cpp delete mode 100644 apps/opencs/view/render/textoverlay.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4f6b2a875d..4e360f6ebd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay + lightingbright object cell terrainstorage ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 67f6822c7c..07b18cc235 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -970,3 +970,8 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) { emit idListChanged(); } + +const VFS::Manager* CSMWorld::Data::getVFS() const +{ + return mResourcesManager.getVFS(); +} diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 02f7bc4526..bb4c9a4a80 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -45,6 +45,11 @@ class QAbstractItemModel; +namespace VFS +{ + class Manager; +} + namespace ESM { class ESMReader; @@ -121,6 +126,8 @@ namespace CSMWorld virtual ~Data(); + const VFS::Manager* getVFS() const; + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 158793173b..4dd480e773 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 218937924d..3e2f72d93d 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -3,6 +3,11 @@ #include +CSMWorld::ResourcesManager::ResourcesManager() + : mVFS(NULL) +{ +} + void CSMWorld::ResourcesManager::addResources (const Resources& resources) { mResources.insert (std::make_pair (resources.getType(), resources)); @@ -12,6 +17,7 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) { + mVFS = vfs; mResources.clear(); static const char * const sMeshTypes[] = { "nif", 0 }; @@ -24,6 +30,11 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } +const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +{ + return mVFS; +} + const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const { std::map::const_iterator iter = mResources.find (type); diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index ee939389f9..1ce06f2d3d 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,6 +16,7 @@ namespace CSMWorld class ResourcesManager { std::map mResources; + const VFS::Manager* mVFS; private: @@ -23,6 +24,10 @@ namespace CSMWorld public: + ResourcesManager(); + + const VFS::Manager* getVFS() const; + void setVFS(const VFS::Manager* vfs); const Resources& get (UniversalId::Type type) const; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 28ce1dd6cc..2c540dee65 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,8 +1,7 @@ #include "cell.hpp" -#include -#include +#include #include #include @@ -50,7 +49,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - //mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); modified = true; } } @@ -58,12 +57,11 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mX(0), mY(0) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) { - mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); - mCellNode->setPosition (origin); + mCellNode = new osg::Group; + rootNode->addChild(mCellNode); CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -72,6 +70,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, addObjects (0, rows-1); + /* const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) @@ -84,14 +83,15 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, mTerrain->loadCell(esmLand->mX, esmLand->mY); - float verts = ESM::Land::LAND_SIZE; - float worldsize = ESM::Land::REAL_SIZE; + //float verts = ESM::Land::LAND_SIZE; + //float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; //mPhysics->addHeightField(sceneManager, // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } + */ } CSVRender::Cell::~Cell() @@ -103,7 +103,7 @@ CSVRender::Cell::~Cell() iter!=mObjects.end(); ++iter) delete iter->second; - mCellNode->getCreator()->destroySceneNode (mCellNode); + mCellNode->getParent(0)->removeChild(mCellNode); } bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft, @@ -190,8 +190,8 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, // add new objects for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { - //mObjects.insert (std::make_pair ( - // iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + mObjects.insert (std::make_pair ( + iter->first, new Object (mData, mCellNode, iter->first, false))); modified = true; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 8c7d7e23ae..259ab1779e 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -7,7 +7,7 @@ #include -#include +#include #ifndef Q_MOC_RUN #include @@ -17,10 +17,9 @@ class QModelIndex; -namespace Ogre +namespace osg { - class SceneManager; - class SceneNode; + class Group; } namespace CSMWorld @@ -34,10 +33,9 @@ namespace CSVRender { CSMWorld::Data& mData; std::string mId; - Ogre::SceneNode *mCellNode; + osg::ref_ptr mCellNode; std::map mObjects; std::auto_ptr mTerrain; - Ogre::SceneManager *mSceneMgr; int mX; int mY; @@ -53,7 +51,7 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); ~Cell(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 9bc7aa2605..50c227d494 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,6 +1,9 @@ #include "object.hpp" +#include + #include +#include #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" @@ -51,14 +54,23 @@ void CSVRender::Object::update() } else { - NifOsg::Loader loader; - loader.resourceManager = mVFS; + try + { + NifOsg::Loader loader; + loader.resourceManager = mVFS; - std::string path = "meshes\\" + model; + std::string path = "meshes\\" + model; - Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); - mBaseNode->addChild(loader.load(file)); + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + mBaseNode->addChild(loader.load(file)); + } + catch (std::exception& e) + { + // TODO: use error marker mesh + std::cerr << e.what() << std::endl; + } //mObject->setVisibilityFlags (Element_Reference); } @@ -66,29 +78,21 @@ void CSVRender::Object::update() void CSVRender::Object::adjust() { - /* if (mReferenceId.empty()) return; const CSMWorld::CellRef& reference = getReference(); // position - if (!mForceBaseToZero) - mBase->setPosition (Ogre::Vector3 ( - reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); + mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); // orientation - Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); + osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0)); + osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0)); + osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1)); + mBaseNode->setAttitude(zr*yr*xr); - Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - - Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - mBase->setOrientation (xr*yr*zr); - - // scale - mBase->setScale (reference.mScale, reference.mScale, reference.mScale); - */ + mBaseNode->setScale(osg::Vec3(reference.mScale, reference.mScale, reference.mScale)); } const CSMWorld::CellRef& CSVRender::Object::getReference() const @@ -99,11 +103,11 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group* parentNode, +CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mVFS(vfs), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mVFS(data.getVFS()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { - mBaseNode = new osg::Group; + mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); if (referenceable) diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 431867d6b5..9efbcf5dc4 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -10,6 +10,7 @@ class QModelIndex; namespace osg { + class PositionAttitudeTransform; class Group; } @@ -36,7 +37,7 @@ namespace CSVRender const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; - osg::ref_ptr mBaseNode; + osg::ref_ptr mBaseNode; osg::Group* mParentNode; const VFS::Manager* mVFS; bool mForceBaseToZero; @@ -61,7 +62,7 @@ namespace CSVRender public: - Object (const VFS::Manager* vfs, const CSMWorld::Data& data, osg::Group *cellNode, + Object (const CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ca4678d497..737a64efaa 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -5,16 +5,9 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include "textoverlay.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -29,7 +22,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; - //bool setCamera = false; const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -44,17 +36,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (!mSelection.has (iter->first) || index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) { - // delete overlays - std::map::iterator itOverlay = mTextOverlays.find(iter->first); - if(itOverlay != mTextOverlays.end()) - { - delete itOverlay->second; - mTextOverlays.erase(itOverlay); - } - - // destroy manual objects - //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); - delete iter->second; mCells.erase (iter++); @@ -64,43 +45,16 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { // check if name or region field has changed // FIXME: config setting - std::string name = cells.getRecord(index).get().mName; - std::string region = cells.getRecord(index).get().mRegion; + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + // cell marker update goes here - std::map::iterator it = mTextOverlays.find(iter->first); - if(it != mTextOverlays.end()) - { - if(it->second->getDesc() != "") // previously had name - { - if(name != it->second->getDesc()) // new name - { - if(name != "") - it->second->setDesc(name); - else // name deleted, use region - it->second->setDesc(region); - it->second->update(); - } - } - else if(name != "") // name added - { - it->second->setDesc(name); - it->second->update(); - } - else if(region != it->second->getDesc()) // new region - { - it->second->setDesc(region); - it->second->update(); - } - modified = true; - } ++iter; } } } - //if (mCells.begin()==mCells.end()) - //setCamera = true; - // add for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) @@ -110,113 +64,20 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { -#if 0 - Cell *cell = new Cell (mDocument.getData(), getSceneManager(), + Cell *cell = new Cell (mDocument.getData(), mRootNode, iter->getId (mWorldspace)); mCells.insert (std::make_pair (*iter, cell)); - float height = cell->getTerrainHeightAt(Ogre::Vector3( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - 0)); - if (setCamera) - { - setCamera = false; - getCamera()->setPosition ( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height); - // better camera position at the start - getCamera()->move(getCamera()->getDirection() * -6000); // FIXME: config setting - } - - Ogre::ManualObject* manual = - getSceneManager()->createManualObject("manual" + iter->getId(mWorldspace)); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - // define start and end point (x, y, z) - manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height); - manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height+200); // FIXME: config setting - manual->end(); - manual->setBoundingBox(Ogre::AxisAlignedBox( - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height, - ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, - ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, - height+200)); - getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - manual->setVisible(false); - - CSVRender::TextOverlay *textDisp = - new CSVRender::TextOverlay(manual, getCamera(), iter->getId(mWorldspace)); - textDisp->enable(true); - textDisp->setCaption(iter->getId(mWorldspace)); - std::string desc = cells.getRecord(index).get().mName; - if(desc == "") desc = cells.getRecord(index).get().mRegion; - textDisp->setDesc(desc); // FIXME: config setting - textDisp->update(); - mTextOverlays.insert(std::make_pair(*iter, textDisp)); - /* - if(!mOverlayMask) - { - mOverlayMask = new OverlayMask(mTextOverlays, getViewport()); - addRenderTargetListener(mOverlayMask); - } - */ - -#endif - modified = true; } } + if (modified) + mView->setCameraManipulator(new osgGA::TrackballManipulator); + return modified; } -void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) -{ - if(event->button() == Qt::RightButton) - { - std::map::iterator iter = mTextOverlays.begin(); - for(; iter != mTextOverlays.end(); ++iter) - { - if(mDisplayCellCoord && - iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) - { - return; - } - } - } - WorldspaceWidget::mousePressEvent(event); -} - -void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) -{ - if(event->button() == Qt::RightButton) - { - std::map::iterator iter = mTextOverlays.begin(); - for(; iter != mTextOverlays.end(); ++iter) - { - if(mDisplayCellCoord && - iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) - { - std::cout << "clicked: " << iter->second->getCaption() << std::endl; - return; - } - } - } - WorldspaceWidget::mouseReleaseEvent(event); -} - -void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) -{ - WorldspaceWidget::mouseDoubleClickEvent(event); -} - void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { @@ -346,23 +207,7 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() iter!=mCells.end(); ++iter) { delete iter->second; - - //getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); } - - for (std::map::iterator iter (mTextOverlays.begin()); - iter != mTextOverlays.end(); ++iter) - { - delete iter->second; - } - - /* - if(mOverlayMask) - { - removeRenderTargetListener(mOverlayMask); - delete mOverlayMask; - } - */ } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 1bc9c3c5c8..64a0bccd1a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -28,7 +28,6 @@ namespace CSVRender std::string mWorldspace; CSVWidget::SceneToolToggle *mControlElements; bool mDisplayCellCoord; - std::map mTextOverlays; private: @@ -86,12 +85,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void mousePressEvent (QMouseEvent *event); - - virtual void mouseReleaseEvent (QMouseEvent *event); - - virtual void mouseDoubleClickEvent (QMouseEvent *event); - signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index c3f8384353..22185effc5 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -1,9 +1,6 @@ #include "previewwidget.hpp" -#include -#include - #include #include "../../model/world/data.hpp" @@ -11,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), mObject(vfs, data, mRootNode, id, referenceable) +: SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) { //setNavigation (&mOrbit); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 195e550a32..98ddf67c3b 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -58,6 +58,10 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; + // TODO: move to utility file + mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + mView->setSceneData(mRootNode); // Press S to reveal profiling stats diff --git a/apps/opencs/view/render/textoverlay.cpp b/apps/opencs/view/render/textoverlay.cpp deleted file mode 100644 index 656ea959c7..0000000000 --- a/apps/opencs/view/render/textoverlay.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include "textoverlay.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace CSVRender -{ - -// Things to do: -// - configurable font size in pixels (automatically calulate everything else from it) -// - configurable texture to use -// - try material script -// - decide whether to use QPaint (http://www.ogre3d.org/tikiwiki/Ogre+overlays+using+Qt) - -// http://www.ogre3d.org/tikiwiki/ObjectTextDisplay -// http://www.ogre3d.org/tikiwiki/MovableTextOverlay -// http://www.ogre3d.org/tikiwiki/Creating+dynamic+textures -// http://www.ogre3d.org/tikiwiki/ManualObject -TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String& id) - : mOverlay(0), mCaption(""), mDesc(""), mEnabled(true), mCamera(camera), mObj(obj), mId(id) - , mOnScreen(false) , mInstance(0), mFontHeight(16) // FIXME: make font height configurable -{ - if(id == "" || !camera || !obj) - throw std::runtime_error("TextOverlay could not be created."); - - // setup font - Ogre::FontManager &fontMgr = Ogre::FontManager::getSingleton(); - if (fontMgr.resourceExists("DejaVuLGC")) - mFont = fontMgr.getByName("DejaVuLGC","General"); - else - { - mFont = fontMgr.create("DejaVuLGC","General"); - mFont->setType(Ogre::FT_TRUETYPE); - mFont->setSource("DejaVuLGCSansMono.ttf"); - mFont->setTrueTypeSize(mFontHeight); - mFont->setTrueTypeResolution(96); - } - if(!mFont.isNull()) - mFont->load(); - else - throw std::runtime_error("TextOverlay font not loaded."); - - // setup overlay - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - // FIXME: this logic is badly broken as it is possible to delete an earlier instance - while(mOverlay != NULL) - { - mInstance++; - mOverlay = overlayMgr.getByName("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - } - mOverlay = overlayMgr.create("CellIDPanel"+mId+Ogre::StringConverter::toString(mInstance)); - - // create texture - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTransBlue"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTransBlue", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - Ogre::uint8* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent blue, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 0; // G - *pDest++ = 0; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - - // setup material for containers - Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().getByName( - "TransOverlayMaterial"); - if(mQuadMaterial.isNull()) - { - Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().create( - "TransOverlayMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = mQuadMaterial->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("MyCustomState", 0); - tex->setTextureName("DynamicTransBlue"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - mQuadMaterial->load(); - } - - mContainer = static_cast(overlayMgr.createOverlayElement( - "Panel", "container"+mId +"#"+Ogre::StringConverter::toString(mInstance))); - mContainer->setMaterialName("TransOverlayMaterial"); - mOverlay->add2D(mContainer); - - // setup text area overlay element - mElement = static_cast(overlayMgr.createOverlayElement( - "TextArea", "text"+mId +"#"+Ogre::StringConverter::toString(mInstance))); - mElement->setMetricsMode(Ogre::GMM_RELATIVE); - mElement->setDimensions(1.0, 1.0); - mElement->setMetricsMode(Ogre::GMM_PIXELS); - mElement->setPosition(2*fontHeight()/3, 1.3*fontHeight()/3); // 1.3 & 2 = fudge factor - - mElement->setFontName("DejaVuLGC"); - mElement->setCharHeight(fontHeight()); // NOTE: seems that this is required as well as font->setTrueTypeSize() - mElement->setHorizontalAlignment(Ogre::GHA_LEFT); - //mElement->setColour(Ogre::ColourValue(1.0, 1.0, 1.0)); // R, G, B - mElement->setColour(Ogre::ColourValue(1.0, 1.0, 0)); // yellow - - mContainer->addChild(mElement); - mOverlay->show(); -} - -void TextOverlay::getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y) -{ - Ogre::Vector3 hcsPosition = mCamera->getProjectionMatrix() * (mCamera->getViewMatrix() * position); - - x = 1.0f - ((hcsPosition.x * 0.5f) + 0.5f); // 0 <= x <= 1 // left := 0,right := 1 - y = ((hcsPosition.y * 0.5f) + 0.5f); // 0 <= y <= 1 // bottom := 0,top := 1 -} - -void TextOverlay::getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY, - bool top) -{ - MinX = 0, MinY = 0, MaxX = 0, MaxY = 0; - float X[4]; // the 2D dots of the AABB in screencoordinates - float Y[4]; - - if(!mObj->isInScene()) - return; - - const Ogre::AxisAlignedBox &AABB = mObj->getWorldBoundingBox(true); // the AABB of the target - Ogre::Vector3 cornersOfAABB[4]; - if(top) - { - cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_TOP); - cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_TOP); - cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_TOP); - cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_TOP); - } - else - { - cornersOfAABB[0] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_BOTTOM); - cornersOfAABB[1] = AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_BOTTOM); - cornersOfAABB[2] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_BOTTOM); - cornersOfAABB[3] = AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_BOTTOM); - } - - //The normal vector of the plane. This points directly infront of the camera. - Ogre::Vector3 cameraPlainNormal = mCamera->getDerivedOrientation().zAxis(); - - //the plane that devides the space before and behind the camera. - Ogre::Plane CameraPlane = Ogre::Plane(cameraPlainNormal, mCamera->getDerivedPosition()); - - for (int i = 0; i < 4; i++) - { - X[i] = 0; - Y[i] = 0; - - getScreenCoordinates(cornersOfAABB[i],X[i],Y[i]); // transfor into 2d dots - - if (CameraPlane.getSide(cornersOfAABB[i]) == Ogre::Plane::NEGATIVE_SIDE) - { - if (i == 0) // accept the first set of values, no matter how bad it might be. - { - MinX = X[i]; - MinY = Y[i]; - MaxX = X[i]; - MaxY = Y[i]; - } - else // now compare if you get "better" values - { - if (MinX > X[i]) MinX = X[i]; - if (MinY > Y[i]) MinY = Y[i]; - if (MaxX < X[i]) MaxX = X[i]; - if (MaxY < Y[i]) MaxY = Y[i]; - } - } - else - { - MinX = 0; - MinY = 0; - MaxX = 0; - MaxY = 0; - break; - } - } -} - -TextOverlay::~TextOverlay() -{ - Ogre::OverlayManager::OverlayMapIterator iter = Ogre::OverlayManager::getSingleton().getOverlayIterator(); - if(!iter.hasMoreElements()) - mOverlay->hide(); - - Ogre::OverlayManager *overlayMgr = Ogre::OverlayManager::getSingletonPtr(); - mContainer->removeChild("text"+mId+"#"+Ogre::StringConverter::toString(mInstance)); - mOverlay->remove2D(mContainer); - - if(!iter.hasMoreElements()) - overlayMgr->destroy(mOverlay); -} - -void TextOverlay::show(bool show) -{ - if(show && mOnScreen) - mContainer->show(); - else - mContainer->hide(); -} - -void TextOverlay::enable(bool enable) -{ - if(enable == mOverlay->isVisible()) - return; - - mEnabled = enable; - if(enable) - mOverlay->show(); - else - mOverlay->hide(); -} - -bool TextOverlay::isEnabled() -{ - return mEnabled; -} - -void TextOverlay::setCaption(const Ogre::String& text) -{ - if(mCaption == text) - return; - - mCaption = text; - mElement->setCaption(text); -} - -void TextOverlay::setDesc(const Ogre::String& text) -{ - if(mDesc == text) - return; - - mDesc = text; - mElement->setCaption(mCaption + ((text == "") ? "" : ("\n" + text))); -} - -Ogre::FontPtr TextOverlay::getFont() -{ - return mFont; -} - -int TextOverlay::textWidth() -{ - float captionWidth = 0; - float descWidth = 0; - - for(Ogre::String::const_iterator i = mCaption.begin(); i < mCaption.end(); ++i) - { - if(*i == 0x0020) - captionWidth += getFont()->getGlyphAspectRatio(0x0030); - else - captionWidth += getFont()->getGlyphAspectRatio(*i); - } - - for(Ogre::String::const_iterator i = mDesc.begin(); i < mDesc.end(); ++i) - { - if(*i == 0x0020) - descWidth += getFont()->getGlyphAspectRatio(0x0030); - else - descWidth += getFont()->getGlyphAspectRatio(*i); - } - - captionWidth *= fontHeight(); - descWidth *= fontHeight(); - - return (int) std::max(captionWidth, descWidth); -} - -int TextOverlay::fontHeight() -{ - return mFontHeight; -} - -void TextOverlay::update() -{ - float min_x, max_x, min_y, max_y; - getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y, false); - - if ((min_x>0.0) && (max_x<1.0) && (min_y>0.0) && (max_y<1.0)) - { - mOnScreen = true; - mContainer->show(); - } - else - { - mOnScreen = false; - mContainer->hide(); - return; - } - - getMinMaxEdgesOfAABBIn2D(min_x, min_y, max_x, max_y); - - Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); - float viewportWidth = std::max(overlayMgr.getViewportWidth(), 1); // zero at the start - float viewportHeight = std::max(overlayMgr.getViewportHeight(), 1); // zero at the start - - int width = fontHeight()*2/3 + textWidth() + fontHeight()*2/3; // add margins - int height = fontHeight()/3 + fontHeight() + fontHeight()/3; - if(mDesc != "") - height = fontHeight()/3 + 2*fontHeight() + fontHeight()/3; - - float relTextWidth = width / viewportWidth; - float relTextHeight = height / viewportHeight; - - float posX = 1 - (min_x + max_x + relTextWidth)/2; - float posY = 1 - max_y - (relTextHeight-fontHeight()/3/viewportHeight); - - mContainer->setMetricsMode(Ogre::GMM_RELATIVE); - mContainer->setPosition(posX, posY); - mContainer->setDimensions(relTextWidth, relTextHeight); - - mPos = QRect(posX*viewportWidth, posY*viewportHeight, width, height); -} - -QRect TextOverlay::container() -{ - return mPos; -} - -} diff --git a/apps/opencs/view/render/textoverlay.hpp b/apps/opencs/view/render/textoverlay.hpp deleted file mode 100644 index dbb347e567..0000000000 --- a/apps/opencs/view/render/textoverlay.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef OPENCS_VIEW_TEXTOVERLAY_H -#define OPENCS_VIEW_TEXTOVERLAY_H - -#include - -#include -#include - -namespace Ogre -{ - class MovableObject; - class Camera; - class Font; - class Overlay; - class OverlayContainer; - class TextAreaOverlayElement; -} - -namespace CSVRender -{ - - class TextOverlay - { - Ogre::Overlay* mOverlay; - Ogre::OverlayContainer* mContainer; - Ogre::TextAreaOverlayElement* mElement; - Ogre::String mCaption; - Ogre::String mDesc; - - const Ogre::MovableObject* mObj; - const Ogre::Camera* mCamera; - Ogre::FontPtr mFont; - int mFontHeight; // in pixels - Ogre::String mId; - QRect mPos; - - bool mEnabled; - bool mOnScreen; - int mInstance; - - Ogre::FontPtr getFont(); - int textWidth(); - int fontHeight(); - void getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y); - void getMinMaxEdgesOfAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY, - bool top = true); - - public: - - TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String &id); - virtual ~TextOverlay(); - - void enable(bool enable); // controlled from scene widget toolbar visibility mask - void show(bool show); // for updating from render target listener - bool isEnabled(); - void setCaption(const Ogre::String& text); - void setDesc(const Ogre::String& text); - void update(); - QRect container(); // for detection of mouse click on the overlay - Ogre::String getCaption() { return mCaption; } // FIXME: debug - Ogre::String getDesc() { return mDesc; } - }; - -} - -#endif // OPENCS_VIEW_TEXTOVERLAY_H diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index fd63567c78..46c010fd2c 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -3,8 +3,7 @@ #include -#include -#include +#include #include @@ -49,7 +48,10 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - //mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); + + mView->setCameraManipulator(new osgGA::TrackballManipulator); + //mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +93,8 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - //mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); + // FIXME: we shouldn't need to rebuild the whole cell + mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 68a3acdb91..f5068bb473 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -3,10 +3,6 @@ #include -#include -#include -#include - #include #include "../../model/world/universalid.hpp" From 5fb8877746541e1ed79bbc259802515281cca3f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:11:23 +0100 Subject: [PATCH 0068/1812] Don't set the root node to dynamic --- apps/nifosgtest/test.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 0f2e43a563..dec0388253 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -41,9 +41,17 @@ public: osg::PolygonMode* mode = new osg::PolygonMode; mode->setMode(osg::PolygonMode::FRONT_AND_BACK, mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - mNode->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); - mNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); + + // Create a new stateset instead of changing the old one, this alleviates the need to set + // the StateSet to DYNAMIC DataVariance, which would have a performance impact. + + osg::StateSet* stateset = new osg::StateSet; + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + mNode->setStateSet(stateset); + return true; } default: @@ -138,10 +146,6 @@ int main(int argc, char** argv) // Mask to separate cull visitors from update visitors viewer.getCamera()->setCullMask(~(0x1)); - // We're going to change this from the event callback, set the variance to DYNAMIC so that - // we don't interfere with the draw thread. - root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); - viewer.addEventHandler(new osgViewer::StatsHandler); while (!viewer.done()) From 1edccdbe5573e1049c1ca8409d550d17bf180bc9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:27:39 +0100 Subject: [PATCH 0069/1812] OpenCS: apply visibility flags to osg node --- apps/opencs/view/render/object.cpp | 5 +++-- apps/opencs/view/render/scenewidget.cpp | 6 ++++++ apps/opencs/view/render/scenewidget.hpp | 2 ++ apps/opencs/view/render/worldspacewidget.cpp | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 50c227d494..f8e91e463b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -71,8 +71,6 @@ void CSVRender::Object::update() // TODO: use error marker mesh std::cerr << e.what() << std::endl; } - - //mObject->setVisibilityFlags (Element_Reference); } } @@ -110,6 +108,9 @@ CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask(Element_Reference<<1); + if (referenceable) { mReferenceableId = id; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 98ddf67c3b..16ad2e68a3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -84,6 +84,12 @@ void SceneWidget::flagAsModified() mView->requestRedraw(); } +void SceneWidget::setVisibilityMask(int mask) +{ + // 0x1 reserved for separating cull and update visitors + mView->getCamera()->setCullMask(mask<<1); +} + CompositeViewer::CompositeViewer() { #if QT_VERSION >= 0x050000 diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index adb10b10ac..04025340d3 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -37,6 +37,8 @@ namespace CSVRender void flagAsModified(); + void setVisibilityMask(int mask); + protected: osg::ref_ptr mView; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f5068bb473..1026aab588 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -348,7 +348,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::elementSelectionChanged() { - //setVisibilityMask (getVisibilityMask()); + setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); } From e3bfbcb44b7f09686f9365cd38cd9cdada9c2db5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 00:55:58 +0100 Subject: [PATCH 0070/1812] OpenCS: connect navigation button to OSG camera manipulators --- .../view/render/pagedworldspacewidget.cpp | 8 ++------ apps/opencs/view/render/previewwidget.cpp | 4 +--- apps/opencs/view/render/previewwidget.hpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 7 ++----- apps/opencs/view/render/worldspacewidget.cpp | 18 ++++++++---------- apps/opencs/view/render/worldspacewidget.hpp | 3 --- apps/opencs/view/world/previewsubview.cpp | 4 ++-- 7 files changed, 16 insertions(+), 30 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 737a64efaa..2b53483ada 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -171,19 +171,15 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { - /* - Ogre::Vector3 position = getCamera()->getPosition(); - + osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); std::ostringstream stream; stream << "player->position " - << position.x << ", " << position.y << ", " << position.z + << position.x() << ", " << position.y() << ", " << position.z() << ", 0"; return stream.str(); - */ - return ""; } CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 22185effc5..02fcd9f060 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -6,12 +6,10 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" -CSVRender::PreviewWidget::PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, +CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) { - //setNavigation (&mOrbit); - mView->setCameraManipulator(new osgGA::TrackballManipulator); QAbstractItemModel *referenceables = diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index dfe05b4843..58a7d8552d 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -30,7 +30,7 @@ namespace CSVRender public: - PreviewWidget (const VFS::Manager* vfs, CSMWorld::Data& data, const std::string& id, bool referenceable, + PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 46c010fd2c..e48b84cffb 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,19 +166,16 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { - /* - Ogre::Vector3 position = getCamera()->getPosition(); + osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); std::ostringstream stream; stream << "player->positionCell " - << position.x << ", " << position.y << ", " << position.z + << position.x() << ", " << position.y() << ", " << position.z() << ", 0, \"" << mCellId << "\""; return stream.str(); - */ - return ""; } CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1026aab588..4bbfd5bcdc 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -5,6 +5,9 @@ #include +#include +#include + #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -16,7 +19,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mMouse(0), +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mInteractionMask (0) { setAcceptDrops(true); @@ -48,32 +51,27 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&))); connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - - //mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { - //delete mMouse; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { - /* if (mode=="1st") - setNavigation (&m1st); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); else if (mode=="free") - setNavigation (&mFree); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); else if (mode=="orbit") - setNavigation (&mOrbit); - */ + mView->setCameraManipulator(new osgGA::OrbitManipulator); } void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {} void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() { - //setNavigation (&m1st); + mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ea344f04aa..e935daae26 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -26,8 +26,6 @@ namespace CSVWidget namespace CSVRender { - class MouseState; - class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -38,7 +36,6 @@ namespace CSVRender CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - MouseState *mMouse; unsigned int mInteractionMask; public: diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index c82d1b82e4..0c9823c444 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo referenceableIdChanged (referenceableId); mScene = - new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), false, this); + new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this); } else - mScene = new CSVRender::PreviewWidget (document.getVFS(), document.getData(), id.getId(), true, this); + mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this); CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); From 99c9907ff397f0901b45b955f4e46a77b4b65867 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 17:38:17 +0100 Subject: [PATCH 0071/1812] Fix emitter/particlesystem scene graph order problems --- components/nifosg/nifloader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index bdd40e2453..df912728b7 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -468,6 +468,7 @@ namespace NifOsg nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr skel = new osgAnimation::Skeleton; + skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); return skel; @@ -609,8 +610,7 @@ namespace NifOsg { if(!children[i].empty()) { - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - transformNode->insertChild(0, + transformNode->addChild( handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); } } @@ -1077,11 +1077,18 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + // Note the RigGeometry's UpdateCallback uses the skeleton space bone matrix, so the bone UpdateCallback has to be fired first. + // For this to work properly, all bones used for skinning a RigGeometry need to be created before that RigGeometry. + // All NIFs I've checked seem to conform to this restriction, perhaps Gamebryo update method works similarly. + // If a file violates this assumption, the worst that could happen is the bone position being a frame late. + // If this happens, we should get a warning from the Skeleton's validation update callback on the error log. osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones // For more accuracy the skinning should be relative to the parent of the first skinned bone, // rather than the root bone. + // TODO: calculate a correct bounding box based on the bone positions every frame in a ComputeBoundingBoxCallback osg::BoundingBox box = geometry->getBound(); box.expandBy(box._min-(box._max-box._min)/2); box.expandBy(box._max+(box._max-box._min)/2); From 60f288195fcbe2214f548aecb152c252b03cebf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 17:39:33 +0100 Subject: [PATCH 0072/1812] Fix for copy construction of particle system templates --- components/nifosg/particle.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 0afbf5e95f..791847cd67 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -23,6 +23,9 @@ ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp &co : osgParticle::ParticleSystem(copy, copyop) , mQuota(copy.mQuota) { + // For some reason the osgParticle constructor doesn't copy the particles + for (int i=0;i Date: Thu, 26 Mar 2015 18:02:51 +0100 Subject: [PATCH 0073/1812] Add SceneManager and clone utility --- apps/opencs/model/world/data.cpp | 7 ++- apps/opencs/model/world/data.hpp | 6 ++ apps/opencs/view/render/object.cpp | 15 +++-- apps/opencs/view/render/object.hpp | 8 +-- components/CMakeLists.txt | 8 +++ components/resource/resourcesystem.cpp | 24 ++++++++ components/resource/resourcesystem.hpp | 34 +++++++++++ components/resource/scenemanager.cpp | 49 +++++++++++++++ components/resource/scenemanager.hpp | 40 ++++++++++++ components/sceneutil/clone.cpp | 85 ++++++++++++++++++++++++++ components/sceneutil/clone.hpp | 45 ++++++++++++++ components/vfs/manager.cpp | 14 ++++- components/vfs/manager.hpp | 7 +++ 13 files changed, 327 insertions(+), 15 deletions(-) create mode 100644 components/resource/resourcesystem.cpp create mode 100644 components/resource/resourcesystem.hpp create mode 100644 components/resource/scenemanager.cpp create mode 100644 components/resource/scenemanager.hpp create mode 100644 components/sceneutil/clone.cpp create mode 100644 components/sceneutil/clone.hpp diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 07b18cc235..77724c997e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,7 +60,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0) + mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS()) { mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); @@ -354,6 +354,11 @@ CSMWorld::Data::~Data() delete mReader; } +Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() +{ + return &mResourceSystem; +} + const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const { return mGlobals; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index bb4c9a4a80..ce87761045 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include "../doc/stage.hpp" @@ -105,6 +107,8 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; + Resource::ResourceSystem mResourceSystem; + std::vector > mReaders; // not implemented @@ -128,6 +132,8 @@ namespace CSMWorld const VFS::Manager* getVFS() const; + Resource::ResourceSystem* getResourceSystem(); + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f8e91e463b..afed837f8a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -9,10 +9,12 @@ #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" -#include +#include +#include #include "elements.hpp" + void CSVRender::Object::clear() { } @@ -56,15 +58,12 @@ void CSVRender::Object::update() { try { - NifOsg::Loader loader; - loader.resourceManager = mVFS; - std::string path = "meshes\\" + model; - Nif::NIFFilePtr file(new Nif::NIFFile(mVFS->get(path), path)); + osg::ref_ptr loaded = mResourceSystem->getSceneManager()->getInstance(path); mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - mBaseNode->addChild(loader.load(file)); + mBaseNode->addChild(loaded); } catch (std::exception& e) { @@ -101,9 +100,9 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } -CSVRender::Object::Object (const CSMWorld::Data& data, osg::Group* parentNode, +CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mVFS(data.getVFS()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mResourceSystem(data.getResourceSystem()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9efbcf5dc4..23a6527925 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -14,9 +14,9 @@ namespace osg class Group; } -namespace VFS +namespace Resource { - class Manager; + class ResourceSystem; } namespace CSMWorld @@ -39,7 +39,7 @@ namespace CSVRender std::string mReferenceableId; osg::ref_ptr mBaseNode; osg::Group* mParentNode; - const VFS::Manager* mVFS; + Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; /// Not implemented @@ -62,7 +62,7 @@ namespace CSVRender public: - Object (const CSMWorld::Data& data, osg::Group *cellNode, + Object (CSMWorld::Data& data, osg::Group *cellNode, const std::string& id, bool referenceable, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 48de580bc4..70c9daa8b1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -38,6 +38,14 @@ add_component_dir (vfs manager archive bsaarchive filesystemarchive registerarchives ) +add_component_dir (resource + scenemanager resourcesystem + ) + +add_component_dir (sceneutil + clone + ) + add_component_dir (nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream ) diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp new file mode 100644 index 0000000000..e87ef6f101 --- /dev/null +++ b/components/resource/resourcesystem.cpp @@ -0,0 +1,24 @@ +#include "resourcesystem.hpp" + +#include "scenemanager.hpp" + +namespace Resource +{ + + ResourceSystem::ResourceSystem(const VFS::Manager *vfs) + : mVFS(vfs) + { + mSceneManager.reset(new SceneManager(vfs)); + } + + SceneManager* ResourceSystem::getSceneManager() + { + return mSceneManager.get(); + } + + const VFS::Manager* ResourceSystem::getVFS() const + { + return mVFS; + } + +} diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp new file mode 100644 index 0000000000..b696a23766 --- /dev/null +++ b/components/resource/resourcesystem.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H +#define OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H + +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + class SceneManager; + + /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + class ResourceSystem + { + public: + ResourceSystem(const VFS::Manager* vfs); + + SceneManager* getSceneManager(); + + const VFS::Manager* getVFS() const; + + private: + std::auto_ptr mSceneManager; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp new file mode 100644 index 0000000000..b6a09f3a7e --- /dev/null +++ b/components/resource/scenemanager.cpp @@ -0,0 +1,49 @@ +#include "scenemanager.hpp" + +#include + +#include +#include + +#include + +namespace Resource +{ + + SceneManager::SceneManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + } + + osg::ref_ptr SceneManager::getTemplate(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + Index::iterator it = mIndex.find(normalized); + if (it == mIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + // TODO: add support for non-NIF formats + + NifOsg::Loader loader; + loader.resourceManager = mVFS; + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + + // TODO: provide way for the user to get textKeys (attach to the node?) + + mIndex[normalized] = loaded; + return loaded; + } + else + return it->second; + } + + osg::ref_ptr SceneManager::getInstance(const std::string &name) + { + osg::ref_ptr scene = getTemplate(name); + return osg::clone(scene.get(), SceneUtil::CopyOp()); + } + +} diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp new file mode 100644 index 0000000000..7922f3a499 --- /dev/null +++ b/components/resource/scenemanager.hpp @@ -0,0 +1,40 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_SCENEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_SCENEMANAGER_H + +#include +#include + +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + /// @brief Handles loading and caching of scenes, e.g. NIF files + class SceneManager + { + public: + SceneManager(const VFS::Manager* vfs); + + /// Get a read-only copy of this scene "template" + osg::ref_ptr getTemplate(const std::string& name); + + /// Create an instance of the given scene template + osg::ref_ptr getInstance(const std::string& name); + + private: + const VFS::Manager* mVFS; + + // observer_ptr? + typedef std::map > Index; + Index mIndex; + }; + +} + +#endif diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp new file mode 100644 index 0000000000..f124d7de76 --- /dev/null +++ b/components/sceneutil/clone.cpp @@ -0,0 +1,85 @@ +#include "clone.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace SceneUtil +{ + + CopyOp::CopyOp() + { + setCopyFlags(osg::CopyOp::DEEP_COPY_NODES + // Controller might need different inputs per scene instance + | osg::CopyOp::DEEP_COPY_CALLBACKS); + } + + osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const + { + if (!stateset) + return NULL; + if (stateset->getDataVariance() == osg::StateSet::DYNAMIC) + return osg::clone(stateset, osg::CopyOp::DEEP_COPY_STATESETS); + return const_cast(stateset); + } + + osg::Node* CopyOp::operator ()(const osg::Node* node) const + { + if (const osgParticle::ParticleProcessor* processor = dynamic_cast(node)) + return operator()(processor); + if (const osgParticle::ParticleSystemUpdater* updater = dynamic_cast(node)) + { + osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, osg::CopyOp::DEEP_COPY_NODES); + mMap2[cloned] = updater->getParticleSystem(0); + return cloned; + } + return osg::CopyOp::operator()(node); + } + + osg::Drawable* CopyOp::operator ()(const osg::Drawable* drawable) const + { + if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) + return operator()(partsys); + if (dynamic_cast(drawable) + || dynamic_cast(drawable)) + return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); + + return osg::CopyOp::operator()(drawable); + } + + osgParticle::ParticleProcessor* CopyOp::operator() (const osgParticle::ParticleProcessor* processor) const + { + osgParticle::ParticleProcessor* cloned = osg::clone(processor, osg::CopyOp::DEEP_COPY_NODES); + mMap[cloned] = processor->getParticleSystem(); + return cloned; + } + + osgParticle::ParticleSystem* CopyOp::operator ()(const osgParticle::ParticleSystem* partsys) const + { + osgParticle::ParticleSystem* cloned = osg::clone(partsys, osg::CopyOp::DEEP_COPY_DRAWABLES); + + for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) + { + if (it->second == partsys) + { + it->first->setParticleSystem(cloned); + } + } + for (std::map::const_iterator it = mMap2.begin(); it != mMap2.end(); ++it) + { + if (it->second == partsys) + { + osgParticle::ParticleSystemUpdater* updater = it->first; + updater->removeParticleSystem(updater->getParticleSystem(0)); + updater->addParticleSystem(cloned); + } + } + return cloned; + } + +} diff --git a/components/sceneutil/clone.hpp b/components/sceneutil/clone.hpp new file mode 100644 index 0000000000..662dad543a --- /dev/null +++ b/components/sceneutil/clone.hpp @@ -0,0 +1,45 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_CLONE_H +#define OPENMW_COMPONENTS_SCENEUTIL_CLONE_H + +#include + +#include + +namespace osgParticle +{ + class ParticleProcessor; + class ParticleSystem; + class ParticleSystemUpdater; +} + +namespace SceneUtil +{ + + /// @par Defines the cloning behaviour we need: + /// * Assigns updated ParticleSystem pointers on cloned emitters and programs. + /// * Creates deep copy of StateSets if they have a DYNAMIC data variance. + /// * Deep copies RigGeometry and MorphGeometry so they can animate without affecting clones. + /// @warning Do not use an object of this class for more than one copy operation. + class CopyOp : public osg::CopyOp + { + public: + CopyOp(); + + virtual osgParticle::ParticleSystem* operator() (const osgParticle::ParticleSystem* partsys) const; + virtual osgParticle::ParticleProcessor* operator() (const osgParticle::ParticleProcessor* processor) const; + + virtual osg::Node* operator() (const osg::Node* node) const; + virtual osg::Drawable* operator() (const osg::Drawable* drawable) const; + + virtual osg::StateSet* operator() (const osg::StateSet* stateset) const; + + private: + // maps new ParticleProcessor to their old ParticleSystem pointer + // a little messy, but I think this should be the most efficient way + mutable std::map mMap; + mutable std::map mMap2; + }; + +} + +#endif diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index d0e0cf5862..829e089788 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -59,9 +59,14 @@ namespace VFS std::string normalized = name; normalize_path(normalized, mStrict); - std::map::const_iterator found = mIndex.find(normalized); + return getNormalized(normalized); + } + + Files::IStreamPtr Manager::getNormalized(const std::string &normalizedName) const + { + std::map::const_iterator found = mIndex.find(normalizedName); if (found == mIndex.end()) - throw std::runtime_error("Resource '" + name + "' not found"); + throw std::runtime_error("Resource '" + normalizedName + "' not found"); return found->second->open(); } @@ -78,4 +83,9 @@ namespace VFS return mIndex; } + void Manager::normalizeFilename(std::string &name) const + { + normalize_path(name, mStrict); + } + } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index ebbec7d15b..f74914977a 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -38,10 +38,17 @@ namespace VFS /// Get a complete list of files from all archives const std::map& getIndex() const; + /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. + void normalizeFilename(std::string& name) const; + /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. Files::IStreamPtr get(const std::string& name) const; + /// Retrieve a file by name (name is already normalized). + /// @note Throws an exception if the file can not be found. + Files::IStreamPtr getNormalized(const std::string& normalizedName) const; + private: bool mStrict; From c10c146ad1b49e4bec6f914fde82e59f8cda3563 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Mar 2015 23:15:46 +0100 Subject: [PATCH 0074/1812] Skeleton based bounding box callback for RigGeometry (Bug #455) --- components/nif/data.cpp | 3 +- components/nif/data.hpp | 3 +- components/nifosg/nifloader.cpp | 166 +++++++++++++++++++++++++++++--- 3 files changed, 156 insertions(+), 16 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 1fef8d56f2..4c9373029f 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -200,7 +200,8 @@ void NiSkinData::read(NIFStream *nif) bi.trafo.rotation = nif->getMatrix3(); bi.trafo.pos = nif->getVector3(); bi.trafo.scale = nif->getFloat(); - bi.unknown = nif->getVector4(); + bi.boundSphereCenter = nif->getVector3(); + bi.boundSphereRadius = nif->getFloat(); // Number of vertex weights bi.weights.resize(nif->getUShort()); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 702fbf3138..e3f1e2770c 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -151,7 +151,8 @@ public: struct BoneInfo { Transformation trafo; - osg::Vec4f unknown; + osg::Vec3f boundSphereCenter; + float boundSphereRadius; std::vector weights; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index df912728b7..6e9de08f89 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -18,6 +18,7 @@ #include #include #include +#include // particle #include @@ -319,6 +320,144 @@ namespace int mSourceIndex; }; + // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. + // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. + // Kind of awful, not sure of a better way to do this. + class DirtyBoundCallback : public osg::NodeCallback + { + public: + DirtyBoundCallback() + { + } + DirtyBoundCallback(const DirtyBoundCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Geode* geode = node->asGeode(); + if (geode && geode->getNumDrawables()) + { + geode->getDrawable(0)->dirtyBound(); + } + traverse(node, nv); + } + }; + + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + RigBoundingBoxCallback() + : mBoneMapInit(false) + { + } + RigBoundingBoxCallback(const RigBoundingBoxCallback& copy, const osg::CopyOp& copyop) + : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) + , mBoneMapInit(false) + , mBoundSpheres(copy.mBoundSpheres) + { + } + + META_Object(NifOsg, RigBoundingBoxCallback) + + void addBoundSphere(const std::string& bonename, const osg::BoundingSphere& sphere) + { + mBoundSpheres[bonename] = sphere; + } + + // based off code in osg::Transform + void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) const + { + osg::BoundingSphere::vec_type xdash = bsphere._center; + xdash.x() += bsphere._radius; + xdash = xdash*matrix; + + osg::BoundingSphere::vec_type ydash = bsphere._center; + ydash.y() += bsphere._radius; + ydash = ydash*matrix; + + osg::BoundingSphere::vec_type zdash = bsphere._center; + zdash.z() += bsphere._radius; + zdash = zdash*matrix; + + bsphere._center = bsphere._center*matrix; + + xdash -= bsphere._center; + osg::BoundingSphere::value_type len_xdash = xdash.length(); + + ydash -= bsphere._center; + osg::BoundingSphere::value_type len_ydash = ydash.length(); + + zdash -= bsphere._center; + osg::BoundingSphere::value_type len_zdash = zdash.length(); + + bsphere._radius = len_xdash; + if (bsphere._radius(&drawable); + if (!rig) + { + std::cerr << "Warning: RigBoundingBoxCallback set on non-rig" << std::endl; + return box; + } + + if (!mBoneMapInit) + { + initBoneMap(rig); + } + + for (std::map::const_iterator it = mBoneMap.begin(); + it != mBoneMap.end(); ++it) + { + osgAnimation::Bone* bone = it->first; + osg::BoundingSphere bs = it->second; + transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); + box.expandBy(bs); + } + + return box; + } + + void initBoneMap(const osgAnimation::RigGeometry* rig) const + { + if (!rig->getSkeleton()) + { + // may happen before the first frame update, but we're not animating yet, so no need for a bounding box + return; + } + + osgAnimation::BoneMapVisitor mapVisitor; + { + // const_cast necessary because there does not seem to be a const variant of NodeVisitor. + // Don't worry, we're not actually changing the skeleton. + osgAnimation::Skeleton* skel = const_cast(rig->getSkeleton()); + skel->accept(mapVisitor); + } + + for (osgAnimation::BoneMap::const_iterator it = mapVisitor.getBoneMap().begin(); it != mapVisitor.getBoneMap().end(); ++it) + { + std::map::const_iterator found = mBoundSpheres.find(it->first); + if (found != mBoundSpheres.end()) // not all bones have to be used for skinning + mBoneMap[it->second.get()] = found->second; + } + + mBoneMapInit = true; + } + + private: + mutable bool mBoneMapInit; + mutable std::map mBoneMap; + + std::map mBoundSpheres; + }; + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -451,7 +590,7 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::ref_ptr created = handleNode(nifNode, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, false, std::map(), 0, 0, false, textKeys); return created; } @@ -469,7 +608,7 @@ namespace NifOsg osg::ref_ptr skel = new osgAnimation::Skeleton; skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy - skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); + handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); return skel; } @@ -494,7 +633,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -515,6 +654,9 @@ namespace NifOsg transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + if (parentNode) + parentNode->addChild(transformNode); + if (!rootNode) rootNode = transformNode; @@ -610,8 +752,7 @@ namespace NifOsg { if(!children[i].empty()) { - transformNode->addChild( - handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -1085,17 +1226,11 @@ namespace NifOsg osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); - // Slightly expand the bounding box to account for movement of the bones - // For more accuracy the skinning should be relative to the parent of the first skinned bone, - // rather than the root bone. - // TODO: calculate a correct bounding box based on the bone positions every frame in a ComputeBoundingBoxCallback - osg::BoundingBox box = geometry->getBound(); - box.expandBy(box._min-(box._max-box._min)/2); - box.expandBy(box._max+(box._max-box._min)/2); - rig->setInitialBound(box); - const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + RigBoundingBoxCallback* callback = new RigBoundingBoxCallback; + rig->setComputeBoundingBoxCallback(callback); + // Assign bone weights osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); @@ -1105,6 +1240,8 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; + callback->addBoundSphere(boneName, osg::BoundingSphere(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius)); + osgAnimation::VertexInfluence influence; influence.setName(boneName); const std::vector &weights = data->bones[i].weights; @@ -1123,6 +1260,7 @@ namespace NifOsg trans->setUpdateCallback(new InvertBoneMatrix()); geode->addDrawable(rig); + geode->addUpdateCallback(new DirtyBoundCallback); trans->addChild(geode); parentNode->addChild(trans); From e91d9d090365742bf916f4802b933f866dc5ce3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Mar 2015 17:00:10 +0100 Subject: [PATCH 0075/1812] Fix for behaviour of scaled particle nodes Not sure if used in vanilla assets so may be low priority, but couldn't help looking into this. --- components/nifosg/nifloader.cpp | 2 ++ components/nifosg/particle.cpp | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6e9de08f89..1a36af4c4a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -993,6 +993,8 @@ namespace NifOsg { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + // Scaling the particle node should also scale particles, even when the worldspace flag is enabled + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 791847cd67..afa76468a5 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -49,8 +49,10 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::MatrixTransform* trans = dynamic_cast(node); - osg::Matrix worldMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(worldMat)); + osg::Matrix mat = osg::computeLocalToWorld( path ); + mat = osg::Matrix::inverse(mat); + mat.orthoNormalize(mat); // don't undo the scale + trans->setMatrix(mat); } traverse(node,nv); } @@ -174,7 +176,7 @@ void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + mCachedWorldPositionDirection = absolute ? osg::Matrix::transform3x3(program->getLocalToWorldMatrix(), mDirection) : mDirection; else // Type_Point mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; } @@ -241,10 +243,10 @@ void Emitter::emitParticles(double dt) worldToPs = osg::Matrix::inverse(psToWorld); } + worldToPs.orthoNormalize(worldToPs); + const osg::Matrix& ltw = getLocalToWorldMatrix(); - const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); const osg::Matrix emitterToPs = ltw * worldToPs; - const osg::Matrix prevEmitterToPs = previous_ltw * worldToPs; int n = mCounter->numParticlesToCreate(dt); @@ -275,15 +277,11 @@ void Emitter::emitParticles(double dt) { mPlacer->place(P); - P->transformPositionVelocity(transform); - mShooter->shoot(P); - // Now need to transform the position and velocity because we having a moving model. - // (is this actually how MW works?) - float r = ((float)rand()/(float)RAND_MAX); - P->transformPositionVelocity(emitterToPs, prevEmitterToPs, r); - //P->transformPositionVelocity(ltw); + P->transformPositionVelocity(transform); + + P->transformPositionVelocity(emitterToPs); } } } From ac2612926ee61d2f5d4bcb3226cb783b567ecdc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Mar 2015 23:25:15 +0100 Subject: [PATCH 0076/1812] Disable unRefImageDataAfterApply --- components/nifosg/nifloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1a36af4c4a..3b68df562f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1407,7 +1407,8 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); osg::Image* image = result.getImage(); osg::Texture2D* texture2d = new osg::Texture2D; - texture2d->setUnRefImageDataAfterApply(true); + // Can be enabled for single-context, i.e. in openmw + //texture2d->setUnRefImageDataAfterApply(true); texture2d->setImage(image); unsigned int clamp = static_cast(tex.clamp); From 961aba5e2bd6aaa1dff0a765527512d3401b8093 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 00:11:25 +0100 Subject: [PATCH 0077/1812] Revert part of e91d9d090365 --- components/nifosg/particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index afa76468a5..c6e5fa9a8b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -176,7 +176,7 @@ void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? osg::Matrix::transform3x3(program->getLocalToWorldMatrix(), mDirection) : mDirection; + mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; else // Type_Point mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; } From 322fcdc2d318a1c9c0325d2b7cb7dd5be2359ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 00:30:49 +0100 Subject: [PATCH 0078/1812] Transform world space particles when attaching to a node --- apps/opencs/view/render/object.cpp | 47 ++++++++++++------- apps/opencs/view/render/object.hpp | 3 +- components/nifosg/nifloader.cpp | 25 +++++----- components/resource/scenemanager.cpp | 70 +++++++++++++++++++++++++++- components/resource/scenemanager.hpp | 11 ++++- 5 files changed, 123 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index afed837f8a..ec184a5636 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -5,6 +5,10 @@ #include #include +#include +#include +#include + #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" @@ -14,6 +18,22 @@ #include "elements.hpp" +namespace +{ + + osg::ref_ptr createErrorCube() + { + osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 50.f)); + osg::ref_ptr shapedrawable(new osg::ShapeDrawable); + shapedrawable->setShape(shape); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(shapedrawable); + return geode; + } + +} + void CSVRender::Object::clear() { @@ -44,15 +64,11 @@ void CSVRender::Object::update() error = 2; } + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + if (error) { - /* - Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE); - entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error - entity->setVisibilityFlags (Element_Reference); - - mBase->attachObject (entity); - */ + mBaseNode->addChild(createErrorCube()); } else { @@ -60,10 +76,7 @@ void CSVRender::Object::update() { std::string path = "meshes\\" + model; - osg::ref_ptr loaded = mResourceSystem->getSceneManager()->getInstance(path); - - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - mBaseNode->addChild(loaded); + mResourceSystem->getSceneManager()->createInstance(path, mBaseNode); } catch (std::exception& e) { @@ -73,7 +86,7 @@ void CSVRender::Object::update() } } -void CSVRender::Object::adjust() +void CSVRender::Object::adjustTransform() { if (mReferenceId.empty()) return; @@ -120,8 +133,8 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mReferenceableId = getReference().mRefID; } + adjustTransform(); update(); - adjust(); } CSVRender::Object::~Object() @@ -140,8 +153,8 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row()) { + adjustTransform(); update(); - adjust(); return true; } @@ -160,8 +173,8 @@ bool CSVRender::Object::referenceableAboutToBeRemoved (const QModelIndex& parent // Deletion of referenceable-type objects is handled outside of Object. if (!mReferenceId.empty()) { + adjustTransform(); update(); - adjust(); return true; } } @@ -184,6 +197,8 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId); + adjustTransform(); + if (columnIndex>=topLeft.column() && columnIndex<=bottomRight.row()) { mReferenceableId = @@ -192,8 +207,6 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, update(); } - adjust(); - return true; } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e40253a606..4cea621338 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -52,10 +52,11 @@ namespace CSVRender void clear(); /// Update model + /// @note Make sure adjustTransform() was called first so world space particles get positioned correctly void update(); /// Adjust position, orientation and scale - void adjust(); + void adjustTransform(); /// Throws an exception if *this was constructed with referenceable const CSMWorld::CellRef& getReference() const; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3b68df562f..7e1c27b0ef 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -915,14 +915,8 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl, - osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { - // TODO: also take into account the transform by placement in the scene (should be done post-load) - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) particledata = static_cast(nifNode)->data.getPtr(); @@ -941,9 +935,11 @@ namespace NifOsg osgParticle::Particle* created = partsys->createParticle(&particletemplate); created->setLifeTime(std::max(0.f, particle.lifespan)); - osg::Vec4f adjustedVelocity = osg::Vec4f(particle.velocity, 0.f) * particletransform; - created->setVelocity(osg::Vec3f(adjustedVelocity.x(), adjustedVelocity.y(), adjustedVelocity.z())); - created->setPosition(particledata->vertices.at(particle.vertex) * particletransform); + + // Note this position and velocity is not correct for a particle system with absolute reference frame, + // which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager. + created->setVelocity(particle.velocity); + created->setPosition(particledata->vertices.at(particle.vertex)); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); if (particle.vertex < int(particledata->colors.size())) @@ -1014,7 +1010,13 @@ namespace NifOsg ? osgParticle::ParticleProcessor::RELATIVE_RF : osgParticle::ParticleProcessor::ABSOLUTE_RF; - handleParticleInitialState(nifNode, partsys, partctrl, rf); + // HACK: ParticleSystem has no setReferenceFrame method + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + { + partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); + } + + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); @@ -1030,7 +1032,6 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid FindRecIndexVisitor find (partctrl->emitter->recIndex); rootNode->accept(find); if (!find.mFound) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b6a09f3a7e..c7fd5065eb 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -1,12 +1,63 @@ #include "scenemanager.hpp" #include +#include +#include + +#include #include #include #include +namespace +{ + + class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor + { + public: + InitWorldSpaceParticlesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + void apply(osg::Node& node) + { + if (osg::Geode* geode = node.asGeode()) + { + for (unsigned int i=0;igetNumDrawables();++i) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode->getDrawable(i))) + { + // HACK: ParticleSystem has no getReferenceFrame() + if (partsys->getUserDataContainer() + && partsys->getUserDataContainer()->getNumDescriptions() > 0 + && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace") + { + // HACK: Ignore the InverseWorldMatrix transform the geode is attached to + if (geode->getNumParents() && geode->getParent(0)->getNumParents()) + transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); + } + } + } + } + + traverse(node); + } + + void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) + { + osg::Matrix worldMat = node->getWorldMatrices()[0]; + for (int i=0; inumParticles(); ++i) + { + partsys->getParticle(i)->transformPositionVelocity(worldMat); + } + } + }; + +} + namespace Resource { @@ -40,10 +91,25 @@ namespace Resource return it->second; } - osg::ref_ptr SceneManager::getInstance(const std::string &name) + osg::ref_ptr SceneManager::createInstance(const std::string &name) { osg::ref_ptr scene = getTemplate(name); - return osg::clone(scene.get(), SceneUtil::CopyOp()); + osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); + return cloned; + } + + osg::ref_ptr SceneManager::createInstance(const std::string &name, osg::Group* parentNode) + { + osg::ref_ptr cloned = createInstance(name); + attachTo(cloned, parentNode); + return cloned; + } + + void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const + { + parentNode->addChild(instance); + InitWorldSpaceParticlesVisitor visitor; + instance->accept(visitor); } } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7922f3a499..76b69be6ec 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -25,7 +25,16 @@ namespace Resource osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template - osg::ref_ptr getInstance(const std::string& name); + osg::ref_ptr createInstance(const std::string& name); + + /// Create an instance of the given scene template and immediately attach it to a parent node + osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); + + /// Attach the given scene instance to the given parent node + /// @note You should have the parentNode in its intended position before calling this method, + /// so that world space particles of the \a instance get transformed correctly. + /// @note Assumes the given instance was not attached to any parents before. + void attachTo(osg::Node* instance, osg::Group* parentNode) const; private: const VFS::Manager* mVFS; From bb32c761df2d08e65128998e6dd68bcfe7737bca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 02:20:20 +0100 Subject: [PATCH 0079/1812] *very* early texture manager, need a lot more thought to design this properly --- apps/nifosgtest/test.cpp | 5 +- apps/opencs/view/render/scenewidget.cpp | 2 +- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 9 +--- components/nifosg/controller.hpp | 6 +-- components/nifosg/nifloader.cpp | 59 ++++++++++------------ components/nifosg/nifloader.hpp | 9 ++-- components/resource/resourcesystem.cpp | 4 +- components/resource/resourcesystem.hpp | 4 ++ components/resource/scenemanager.cpp | 7 ++- components/resource/scenemanager.hpp | 8 ++- components/resource/texturemanager.cpp | 66 +++++++++++++++++++++++++ components/resource/texturemanager.hpp | 48 ++++++++++++++++++ 13 files changed, 176 insertions(+), 53 deletions(-) create mode 100644 components/resource/texturemanager.cpp create mode 100644 components/resource/texturemanager.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index dec0388253..332867be5d 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -124,7 +126,8 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); osg::Group* newNode = new osg::Group; NifOsg::Loader loader; - loader.resourceManager = &resourceMgr; + Resource::TextureManager texMgr(&resourceMgr); + loader.mTextureManager = &texMgr; newNode->addChild(loader.load(nif)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 16ad2e68a3..d7a85410bc 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -109,7 +109,7 @@ CompositeViewer::CompositeViewer() setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); - mTimer.start( 10 ); + mTimer.start( 0 ); } CompositeViewer &CompositeViewer::get() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 161c9ce4a0..47fcf24990 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager resourcesystem + scenemanager texturemanager resourcesystem ) add_component_dir (sceneutil diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 6aa9205532..eca5a7d79a 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -416,7 +416,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } -FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) @@ -442,12 +442,7 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { osg::StateSet* stateset = node->getStateSet(); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(stateset->getTextureAttribute(mTexSlot, osg::StateAttribute::TEXTURE)); - if (tex) - tex->setImage(mTextures[curTexture].get()); - else - std::cout << "FlipController: can't find target slot" << std::endl; - + stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } traverse(node, nv); } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 7579735cac..0e58853330 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -13,7 +13,7 @@ #include //UVController // FlipController -#include +#include #include #include @@ -265,10 +265,10 @@ namespace NifOsg private: int mTexSlot; float mDelta; - std::vector > mTextures; + std::vector > mTextures; public: - FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); FlipController(); FlipController(const FlipController& copy, const osg::CopyOp& copyop); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7e1c27b0ef..ace14c6690 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,12 +6,12 @@ #include #include -// resource -#include -#include #include + +// resource #include #include +#include // skel #include @@ -510,11 +510,11 @@ namespace NifOsg class LoaderImpl { public: - const VFS::Manager* mResourceManager; + Resource::TextureManager* mTextureManager; bool mShowMarkers; - LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers) - : mResourceManager(resourceManager) + LoaderImpl(Resource::TextureManager* textureManager, bool showMarkers) + : mTextureManager(textureManager) , mShowMarkers(showMarkers) { } @@ -846,22 +846,26 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiFlipController) { const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); - std::vector > textures; + std::vector > textures; for (unsigned int i=0; imSources.length(); ++i) { Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; if (st.empty()) continue; - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); + // inherit wrap settings from the target slot + osg::Texture2D* inherit = dynamic_cast(stateset->getTextureAttribute(flipctrl->mTexSlot, osg::StateAttribute::TEXTURE)); + osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP; + osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP; + if (inherit) + { + wrapS = inherit->getWrap(osg::Texture2D::WRAP_S); + wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); + } - // TODO: replace with texture manager - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); - textures.push_back(osg::ref_ptr(result.getImage())); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); + osg::ref_ptr texture = mTextureManager->getTexture2D(filename, wrapS, wrapT); + textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); @@ -1398,26 +1402,15 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager); - - // TODO: replace with texture manager - // tx_creature_werewolf.dds isn't loading in the correct format without this option - osgDB::Options* opts = new osgDB::Options; - opts->setOptionString("dds_dxt1_detect_rgba"); - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts); - osg::Image* image = result.getImage(); - osg::Texture2D* texture2d = new osg::Texture2D; - // Can be enabled for single-context, i.e. in openmw - //texture2d->setUnRefImageDataAfterApply(true); - texture2d->setImage(image); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); - texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); + osg::Texture2D* texture2d = mTextureManager->getTexture2D(filename, + wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, + wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); @@ -1544,19 +1537,19 @@ namespace NifOsg osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); return loader.load(file, textKeys); } osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); return loader.loadAsSkeleton(file, textKeys); } void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) { - LoaderImpl loader(resourceManager, sShowMarkers); + LoaderImpl loader(mTextureManager, sShowMarkers); loader.loadKf(kf, rootNode, sourceIndex, textKeys); } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 87d1a0a99f..716cd1957e 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -5,8 +5,6 @@ #include // NIFFilePtr -#include - #include namespace osg @@ -14,6 +12,11 @@ namespace osg class Node; } +namespace Resource +{ + class TextureManager; +} + namespace NifOsg { typedef std::multimap TextKeyMap; @@ -41,7 +44,7 @@ namespace NifOsg /// Default: false. static void setShowMarkers(bool show); - const VFS::Manager* resourceManager; + Resource::TextureManager* mTextureManager; private: diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index e87ef6f101..215b1a67c8 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -1,6 +1,7 @@ #include "resourcesystem.hpp" #include "scenemanager.hpp" +#include "texturemanager.hpp" namespace Resource { @@ -8,7 +9,8 @@ namespace Resource ResourceSystem::ResourceSystem(const VFS::Manager *vfs) : mVFS(vfs) { - mSceneManager.reset(new SceneManager(vfs)); + mTextureManager.reset(new TextureManager(vfs)); + mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); } SceneManager* ResourceSystem::getSceneManager() diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index b696a23766..a91f3cab3d 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -12,8 +12,11 @@ namespace Resource { class SceneManager; + class TextureManager; /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but + /// are built around the use of a single virtual file system. class ResourceSystem { public: @@ -25,6 +28,7 @@ namespace Resource private: std::auto_ptr mSceneManager; + std::auto_ptr mTextureManager; const VFS::Manager* mVFS; }; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c7fd5065eb..c44cbd2ae4 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include namespace @@ -61,8 +63,9 @@ namespace namespace Resource { - SceneManager::SceneManager(const VFS::Manager *vfs) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) : mVFS(vfs) + , mTextureManager(textureManager) { } @@ -79,7 +82,7 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - loader.resourceManager = mVFS; + loader.mTextureManager = mTextureManager; osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); // TODO: provide way for the user to get textKeys (attach to the node?) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 76b69be6ec..3d439c1867 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,6 +7,11 @@ #include #include +namespace Resource +{ + class TextureManager; +} + namespace VFS { class Manager; @@ -19,7 +24,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs); + SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); /// Get a read-only copy of this scene "template" osg::ref_ptr getTemplate(const std::string& name); @@ -38,6 +43,7 @@ namespace Resource private: const VFS::Manager* mVFS; + Resource::TextureManager* mTextureManager; // observer_ptr? typedef std::map > Index; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp new file mode 100644 index 0000000000..8347d5f043 --- /dev/null +++ b/components/resource/texturemanager.cpp @@ -0,0 +1,66 @@ +#include "texturemanager.hpp" + +#include + +#include + +#include + +namespace Resource +{ + + TextureManager::TextureManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + + } + + /* + osg::ref_ptr TextureManager::getImage(const std::string &filename) + { + + } + */ + + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) + { + std::string normalized = filename; + mVFS->normalizeFilename(normalized); + MapKey key = std::make_pair(std::make_pair(wrapS, wrapT), normalized); + std::map >::iterator found = mTextures.find(key); + if (found != mTextures.end()) + { + return found->second; + } + else + { + osg::ref_ptr opts (new osgDB::Options); + opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*mVFS->get(normalized.c_str()), opts); + if (!result.success()) + { + // TODO: use "notfound" default texture + throw std::runtime_error("Error loading"); + //std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + } + + osg::Image* image = result.getImage(); + osg::ref_ptr texture(new osg::Texture2D); + texture->setImage(image); + texture->setWrap(osg::Texture::WRAP_S, wrapS); + texture->setWrap(osg::Texture::WRAP_T, wrapT); + + // Can be enabled for single-context, i.e. in openmw + //texture->setUnRefImageDataAfterApply(true); + + mTextures.insert(std::make_pair(key, texture)); + return texture; + } + } + +} diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp new file mode 100644 index 0000000000..c0b36f7cf6 --- /dev/null +++ b/components/resource/texturemanager.hpp @@ -0,0 +1,48 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_TEXTUREMANAGER_H + +#include +#include + +#include +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace Resource +{ + + /// @brief Handles loading/caching of Images and Texture StateAttributes. + class TextureManager + { + public: + TextureManager(const VFS::Manager* vfs); + + // TODO: texture filtering settings + + /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. + osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); + + /// Create or retrieve an Image + //osg::ref_ptr getImage(const std::string& filename); + + const VFS::Manager* getVFS() { return mVFS; } + + private: + const VFS::Manager* mVFS; + + typedef std::pair, std::string> MapKey; + + std::map > mImages; + + std::map > mTextures; + + }; + +} + +#endif From c5fd92fde1e357c54102cfb8726aad86cd539311 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 02:57:39 +0100 Subject: [PATCH 0080/1812] Show a default warning texture for not found textures --- components/resource/texturemanager.cpp | 43 +++++++++++++++++++++++--- components/resource/texturemanager.hpp | 2 ++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 8347d5f043..d0d32a40e1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -6,11 +6,36 @@ #include +namespace +{ + + osg::ref_ptr createWarningTexture() + { + osg::ref_ptr warningImage = new osg::Image; + + int width=8, height=8; + unsigned char* bytes = (unsigned char*)calloc(width*height*3, sizeof(unsigned char)); + for (int i=0;isetImage(width, height, 1, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + + osg::ref_ptr warningTexture = new osg::Texture2D; + warningTexture->setImage(warningImage); + return warningTexture; + } + +} + namespace Resource { TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) + , mWarningTexture(createWarningTexture()) { } @@ -34,6 +59,17 @@ namespace Resource } else { + Files::IStreamPtr stream; + try + { + stream = mVFS->get(normalized.c_str()); + } + catch (std::exception& e) + { + std::cerr << "Failed to open texture: " << e.what() << std::endl; + return mWarningTexture; + } + osg::ref_ptr opts (new osgDB::Options); opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option size_t extPos = normalized.find_last_of('.'); @@ -41,12 +77,11 @@ namespace Resource if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); - osgDB::ReaderWriter::ReadResult result = reader->readImage(*mVFS->get(normalized.c_str()), opts); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { - // TODO: use "notfound" default texture - throw std::runtime_error("Error loading"); - //std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + return mWarningTexture; } osg::Image* image = result.getImage(); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index c0b36f7cf6..f4ade515d3 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -41,6 +41,8 @@ namespace Resource std::map > mTextures; + osg::ref_ptr mWarningTexture; + }; } From 232e34bddd7f5bf0bd48d1292a5f94128dc45f46 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 20:15:17 +0100 Subject: [PATCH 0081/1812] OpenCS: port lighting toolbar, fix multiple context GL objects issue --- apps/opencs/view/render/lighting.hpp | 15 ++- apps/opencs/view/render/lightingbright.cpp | 30 ++--- apps/opencs/view/render/lightingbright.hpp | 9 +- apps/opencs/view/render/lightingday.cpp | 35 +++--- apps/opencs/view/render/lightingday.hpp | 9 +- apps/opencs/view/render/lightingnight.cpp | 35 +++--- apps/opencs/view/render/lightingnight.hpp | 9 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 111 ++++++++++++++++-- apps/opencs/view/render/scenewidget.hpp | 46 +++++++- .../view/render/unpagedworldspacewidget.cpp | 12 +- apps/opencs/view/render/worldspacewidget.cpp | 10 +- apps/opencs/view/world/previewsubview.cpp | 4 +- apps/opencs/view/world/scenesubview.cpp | 4 +- components/esm/defs.hpp | 2 +- components/resource/scenemanager.cpp | 8 ++ components/resource/scenemanager.hpp | 2 + 17 files changed, 237 insertions(+), 106 deletions(-) diff --git a/apps/opencs/view/render/lighting.hpp b/apps/opencs/view/render/lighting.hpp index a1da9f7e38..eb8c97b129 100644 --- a/apps/opencs/view/render/lighting.hpp +++ b/apps/opencs/view/render/lighting.hpp @@ -1,10 +1,13 @@ #ifndef OPENCS_VIEW_LIGHTING_H #define OPENCS_VIEW_LIGHTING_H -namespace Ogre +namespace osgViewer { - class SceneManager; - class ColourValue; + class View; +} +namespace osg +{ + class Vec4f; } namespace CSVRender @@ -15,12 +18,12 @@ namespace CSVRender virtual ~Lighting(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0) = 0; + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0) = 0; virtual void deactivate() = 0; - virtual void setDefaultAmbient (const Ogre::ColourValue& colour) = 0; + virtual void setDefaultAmbient (const osg::Vec4f& colour) = 0; }; } diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index a342ab0936..6d3d4d7906 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -3,28 +3,28 @@ #include -CSVRender::LightingBright::LightingBright() : mSceneManager (0), mLight (0) {} +#include -void CSVRender::LightingBright::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +CSVRender::LightingBright::LightingBright() : mView(NULL) {} + +void CSVRender::LightingBright::activate (osgViewer::View* view, + const osg::Vec4f* /*defaultAmbient*/) { - mSceneManager = sceneManager; + mView = view; - mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1)); + // FIXME: ambient should be applied to LightModel instead of the light - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (1.0, 1.0, 1.0)); + osg::ref_ptr light (new osg::Light); + light->setConstantAttenuation(1.f); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setAmbient(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + + mView->setLight(light); } void CSVRender::LightingBright::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} +void CSVRender::LightingBright::setDefaultAmbient (const osg::Vec4f& colour) {} diff --git a/apps/opencs/view/render/lightingbright.hpp b/apps/opencs/view/render/lightingbright.hpp index bc01899cb0..e7ef63f0a9 100644 --- a/apps/opencs/view/render/lightingbright.hpp +++ b/apps/opencs/view/render/lightingbright.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingBright : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingBright(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index c5189ccfdf..1d8444bc37 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -1,36 +1,33 @@ - #include "lightingday.hpp" -#include +#include -CSVRender::LightingDay::LightingDay() : mSceneManager (0), mLight (0) {} +CSVRender::LightingDay::LightingDay() : mView(NULL) {} -void CSVRender::LightingDay::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +void CSVRender::LightingDay::activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient) { - mSceneManager = sceneManager; + mView = view; + + osg::ref_ptr light (new osg::Light); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setConstantAttenuation(1.f); if (defaultAmbient) - mSceneManager->setAmbientLight (*defaultAmbient); + light->setAmbient(*defaultAmbient); else - mSceneManager->setAmbientLight (Ogre::ColourValue (0.7, 0.7, 0.7, 1)); + light->setAmbient(osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f)); - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (1, 1, 1)); + mView->setLight(light); } void CSVRender::LightingDay::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour) +void CSVRender::LightingDay::setDefaultAmbient (const osg::Vec4f& colour) { - mSceneManager->setAmbientLight (colour); + if (mView) + mView->getLight()->setAmbient(colour); } diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index 8638146e23..a0f39b866a 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingDay : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingDay(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 7d94dc9646..81236ec13a 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -1,36 +1,33 @@ - #include "lightingnight.hpp" -#include +#include -CSVRender::LightingNight::LightingNight() : mSceneManager (0), mLight (0) {} +CSVRender::LightingNight::LightingNight() : mView(NULL) {} -void CSVRender::LightingNight::activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient) +void CSVRender::LightingNight::activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient) { - mSceneManager = sceneManager; + mView = view; + + osg::ref_ptr light (new osg::Light); + light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + light->setConstantAttenuation(1.f); if (defaultAmbient) - mSceneManager->setAmbientLight (*defaultAmbient); + light->setAmbient(*defaultAmbient); else - mSceneManager->setAmbientLight (Ogre::ColourValue (0.2, 0.2, 0.2, 1)); + light->setAmbient(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); - mLight = mSceneManager->createLight(); - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3 (0, 0, -1)); - mLight->setDiffuseColour (Ogre::ColourValue (0.2, 0.2, 0.2)); + mView->setLight(light); } void CSVRender::LightingNight::deactivate() { - if (mLight) - { - mSceneManager->destroyLight (mLight); - mLight = 0; - } } -void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour) +void CSVRender::LightingNight::setDefaultAmbient (const osg::Vec4f& colour) { - mSceneManager->setAmbientLight (colour); + if (mView) + mView->getLight()->setAmbient(colour); } diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index 47d1d7ce82..b2fd178932 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -12,19 +12,18 @@ namespace CSVRender { class LightingNight : public Lighting { - Ogre::SceneManager *mSceneManager; - Ogre::Light *mLight; + osgViewer::View* mView; public: LightingNight(); - virtual void activate (Ogre::SceneManager *sceneManager, - const Ogre::ColourValue *defaultAmbient = 0); + virtual void activate (osgViewer::View* view, + const osg::Vec4f *defaultAmbient = 0); virtual void deactivate(); - virtual void setDefaultAmbient (const Ogre::ColourValue& colour); + virtual void setDefaultAmbient (const osg::Vec4f& colour); }; } diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 02fcd9f060..f0cbc939aa 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -8,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (parent), mData (data), mObject(data, mRootNode, id, referenceable) +: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable) { mView->setCameraManipulator(new osgGA::TrackballManipulator); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d7a85410bc..ef2d701c60 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -6,21 +6,23 @@ #include #include +#include +#include +#include +#include + +#include + #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" #include "navigation.hpp" #include "lighting.hpp" -#include -#include -#include -#include - namespace CSVRender { -SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) +RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , mRootNode(0) { @@ -58,9 +60,8 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); mRootNode = new osg::Group; - // TODO: move to utility file - mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + addDefaultRootState(mRootNode->getOrCreateStateSet()); mView->setSceneData(mRootNode); @@ -74,22 +75,30 @@ SceneWidget::SceneWidget(QWidget *parent, Qt::WindowFlags f) viewer.realize(); } -SceneWidget::~SceneWidget() +void RenderWidget::addDefaultRootState(osg::StateSet* stateset) +{ + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); +} + +RenderWidget::~RenderWidget() { CompositeViewer::get().removeView(mView); } -void SceneWidget::flagAsModified() +void RenderWidget::flagAsModified() { mView->requestRedraw(); } -void SceneWidget::setVisibilityMask(int mask) +void RenderWidget::setVisibilityMask(int mask) { // 0x1 reserved for separating cull and update visitors mView->getCamera()->setCullMask(mask<<1); } +// -------------------------------------------------- + CompositeViewer::CompositeViewer() { #if QT_VERSION >= 0x050000 @@ -109,7 +118,7 @@ CompositeViewer::CompositeViewer() setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); - mTimer.start( 0 ); + mTimer.start( 10 ); } CompositeViewer &CompositeViewer::get() @@ -123,4 +132,80 @@ void CompositeViewer::update() frame(); } +// --------------------------------------------------- + +SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f) + : RenderWidget(parent, f) + , mSceneManager(sceneManager) + , mLighting(NULL) +{ + //mView->setLightingMode(osgViewer::View::NO_LIGHT); + + setLighting(&mLightingDay); +} + +SceneWidget::~SceneWidget() +{ + // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects + mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); +} + +void SceneWidget::setLighting(Lighting *lighting) +{ + if (mLighting) + mLighting->deactivate(); + + mLighting = lighting; + mLighting->activate (mView.get(), mHasDefaultAmbient ? &mDefaultAmbient : 0); + + flagAsModified(); +} + +void SceneWidget::selectLightingMode (const std::string& mode) +{ + if (mode=="day") + setLighting (&mLightingDay); + else if (mode=="night") + setLighting (&mLightingNight); + else if (mode=="bright") + setLighting (&mLightingBright); +} + +CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) +{ + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode"); + + /// \todo replace icons + tool->addButton (":scenetoolbar/day", "day", + "Day" + "
  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Strong directional light source
  • " + "
  • This mode closely resembles day time in-game
"); + tool->addButton (":scenetoolbar/night", "night", + "Night" + "
  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Weak directional light source
  • " + "
  • This mode closely resembles night time in-game
"); + tool->addButton (":scenetoolbar/bright", "bright", + "Bright" + "
  • Maximum ambient
  • " + "
  • Strong directional light source
"); + + connect (tool, SIGNAL (modeChanged (const std::string&)), + this, SLOT (selectLightingMode (const std::string&))); + + return tool; +} + +void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) +{ + mDefaultAmbient = colour; + mHasDefaultAmbient = true; + + if (mLighting) + mLighting->setDefaultAmbient (colour); +} + } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 04025340d3..8580a2bb1a 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -11,6 +11,11 @@ #include #include +namespace Resource +{ + class SceneManager; +} + namespace osg { class Group; @@ -27,13 +32,13 @@ namespace CSVRender class Navigation; class Lighting; - class SceneWidget : public QWidget + class RenderWidget : public QWidget { Q_OBJECT public: - SceneWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); - ~SceneWidget(); + RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~RenderWidget(); void flagAsModified(); @@ -41,6 +46,8 @@ namespace CSVRender protected: + void addDefaultRootState(osg::StateSet* stateset); + osg::ref_ptr mView; osg::Group* mRootNode; @@ -48,6 +55,39 @@ namespace CSVRender QTimer mTimer; }; + // Extension of RenderWidget to support lighting mode selection & toolbar + class SceneWidget : public RenderWidget + { + Q_OBJECT + public: + SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~SceneWidget(); + + CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); + ///< \attention The created tool is not added to the toolbar (via addTool). Doing that + /// is the responsibility of the calling function. + + void setDefaultAmbient (const osg::Vec4f& colour); + ///< \note The actual ambient colour may differ based on lighting settings. + + protected: + void setLighting (Lighting *lighting); + ///< \attention The ownership of \a lighting is not transferred to *this. + + Resource::SceneManager* mSceneManager; + + Lighting* mLighting; + + osg::Vec4f mDefaultAmbient; + bool mHasDefaultAmbient; + LightingDay mLightingDay; + LightingNight mLightingNight; + LightingBright mLightingBright; + + private slots: + + void selectLightingMode (const std::string& mode); + }; // There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with multiple views diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index e48b84cffb..a6d18a0f2d 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -23,9 +23,12 @@ void CSVRender::UnpagedWorldspaceWidget::update() const CSMWorld::Record& record = dynamic_cast&> (mCellsModel->getRecord (mCellId)); - Ogre::ColourValue colour; - colour.setAsABGR (record.get().mAmbi.mAmbient); - //setDefaultAmbient (colour); + ESM::Color clr = record.get().mAmbi.mAmbient; + osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, 1.f); + + setDefaultAmbient (colour); /// \todo deal with mSunlight and mFog/mForDensity @@ -51,7 +54,6 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); mView->setCameraManipulator(new osgGA::TrackballManipulator); - //mView->setCameraManipulator(new osgGA::FirstPersonManipulator); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -93,7 +95,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - // FIXME: we shouldn't need to rebuild the whole cell + mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); update(); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4bbfd5bcdc..2d7a0a0f85 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -19,7 +19,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), +: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mDocument(document), mSceneElements(0), mRun(0), mInteractionMask (0) { setAcceptDrops(true); @@ -361,7 +361,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { //mMouse->mouseMoveEvent(event); } - SceneWidget::mouseMoveEvent(event); + RenderWidget::mouseMoveEvent(event); } void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) @@ -386,7 +386,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) */ //mMouse->mouseReleaseEvent(event); } - SceneWidget::mouseReleaseEvent(event); + RenderWidget::mouseReleaseEvent(event); } void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -401,7 +401,7 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { //if(!mMouse->wheelEvent(event)) - SceneWidget::wheelEvent(event); + RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) @@ -411,5 +411,5 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) //mMouse->cancelDrag(); } else - SceneWidget::keyPressEvent(event); + RenderWidget::keyPressEvent(event); } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 0c9823c444..1c2d6b95c7 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -30,8 +30,8 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); - //CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); - //toolbar->addTool (lightingTool); + CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); + toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index c59236ee5d..3fdf2f6e5c 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -107,8 +107,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); - //CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); - //toolbar->addTool (lightingTool); + CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); + toolbar->addTool (lightingTool); CSVWidget::SceneToolToggle2 *sceneVisibilityTool = widget->makeSceneVisibilitySelector (toolbar); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 7ef8102c29..d261d7247d 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -13,7 +13,7 @@ struct TimeStamp }; // Pixel color value. Standard four-byte rr,gg,bb,aa format. -typedef int32_t Color; +typedef uint32_t Color; enum Specialization { diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c44cbd2ae4..3f38762caa 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -115,4 +115,12 @@ namespace Resource instance->accept(visitor); } + void SceneManager::releaseGLObjects(osg::State *state) + { + for (Index::iterator it = mIndex.begin(); it != mIndex.end(); ++it) + { + it->second->releaseGLObjects(state); + } + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 3d439c1867..7b3bcb2d54 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -41,6 +41,8 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; + void releaseGLObjects(osg::State* state); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; From 173887c2d9a856dbb213ced2f7e3cb51385906a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 21:19:16 +0100 Subject: [PATCH 0082/1812] AlphaController copy fix --- components/nifosg/controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index eca5a7d79a..76d3c5e62d 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -364,6 +364,7 @@ AlphaController::AlphaController() AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) + , mData(copy.mData) { } From 00deacc27e13a5fcd6cb4d3b859d2ed64a971ca7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 21:26:16 +0100 Subject: [PATCH 0083/1812] OpenCS: lighting modes --- apps/opencs/view/render/lighting.cpp | 3 +- apps/opencs/view/render/lighting.hpp | 19 +++++++----- apps/opencs/view/render/lightingbright.cpp | 29 ++++++++++-------- apps/opencs/view/render/lightingbright.hpp | 10 +++---- apps/opencs/view/render/lightingday.cpp | 31 +++++++++++--------- apps/opencs/view/render/lightingday.hpp | 7 ++--- apps/opencs/view/render/lightingnight.cpp | 30 ++++++++++--------- apps/opencs/view/render/lightingnight.hpp | 8 ++--- apps/opencs/view/render/scenewidget.cpp | 34 +++++++++++++++------- apps/opencs/view/render/scenewidget.hpp | 4 +-- 10 files changed, 98 insertions(+), 77 deletions(-) diff --git a/apps/opencs/view/render/lighting.cpp b/apps/opencs/view/render/lighting.cpp index 3553ef58cc..8e068168f5 100644 --- a/apps/opencs/view/render/lighting.cpp +++ b/apps/opencs/view/render/lighting.cpp @@ -1,4 +1,5 @@ - #include "lighting.hpp" +#include + CSVRender::Lighting::~Lighting() {} diff --git a/apps/opencs/view/render/lighting.hpp b/apps/opencs/view/render/lighting.hpp index eb8c97b129..a4315d02fa 100644 --- a/apps/opencs/view/render/lighting.hpp +++ b/apps/opencs/view/render/lighting.hpp @@ -1,13 +1,13 @@ #ifndef OPENCS_VIEW_LIGHTING_H #define OPENCS_VIEW_LIGHTING_H -namespace osgViewer -{ - class View; -} +#include + namespace osg { class Vec4f; + class LightSource; + class Group; } namespace CSVRender @@ -16,14 +16,19 @@ namespace CSVRender { public: + Lighting() : mRootNode(0) {} virtual ~Lighting(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0) = 0; + virtual void activate (osg::Group* rootNode) = 0; virtual void deactivate() = 0; - virtual void setDefaultAmbient (const osg::Vec4f& colour) = 0; + virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient) = 0; + + protected: + + osg::ref_ptr mLightSource; + osg::Group* mRootNode; }; } diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 6d3d4d7906..035e57c562 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -1,30 +1,35 @@ #include "lightingbright.hpp" -#include +#include -#include +CSVRender::LightingBright::LightingBright() {} -CSVRender::LightingBright::LightingBright() : mView(NULL) {} - -void CSVRender::LightingBright::activate (osgViewer::View* view, - const osg::Vec4f* /*defaultAmbient*/) +void CSVRender::LightingBright::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; - // FIXME: ambient should be applied to LightModel instead of the light + mLightSource = (new osg::LightSource); osg::ref_ptr light (new osg::Light); - light->setConstantAttenuation(1.f); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - light->setAmbient(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + light->setConstantAttenuation(1.f); - mView->setLight(light); + mLightSource->setLight(light); + + mRootNode->addChild(mLightSource); } void CSVRender::LightingBright::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingBright::setDefaultAmbient (const osg::Vec4f& colour) {} +osg::Vec4f CSVRender::LightingBright::getAmbientColour(osg::Vec4f* /*defaultAmbient*/) +{ + return osg::Vec4f(1.f, 1.f, 1.f, 1.f); +} diff --git a/apps/opencs/view/render/lightingbright.hpp b/apps/opencs/view/render/lightingbright.hpp index e7ef63f0a9..bc6422814c 100644 --- a/apps/opencs/view/render/lightingbright.hpp +++ b/apps/opencs/view/render/lightingbright.hpp @@ -3,27 +3,25 @@ #include "lighting.hpp" -namespace Ogre +namespace osg { class Light; + class Group; } namespace CSVRender { class LightingBright : public Lighting { - osgViewer::View* mView; - public: LightingBright(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient); }; } diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index 1d8444bc37..376f3e4321 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -1,33 +1,36 @@ #include "lightingday.hpp" -#include +#include -CSVRender::LightingDay::LightingDay() : mView(NULL) {} +CSVRender::LightingDay::LightingDay(){} -void CSVRender::LightingDay::activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient) +void CSVRender::LightingDay::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; + + mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); - if (defaultAmbient) - light->setAmbient(*defaultAmbient); - else - light->setAmbient(osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f)); - - mView->setLight(light); + mLightSource->setLight(light); + mRootNode->addChild(mLightSource); } void CSVRender::LightingDay::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingDay::setDefaultAmbient (const osg::Vec4f& colour) +osg::Vec4f CSVRender::LightingDay::getAmbientColour(osg::Vec4f *defaultAmbient) { - if (mView) - mView->getLight()->setAmbient(colour); + if (defaultAmbient) + return *defaultAmbient; + else + return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.f); } diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index a0f39b866a..407933ec66 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -12,18 +12,15 @@ namespace CSVRender { class LightingDay : public Lighting { - osgViewer::View* mView; - public: LightingDay(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient); }; } diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 81236ec13a..18a12d63d5 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -1,33 +1,37 @@ #include "lightingnight.hpp" -#include +#include -CSVRender::LightingNight::LightingNight() : mView(NULL) {} +CSVRender::LightingNight::LightingNight() {} -void CSVRender::LightingNight::activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient) +void CSVRender::LightingNight::activate (osg::Group* rootNode) { - mView = view; + mRootNode = rootNode; + + mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); - if (defaultAmbient) - light->setAmbient(*defaultAmbient); - else - light->setAmbient(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); + mLightSource->setLight(light); - mView->setLight(light); + mRootNode->addChild(mLightSource); } void CSVRender::LightingNight::deactivate() { + if (mRootNode && mLightSource.get()) + mRootNode->removeChild(mLightSource); } -void CSVRender::LightingNight::setDefaultAmbient (const osg::Vec4f& colour) +osg::Vec4f CSVRender::LightingNight::getAmbientColour(osg::Vec4f *defaultAmbient) { - if (mView) - mView->getLight()->setAmbient(colour); + if (defaultAmbient) + return *defaultAmbient; + else + return osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f); } diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index b2fd178932..8743cc438b 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -12,18 +12,14 @@ namespace CSVRender { class LightingNight : public Lighting { - osgViewer::View* mView; - public: LightingNight(); - virtual void activate (osgViewer::View* view, - const osg::Vec4f *defaultAmbient = 0); - + virtual void activate (osg::Group* rootNode); virtual void deactivate(); - virtual void setDefaultAmbient (const osg::Vec4f& colour); + virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient); }; } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ef2d701c60..5937759701 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -61,7 +63,8 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mRootNode = new osg::Group; - addDefaultRootState(mRootNode->getOrCreateStateSet()); + mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mView->getCamera()->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); mView->setSceneData(mRootNode); @@ -75,12 +78,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) viewer.realize(); } -void RenderWidget::addDefaultRootState(osg::StateSet* stateset) -{ - stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); -} - RenderWidget::~RenderWidget() { CompositeViewer::get().removeView(mView); @@ -138,8 +135,10 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, : RenderWidget(parent, f) , mSceneManager(sceneManager) , mLighting(NULL) + , mHasDefaultAmbient(false) { - //mView->setLightingMode(osgViewer::View::NO_LIGHT); + // we handle lighting manually + mView->setLightingMode(osgViewer::View::NO_LIGHT); setLighting(&mLightingDay); } @@ -156,11 +155,25 @@ void SceneWidget::setLighting(Lighting *lighting) mLighting->deactivate(); mLighting = lighting; - mLighting->activate (mView.get(), mHasDefaultAmbient ? &mDefaultAmbient : 0); + mLighting->activate (mRootNode); + + osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0); + setAmbient(ambient); flagAsModified(); } +void SceneWidget::setAmbient(const osg::Vec4f& ambient) +{ + osg::ref_ptr stateset = new osg::StateSet; + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(ambient); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + mRootNode->setStateSet(stateset); +} + void SceneWidget::selectLightingMode (const std::string& mode) { if (mode=="day") @@ -204,8 +217,7 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) mDefaultAmbient = colour; mHasDefaultAmbient = true; - if (mLighting) - mLighting->setDefaultAmbient (colour); + setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 8580a2bb1a..acfc0bbd48 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -46,8 +46,6 @@ namespace CSVRender protected: - void addDefaultRootState(osg::StateSet* stateset); - osg::ref_ptr mView; osg::Group* mRootNode; @@ -74,6 +72,8 @@ namespace CSVRender void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. + void setAmbient(const osg::Vec4f& ambient); + Resource::SceneManager* mSceneManager; Lighting* mLighting; From 6183926732771d401b257fc64653be27ef5b07ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Mar 2015 22:21:16 +0100 Subject: [PATCH 0084/1812] Particle fix --- components/nifosg/particle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c6e5fa9a8b..c86a79af87 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -81,8 +81,8 @@ void ParticleShooter::shoot(osgParticle::Particle *particle) const { float hdir = mHorizontalDir + mHorizontalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); float vdir = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - float vdir2 = mVerticalDir + mVerticalAngle * (2.f * (std::rand() / static_cast(RAND_MAX)) - 1.f); - osg::Vec3f dir = (osg::Quat(vdir2, osg::Vec3f(1,0,0)) * osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) + + osg::Vec3f dir = (osg::Quat(vdir, osg::Vec3f(0,1,0)) * osg::Quat(hdir, osg::Vec3f(0,0,1))) * osg::Vec3f(0,0,1); float vel = mMinSpeed + (mMaxSpeed - mMinSpeed) * std::rand() / static_cast(RAND_MAX); From a7272b73d07de539bf0ed2c0181a198546becd98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 04:12:54 +0200 Subject: [PATCH 0085/1812] Add utility for assembling body parts / equipment --- components/CMakeLists.txt | 2 +- components/sceneutil/attach.cpp | 185 ++++++++++++++++++++++++++++++++ components/sceneutil/attach.hpp | 25 +++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/attach.cpp create mode 100644 components/sceneutil/attach.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 47fcf24990..9d9ae4f314 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -43,7 +43,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone + clone attach ) add_component_dir (nif diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp new file mode 100644 index 0000000000..7cfb80b5c2 --- /dev/null +++ b/components/sceneutil/attach.cpp @@ -0,0 +1,185 @@ +#include "attach.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace SceneUtil +{ + + class FindByNameVisitor : public osg::NodeVisitor + { + public: + FindByNameVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node) + { + osg::Group* group = node.asGroup(); + if (group && node.getName() == mNameToFind) + { + mFoundNode = group; + return; + } + traverse(node); + } + + const std::string& mNameToFind; + osg::Group* mFoundNode; + }; + + /// Copy the skeleton-space matrix of a "source" bone to a "dest" bone (the bone that the callback is attached to). + /// Must be set on a Bone. + class CopyController : public osg::NodeCallback + { + public: + CopyController(osgAnimation::Bone* copyFrom) + : mCopyFrom(copyFrom) + { + } + CopyController(const CopyController& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + , mCopyFrom(copy.mCopyFrom) + { + } + CopyController() + : mCopyFrom(NULL) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgAnimation::Bone* bone = static_cast(node); + + if (mCopyFrom) + { + bone->setMatrix(mCopyFrom->getMatrix()); + bone->setMatrixInSkeletonSpace(mCopyFrom->getMatrixInSkeletonSpace()); + } + + traverse(node, nv); + } + + private: + const osgAnimation::Bone* mCopyFrom; + }; + + class AddCopyControllerVisitor : public osg::NodeVisitor + { + public: + AddCopyControllerVisitor(const osgAnimation::BoneMap& boneMap) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mBoneMap(boneMap) + { + } + + virtual void apply(osg::MatrixTransform &node) + { + if (osgAnimation::Bone* bone = dynamic_cast(&node)) + { + osgAnimation::BoneMap::const_iterator found = mBoneMap.find(bone->getName()); + if (found != mBoneMap.end()) + { + bone->setUpdateCallback(new CopyController(found->second.get())); + } + } + } + + private: + const osgAnimation::BoneMap& mBoneMap; + }; + + // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later + class FilterVisitor : public osg::NodeVisitor + { + public: + FilterVisitor(const std::string& filter) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mFilter(filter) + { + } + + virtual void apply(osg::Geode &node) + { + if (node.getName().find(mFilter) == std::string::npos) + { + mToRemove.push_back(&node); + } + } + + void removeFilteredParts() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Geode* geode = *it; + geode->getParent(0)->removeChild(geode); + } + } + + private: + std::vector mToRemove; + const std::string& mFilter; + }; + + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) + { + if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) + { + osgAnimation::Skeleton* masterSkel = dynamic_cast(master); + osgAnimation::BoneMapVisitor boneMapVisitor; + masterSkel->accept(boneMapVisitor); + + AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); + toAttach->accept(visitor); + + FilterVisitor filterVisitor(filter); + toAttach->accept(filterVisitor); + filterVisitor.removeFilteredParts(); + + master->asGroup()->addChild(skel); + return skel; + } + else + { + FindByNameVisitor find(attachNode); + master->accept(find); + if (!find.mFoundNode) + throw std::runtime_error(std::string("Can't find attachment node ") + attachNode); + + if (attachNode.find("Left") != std::string::npos) + { + osg::ref_ptr trans = new osg::PositionAttitudeTransform; + trans->setScale(osg::Vec3f(-1.f, 1.f, 1.f)); + + // Need to invert culling because of the negative scale + // Note: for absolute correctness we would need to check the current front face for every mesh then invert it + // However MW isn't doing this either, so don't. Assuming all meshes are using backface culling is more efficient. + osg::FrontFace* frontFace = new osg::FrontFace; + frontFace->setMode(osg::FrontFace::CLOCKWISE); + toAttach->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + find.mFoundNode->addChild(trans); + trans->addChild(toAttach); + return trans; + } + else + { + find.mFoundNode->addChild(toAttach); + return toAttach; + } + } + } + +} diff --git a/components/sceneutil/attach.hpp b/components/sceneutil/attach.hpp new file mode 100644 index 0000000000..72f7809e9d --- /dev/null +++ b/components/sceneutil/attach.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_ATTACH_H +#define OPENMW_COMPONENTS_SCENEUTIL_ATTACH_H + +#include + +#include + +namespace osg +{ + class Node; +} + +namespace SceneUtil +{ + + /// Attach parts of the \a toAttach scenegraph to the \a master scenegraph, using the specified filter and attachment node. + /// If the \a toAttach scene graph contains skinned objects, we will attach only those (filtered by the \a filter). + /// Otherwise, just attach all of the toAttach scenegraph to the attachment node on the master scenegraph, with no filtering. + /// @note The master scene graph is expected to include a skeleton. + /// @return A newly created node that is directly attached to the master scene graph + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, const std::string& attachNode); + +} + +#endif From 5162e9c09efbc5158dea0f6750b52f96a3a1f8bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 18:44:46 +0200 Subject: [PATCH 0086/1812] Add comment --- components/sceneutil/attach.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 7cfb80b5c2..6208d01528 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -141,6 +141,8 @@ namespace SceneUtil osgAnimation::BoneMapVisitor boneMapVisitor; masterSkel->accept(boneMapVisitor); + // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible + // due to a difference in binding pose of the two skeletons AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); toAttach->accept(visitor); From 9975ec1678a011e4b04fb7cad9c9296f04981e80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Mar 2015 19:32:55 +0200 Subject: [PATCH 0087/1812] Missing clone function --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ace14c6690..9006c16efc 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -334,6 +334,8 @@ namespace { } + META_Object(NifOsg, DirtyBoundCallback) + void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::Geode* geode = node->asGeode(); From 34934f016ad0b8d92dc9f77ff6492252a2c584b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 01:51:50 +0200 Subject: [PATCH 0088/1812] Remove obsoleted OpenCS settings and comment non-ported settings --- apps/opencs/model/settings/usersettings.cpp | 34 +++------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 0aa1cb4ad7..ed8fbf6d0c 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -12,8 +12,6 @@ #include #include -#include - /** * Workaround for problems with whitespaces in paths in older versions of Boost library */ @@ -44,13 +42,9 @@ CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0; void CSMSettings::UserSettings::buildSettingModelDefaults() { - QString section; - + /* declareSection ("3d-render", "3D Rendering"); { - Setting *shaders = createSetting (Type_CheckBox, "shaders", "Enable Shaders"); - shaders->setDefaultValue ("true"); - Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance"); farClipDist->setDefaultValue (300000); farClipDist->setRange (0, 1000000); @@ -62,23 +56,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() << defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16"); antialiasing->setDefaultValue (defaultValue); } + */ - declareSection ("3d-render-adv", "3D Rendering (Advanced)"); - { - Setting *numLights = createSetting (Type_SpinBox, "num_lights", - "Number of lights per pass"); - numLights->setDefaultValue (8); - numLights->setRange (1, 100); - } - + /* declareSection ("scene-input", "Scene Input"); { - Setting *timer = createSetting (Type_SpinBox, "timer", "Input responsiveness"); - timer->setDefaultValue (20); - timer->setRange (1, 100); - timer->setToolTip ("The time between two checks for user input in milliseconds.

" - "Lower value result in higher responsiveness."); - Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor", "Fast movement factor"); fastFactor->setDefaultValue (4); @@ -86,6 +68,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() fastFactor->setToolTip ( "Factor by which movement is speed up while the shift key is held down."); } + */ declareSection ("window", "Window"); { @@ -470,15 +453,6 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, { mSettingDefinitions->setValue (settingKey ,list); - if(settingKey == "3d-render-adv/num_lights" && !list.empty()) - { - //sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString()); - } - else if(settingKey == "3d-render/shaders" && !list.empty()) - { - //sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false); - } - emit userSettingUpdated (settingKey, list); } From a474c7202623da429cbf535868de48bf87bc0b91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 17:11:15 +0200 Subject: [PATCH 0089/1812] Archive priority fix --- components/vfs/registerarchives.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index cd077356f7..69d4498bb5 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -11,13 +11,6 @@ namespace VFS { const Files::PathContainer& dataDirs = collections.getPaths(); - if (useLooseFiles) - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) - { - // Last data dir has the highest priority - vfs->addArchive(new FileSystemArchive(iter->string())); - } - for (std::vector::const_iterator archive = archives.begin(); archive != archives.end(); ++archive) { if (collections.doesExist(*archive)) @@ -36,6 +29,13 @@ namespace VFS } } + if (useLooseFiles) + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + // Last data dir has the highest priority + vfs->addArchive(new FileSystemArchive(iter->string())); + } + vfs->buildIndex(); } From 12f27123f2b3796d0dd02228da63bfa503ca9b6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Mar 2015 17:11:27 +0200 Subject: [PATCH 0090/1812] Billboard scaling fix and culling bug fix --- CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 69 ++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0785ef28cd..cde53f27a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9006c16efc..555105e354 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -210,36 +210,49 @@ namespace } }; - // Custom node used to have a transform always oriented towards the camera. Can have translation and scale + // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. - class BillboardNode : public osg::MatrixTransform + class BillboardCallback : public osg::NodeCallback { public: - BillboardNode() : osg::MatrixTransform() {} - BillboardNode(const BillboardNode& copy, const osg::CopyOp& copyop) - : osg::MatrixTransform(copy, copyop) {} - BillboardNode(const osg::Matrix& matrix) - : osg::MatrixTransform(matrix) {} - - META_Node(NifOsg, BillboardNode) - - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + BillboardCallback() { - if (_referenceFrame==RELATIVE_RF) - { - const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + } + BillboardCallback(const BillboardCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } - matrix.preMult(_matrix); - matrix.setRotate(osg::Quat()); - matrix(0,0) = userdata->mScale; - matrix(1,1) = userdata->mScale; - matrix(2,2) = userdata->mScale; - } - else // absolute + META_Object(NifOsg, BillboardCallback) + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::MatrixTransform* billboardNode = dynamic_cast(node); + if (billboardNode && cv) { - matrix = _matrix; + osg::Matrix modelView = *cv->getModelViewMatrix(); + + // attempt to preserve scale + float mag[3]; + for (int i=0;i<3;++i) + { + mag[i] = std::sqrt(modelView(0,i) * modelView(0,i) + modelView(1,i) * modelView(1,i) + modelView(2,i) * modelView(2,i)); + } + + modelView.setRotate(osg::Quat()); + modelView(0,0) = mag[0]; + modelView(1,1) = mag[1]; + modelView(2,2) = mag[2]; + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); } - return true; + else + traverse(node, nv); } }; @@ -639,11 +652,7 @@ namespace NifOsg std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode = new BillboardNode(toMatrix(nifNode->trafo)); - } - else if (createSkeleton) + if (createSkeleton) { osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; @@ -655,6 +664,10 @@ namespace NifOsg { transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode->addCullCallback(new BillboardCallback); + } if (parentNode) parentNode->addChild(transformNode); From 4e69e7cc0f0271f3185953683efd9201252ddc24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Apr 2015 17:02:15 +0200 Subject: [PATCH 0091/1812] OpenMW compiles and runs w/o render window --- CMakeLists.txt | 8 +- apps/openmw/CMakeLists.txt | 30 +- apps/openmw/engine.cpp | 66 +- apps/openmw/engine.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/npc.cpp | 8 +- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/cursor.cpp | 2 - apps/openmw/mwgui/formatting.cpp | 5 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 13 +- apps/openmw/mwgui/itemwidget.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 27 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/race.cpp | 29 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 3 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 6 +- apps/openmw/mwgui/videowidget.cpp | 22 +- apps/openmw/mwgui/videowidget.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 66 +- apps/openmw/mwmechanics/actor.cpp | 8 +- apps/openmw/mwmechanics/aicombat.cpp | 10 +- apps/openmw/mwmechanics/alchemy.cpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 72 +- .../mwmechanics/mechanicsmanagerimp.hpp | 8 +- apps/openmw/mwmechanics/spellcasting.cpp | 16 +- apps/openmw/mwmechanics/summoning.cpp | 6 +- apps/openmw/mwrender/actors.cpp | 50 +- apps/openmw/mwrender/actors.hpp | 31 +- apps/openmw/mwrender/objects.cpp | 108 +-- apps/openmw/mwrender/objects.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 36 +- apps/openmw/mwrender/renderingmanager.hpp | 7 - apps/openmw/mwscript/interpretercontext.cpp | 2 + apps/openmw/mwsound/soundmanagerimp.cpp | 3 + apps/openmw/mwworld/physicssystem.cpp | 28 +- apps/openmw/mwworld/scene.cpp | 57 +- apps/openmw/mwworld/scene.hpp | 9 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 259 ++++---- apps/openmw/mwworld/worldimp.hpp | 22 +- cmake/FindMyGUI.cmake | 10 +- components/CMakeLists.txt | 4 - components/esm/esmreader.cpp | 3 +- components/esm/esmreader.hpp | 5 + components/fontloader/fontloader.cpp | 2 + components/nifoverrides/nifoverrides.cpp | 80 --- components/nifoverrides/nifoverrides.hpp | 38 -- files/transparency-overrides.cfg | 623 ------------------ libs/openengine/CMakeLists.txt | 4 +- 55 files changed, 534 insertions(+), 1286 deletions(-) delete mode 100644 components/nifoverrides/nifoverrides.cpp delete mode 100644 components/nifoverrides/nifoverrides.hpp delete mode 100644 files/transparency-overrides.cfg diff --git a/CMakeLists.txt b/CMakeLists.txt index cde53f27a5..bf525646d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,9 +328,6 @@ endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}/settings-default.cfg") -configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg - "${OpenMW_BINARY_DIR}/transparency-overrides.cfg") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local "${OpenMW_BINARY_DIR}/openmw.cfg") @@ -433,7 +430,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") @@ -456,7 +452,6 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" - "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -549,7 +544,7 @@ add_subdirectory(libs/openengine) # Extern #add_subdirectory (extern/shiny) #add_subdirectory (extern/ogre-ffmpeg-videoplayer) -#add_subdirectory (extern/oics) +add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) # Components @@ -714,7 +709,6 @@ if (APPLE) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a183d172dc..56ee82d7d5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,15 +20,16 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation - actors objects renderinginterface localmap occlusionquery water shadows - characterpreview globalmap ripplesimulation refraction - terrainstorage renderconst effectmanager weaponanimation +actors objects +# renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation +# renderinginterface localmap occlusionquery water shadows +# characterpreview globalmap ripplesimulation refraction +# terrainstorage renderconst effectmanager weaponanimation ) -add_openmw_dir (mwinput - inputmanagerimp - ) +#add_openmw_dir (mwinput +# inputmanagerimp +# ) add_openmw_dir (mwgui textinput widgets race class birth review windowmanagerimp console dialogue @@ -57,16 +58,18 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper +# movieaudiofactory ) add_openmw_dir (mwworld - refdata worldimp physicssystem scene globals class action nullaction actionteleport + refdata worldimp scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors failedaction - cells localscripts customdata weather inventorystore ptr actionopen actionread + cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist projectilemanager cellref + contentloader esmloader actiontrap cellreflist cellref physicssystem +# weather projectilemanager ) add_openmw_dir (mwclass @@ -75,10 +78,11 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects + mechanicsmanagerimp stat creaturestats magiceffects movement drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning +# character actors objects ) add_openmw_dir (mwstate @@ -133,9 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - "ogre-ffmpeg-videoplayer" "oics" - "sdl4ogre" components ) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a4bb8c5380..c7a92e52e3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -14,17 +14,14 @@ #include -#include #include #include -#include #include -#include #include -#include "mwinput/inputmanagerimp.hpp" +//#include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" @@ -86,12 +83,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.setFrameDuration (frametime); // update input - MWBase::Environment::get().getInputManager()->update(frametime, false); + //MWBase::Environment::get().getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. - if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) - return true; + //if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) + // return true; // sound if (mUseSound) @@ -157,11 +154,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { +#if 0 Ogre::RenderWindow* window = mOgre->getWindow(); unsigned int tri, batch; MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - +#endif MWBase::Environment::get().getWindowManager()->update(); } } @@ -210,11 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - if (mOgre) - mOgre->restoreWindowGammaRamp(); mEnvironment.cleanup(); delete mScriptContext; - delete mOgre; SDL_Quit(); } @@ -223,14 +218,10 @@ OMW::Engine::~Engine() void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) { - mOgre->getRoot()->addResourceLocation (path.string(), "FileSystem", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } void OMW::Engine::addZipResource (const boost::filesystem::path& path) { - mOgre->getRoot()->addResourceLocation (path.string(), "Zip", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false); } void OMW::Engine::enableFSStrict(bool fsStrict) @@ -299,19 +290,6 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - // load nif overrides - NifOverrides::Overrides nifOverrides; - std::string transparencyOverrides = "/transparency-overrides.cfg"; - std::string materialOverrides = "/material-overrides.cfg"; - if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides)) - nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides); - else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides)) - nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + transparencyOverrides); - if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + materialOverrides)) - nifOverrides.loadMaterialOverrides(mCfgMgr.getLocalPath().string() + materialOverrides); - else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + materialOverrides)) - nifOverrides.loadMaterialOverrides(mCfgMgr.getGlobalPath().string() + materialOverrides); - return settingspath; } @@ -330,13 +308,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) #endif } - mOgre = new OEngine::Render::OgreRenderer; - - mOgre->configure( - mCfgMgr.getLogPath().string(), - renderSystem, - Settings::Manager::getString("opengl rtt mode", "Video")); - // This has to be added BEFORE MyGUI is initialized, as it needs // to find core.xml here. @@ -361,9 +332,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - mOgre->createWindow("OpenMW", windowSettings); - - Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); + //Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -390,19 +359,17 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); - mEnvironment.setInputManager (input); + //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + //mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, NULL, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); - mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); - if (!mSkipMenu) { std::string logo = mFallbackMap["Movies_Company_Logo"]; @@ -411,11 +378,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles, + mEnvironment.setWorld( new MWWorld::World (mFileCollections, mContentFiles, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); - input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); window->renderWorldMap(); @@ -443,7 +410,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); - mOgre->getRoot()->addFrameListener (this); + //mOgre->getRoot()->addFrameListener (this); // scripts if (mCompileAll) @@ -473,7 +440,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { assert (!mContentFiles.empty()); - assert (!mOgre); + //assert (!mOgre); Settings::Manager settings; std::string settingspath; @@ -514,6 +481,7 @@ void OMW::Engine::go() } // Start the main rendering loop + /* Ogre::Timer timer; while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) { @@ -523,6 +491,8 @@ void OMW::Engine::go() timer.reset(); Ogre::Root::getSingleton().renderOneFrame(dt); } + */ + // Save user settings settings.saveUser(settingspath); @@ -577,7 +547,7 @@ void OMW::Engine::screenshot() } while (boost::filesystem::exists(stream.str())); - mOgre->screenshot(stream.str(), format); + //mOgre->screenshot(stream.str(), format); } void OMW::Engine::setCompileAll (bool all) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 3b088595c0..ef26ceb3a8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -98,7 +98,7 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; - Nif::Cache mNifCache; + //Nif::Cache mNifCache; // not implemented Engine (const Engine&); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8404b95234..ac99fa4b48 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -163,17 +163,17 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = ptr.get(); + //MWWorld::LiveCellRef *ref = ptr.get(); - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + //MWRender::Actors& actors = renderingInterface.getActors(); + //actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { if(!model.empty()) { - physics.addActor(ptr, model); + //physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1d58dc87e3..3dcb57fbba 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include @@ -1151,9 +1149,9 @@ namespace MWClass if (ptr.getClass().getNpcStats(ptr).isWerewolf() && ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)) { - MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; - MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); - if (weaponType == MWMechanics::WeapType_None) + //MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; + //MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); + //if (weaponType == MWMechanics::WeapType_None) return ""; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 668253712d..475428f335 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -183,7 +183,7 @@ namespace MWGui const ESM::BirthSign *birth = store.get().find(mCurrentBirthId); - mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); + //mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); std::vector abilities, powers, spells; diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 9c64f94caa..82e0b9699b 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -5,8 +5,6 @@ #include #include -#include - namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 761a89ca62..d96255c859 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,8 +1,5 @@ #include "formatting.hpp" -#include -#include - #include #include #include @@ -466,7 +463,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); + std::string image;// = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index eb458be500..2323d39e71 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -448,7 +448,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - icon = Misc::ResourceHelpers::correctIconPath(icon); + //icon = Misc::ResourceHelpers::correctIconPath(icon); mSpellImage->setItem(MWWorld::Ptr()); mSpellImage->setIcon(icon); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 80b246e840..c3932d388a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -53,7 +53,9 @@ namespace MWGui , mTrading(false) , mLastXSize(0) , mLastYSize(0) + #if 0 , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) + #endif , mPreviewDirty(true) , mPreviewResize(true) , mDragAndDrop(dragAndDrop) @@ -118,10 +120,10 @@ namespace MWGui MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); if (tex) MyGUI::RenderManager::getInstance().destroyTexture(tex); - +#if 0 mPreview.reset(new MWRender::InventoryPreview(mPtr)); mPreview->setup(); - +#endif mPreviewDirty = true; mPreviewResize = true; } @@ -481,6 +483,8 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { + return MWWorld::Ptr(); +#if 0 int slot = mPreview->getSlotSelected (x, y); if (slot == -1) @@ -499,6 +503,7 @@ namespace MWGui } return MWWorld::Ptr(); +#endif } void InventoryWindow::updateEncumbranceBar() @@ -526,6 +531,7 @@ namespace MWGui void InventoryWindow::doRenderUpdate () { +#if 0 mPreview->onFrame(); if (mPreviewResize || mPreviewDirty) @@ -552,6 +558,7 @@ namespace MWGui mAvatarImage->setImageTexture("CharacterPreview"); } +#endif } void InventoryWindow::notifyContentChanged() @@ -668,6 +675,8 @@ namespace MWGui void InventoryWindow::rebuildAvatar() { +#if 0 mPreview->rebuild(); +#endif } } diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 36940113e1..1da2ab8797 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -77,7 +77,7 @@ namespace MWGui void ItemWidget::setIcon(const MWWorld::Ptr &ptr) { - setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); + //setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 02e8ffdfed..d65e242def 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -212,6 +212,7 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { +#if 0 for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -225,6 +226,7 @@ namespace MWGui : ""); } } +#endif redraw(); } @@ -338,6 +340,7 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures +#if 0 for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -354,7 +357,7 @@ namespace MWGui box->setImageTexture("black.png"); } } - +#endif MWBase::World* world = MWBase::Environment::get().getWorld(); // Retrieve the door markers we want to show @@ -558,7 +561,7 @@ namespace MWGui , LocalMapBase(customMarkers) , mGlobal(false) , mGlobalMap(0) - , mGlobalMapRender(0) + //, mGlobalMapRender(0) , mEditNoteDialog() , mEventBoxGlobal(NULL) , mEventBoxLocal(NULL) @@ -705,18 +708,19 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { +#if 0 mGlobalMapRender = new MWRender::GlobalMap(""); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setImageTexture("GlobalMap.png"); mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); +#endif } MapWindow::~MapWindow() { - delete mGlobalMapRender; + //delete mGlobalMapRender; } void MapWindow::setCellName(const std::string& cellName) @@ -726,6 +730,7 @@ namespace MWGui void MapWindow::addVisitedLocation(const std::string& name, int x, int y) { +#if 0 CellId cell; cell.first = x; cell.second = y; @@ -752,6 +757,7 @@ namespace MWGui markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); } +#endif } void MapWindow::cellExplored(int x, int y) @@ -763,10 +769,12 @@ namespace MWGui { LocalMapBase::onFrame(dt); +#if 0 for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { mGlobalMapRender->exploreCell(it->first, it->second); } +#endif mQueuedToExplore.clear(); NoDrop::onFrame(dt); @@ -823,12 +831,14 @@ namespace MWGui void MapWindow::globalMapUpdatePlayer () { +#if 0 // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); setGlobalMapPlayerPosition(pos.x, pos.y); } +#endif } void MapWindow::notifyPlayerUpdate () @@ -838,6 +848,7 @@ namespace MWGui void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) { +#if 0 float x, y; mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y); x *= mGlobalMapRender->getWidth(); @@ -849,6 +860,7 @@ namespace MWGui MyGUI::IntSize viewsize = mGlobalMap->getSize(); MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); +#endif } void MapWindow::setGlobalMapPlayerDir(const float x, const float y) @@ -863,7 +875,8 @@ namespace MWGui void MapWindow::clear() { mMarkers.clear(); - mGlobalMapRender->clear(); + + //mGlobalMapRender->clear(); mChanged = true; while (mEventBoxGlobal->getChildCount()) @@ -872,6 +885,7 @@ namespace MWGui void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) { +#if 0 ESM::GlobalMap map; mGlobalMapRender->write(map); @@ -880,10 +894,12 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); +#endif } void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { +#if 0 if (type == ESM::REC_GMAP) { ESM::GlobalMap map; @@ -898,6 +914,7 @@ namespace MWGui addVisitedLocation(cell->mName, it->first, it->second); } } +#endif } void MapWindow::setAlpha(float alpha) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a80b3e4c59..68d2e28de5 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -216,7 +216,7 @@ namespace MWGui MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; - MWRender::GlobalMap* mGlobalMapRender; + //MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8f595df803..5c0fd773d9 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -245,7 +245,7 @@ namespace MWGui std::string path = effect->mIcon; int slashPos = path.rfind('\\'); path.insert(slashPos+1, "b_"); - path = Misc::ResourceHelpers::correctIconPath(path); + //path = Misc::ResourceHelpers::correctIconPath(path); button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); button->setIcon(path); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index f908a9dd0d..af4332c7ca 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -125,18 +125,19 @@ namespace MWGui updateSkills(); updateSpellPowers(); - mPreview.reset(NULL); + //mPreview.reset(NULL); mPreviewImage->setImageTexture(""); const std::string textureName = "CharacterHeadPreview"; MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - mPreview.reset(new MWRender::RaceSelectionPreview()); - mPreview->setup(); - mPreview->update (mCurrentAngle); + //mPreview.reset(new MWRender::RaceSelectionPreview()); + //mPreview->setup(); + //mPreview->update (mCurrentAngle); - const ESM::NPC proto = mPreview->getPrototype(); + //const ESM::NPC& proto = mPreview->getPrototype(); + ESM::NPC proto; setRaceId(proto.mRace); recountParts(); @@ -184,7 +185,7 @@ namespace MWGui mPreviewImage->setImageTexture(""); const std::string textureName = "CharacterHeadPreview"; MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - mPreview.reset(NULL); + //mPreview.reset(NULL); } // widget controls @@ -204,7 +205,7 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; - mPreview->update (angle); + //mPreview->update (angle); mPreviewDirty = true; mCurrentAngle = angle; } @@ -316,7 +317,7 @@ namespace MWGui void RaceDialog::updatePreview() { - ESM::NPC record = mPreview->getPrototype(); + ESM::NPC record;// = mPreview->getPrototype(); record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); @@ -325,7 +326,7 @@ namespace MWGui try { - mPreview->setPrototype(record); + //mPreview->setPrototype(record); } catch (std::exception& e) { @@ -337,13 +338,13 @@ namespace MWGui void RaceDialog::doRenderUpdate() { - if (!mPreview.get()) + //if (!mPreview.get()) return; - mPreview->onFrame(); + //mPreview->onFrame(); if (mPreviewDirty) { - mPreview->render(); + //mPreview->render(); mPreviewDirty = false; } } @@ -450,6 +451,8 @@ namespace MWGui const ESM::NPC& RaceDialog::getResult() const { - return mPreview->getPrototype(); + static ESM::NPC result; + return result; + //return mPreview->getPrototype(); } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index be16af5d1e..f188af2b30 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -108,7 +108,7 @@ namespace MWGui float mCurrentAngle; - std::auto_ptr mPreview; + //std::auto_ptr mPreview; bool mPreviewDirty; }; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d022c8e251..980afdfae4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -358,7 +358,7 @@ namespace MWGui << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); - +#if 0 // Decode screenshot std::vector data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); @@ -382,5 +382,6 @@ namespace MWGui texture->loadImage(image); mScreenshot->setImageTexture(textureName); +#endif } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index c744d3ed63..80806941c1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -180,7 +180,7 @@ namespace MWGui void EditEffectDialog::setMagicEffect (const ESM::MagicEffect *effect) { - mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + //mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); mEffectName->setCaptionWithReplacing("#{"+ESM::MagicEffect::effectIdToString (effect->mIndex)+"}"); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c597cfaebe..8770bab382 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -145,7 +145,7 @@ namespace MWGui ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); mWidgetMap[it->first] = image; - image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + //image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); std::string name = ESM::MagicEffect::effectIdToString (it->first); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4e03b788a4..8b63ab5413 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -388,7 +388,7 @@ namespace MWGui const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); - std::string realImage = Misc::ResourceHelpers::correctIconPath(image); + std::string realImage;// = Misc::ResourceHelpers::correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); @@ -686,7 +686,7 @@ namespace MWGui widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - widget->setUserString("ImageTexture_BirthSignImage", Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); + widget->setUserString("ImageTexture_BirthSignImage", "");//Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); std::string text; text += sign->mName; @@ -781,7 +781,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - icon = Misc::ResourceHelpers::correctIconPath(icon); + //icon = Misc::ResourceHelpers::correctIconPath(icon); widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index f865de377d..4ead16c5b3 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,51 +1,51 @@ #include "videowidget.hpp" -#include +//#include #include -#include "../mwsound/movieaudiofactory.hpp" +//#include "../mwsound/movieaudiofactory.hpp" namespace MWGui { VideoWidget::VideoWidget() { - mPlayer.reset(new Video::VideoPlayer()); + //mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } void VideoWidget::playVideo(const std::string &video) { - mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(video); + //mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); + //mPlayer->playVideo(video); - setImageTexture(mPlayer->getTextureName()); + //setImageTexture(mPlayer->getTextureName()); } int VideoWidget::getVideoWidth() { - return mPlayer->getVideoWidth(); + return 0;//mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return mPlayer->getVideoHeight(); + return 0;//mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return mPlayer->update(); + return 0;//mPlayer->update(); } void VideoWidget::stop() { - mPlayer->close(); + //mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return mPlayer->hasAudioStream(); + return 0;//mPlayer->hasAudioStream(); } void VideoWidget::autoResize(bool stretch) diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index ee44328eb6..75aa6e98aa 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -42,7 +42,7 @@ namespace MWGui void autoResize (bool stretch); private: - std::auto_ptr mPlayer; + //std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 718624a16f..888955391d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -474,7 +474,7 @@ namespace MWGui mTextWidget->setCaptionWithReplacing(spellLine); mRequestedWidth = mTextWidget->getTextSize().width + 24; - mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); + //mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); } MWSpellEffect::~MWSpellEffect() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 279c2f22ea..bc7bb0bb58 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,11 +19,12 @@ #include #include +#include + #include #include #include -#include #include @@ -102,7 +103,7 @@ namespace MWGui const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) - , mGuiManager(NULL) + //, mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) , mMap(NULL) @@ -177,7 +178,13 @@ namespace MWGui , mFallbackMap(fallbackMap) { // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + //mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + + MyGUI::DummyPlatform* platform = new MyGUI::DummyPlatform; + platform->initialise(logpath); + + MyGUI::Gui* gui = new MyGUI::Gui; + gui->initialise(""); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); @@ -207,11 +214,11 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); - +#if 0 mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - +#endif //set up the hardware cursor manager - mCursorManager = new SFO::SDLCursorManager(); + //mCursorManager = new SFO::SDLCursorManager(); MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); @@ -219,7 +226,7 @@ namespace MWGui onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->setEnabled(true); + //mCursorManager->setEnabled(true); // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); @@ -245,6 +252,7 @@ namespace MWGui void WindowManager::initUI() { + /* // Get size info from the Gui object int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; @@ -328,6 +336,7 @@ namespace MWGui updateVisible(); MWBase::Environment::get().getInputManager()->changeInputMode(false); + */ } void WindowManager::renderWorldMap() @@ -408,11 +417,11 @@ namespace MWGui delete mDebugWindow; delete mJailScreen; - delete mCursorManager; + //delete mCursorManager; cleanupGarbage(); - delete mGuiManager; + //delete mGuiManager; } void WindowManager::cleanupGarbage() @@ -923,6 +932,7 @@ namespace MWGui void WindowManager::changeCell(MWWorld::CellStore* cell) { + /* std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); mMap->setCellName( name ); @@ -947,10 +957,12 @@ namespace MWGui MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); } + */ } void WindowManager::setActiveMap(int x, int y, bool interior) { + /* if (!interior) { mMap->setCellPrefix("Cell"); @@ -959,19 +971,22 @@ namespace MWGui mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); + */ } void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) { - mMap->setPlayerPos(cellX, cellY, x, y); - mHud->setPlayerPos(cellX, cellY, x, y); + //mMap->setPlayerPos(cellX, cellY, x, y); + //mHud->setPlayerPos(cellX, cellY, x, y); } void WindowManager::setPlayerDir(const float x, const float y) { + /* mMap->setPlayerDir(x,y); mMap->setGlobalMapPlayerDir(x, y); mHud->setPlayerDir(x,y); + */ } void WindowManager::setDrowningBarVisibility(bool visible) @@ -1087,7 +1102,7 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { sizeVideo(x, y); - mGuiManager->windowResized(); + //mGuiManager->windowResized(); if (!mHud) return; // UI not initialized yet @@ -1133,6 +1148,7 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { + /* if(!mCursorManager->cursorChanged(name)) return; //the cursor manager doesn't want any more info about this cursor //See if we can get the information we need out of the cursor resource @@ -1157,6 +1173,7 @@ namespace MWGui mCursorManager->receiveCursorInfo(name, rotation, tex, size_x, size_y, hotspot_x, hotspot_y); } } + */ } void WindowManager::popGuiMode() @@ -1266,7 +1283,7 @@ namespace MWGui void WindowManager::executeInConsole (const std::string& path) { - mConsole->executeFile (path); + //mConsole->executeFile (path); } void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) @@ -1507,7 +1524,7 @@ namespace MWGui void WindowManager::updatePlayer() { - mInventoryWindow->updatePlayer(); + //mInventoryWindow->updatePlayer(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getNpcStats(player).isWerewolf()) @@ -1540,9 +1557,22 @@ namespace MWGui mHud->setEnemy(enemy); } + class DummyListener : public Loading::Listener + { + public: + virtual void setLabel (const std::string& label){} + virtual void loadingOn(){} + virtual void loadingOff(){} + virtual void indicateProgress (){} + virtual void setProgressRange (size_t range){} + virtual void setProgress (size_t value){} + virtual void increaseProgress (size_t increase = 1){} + }; + Loading::Listener* WindowManager::getLoadingScreen() { - return mLoadingScreen; + static DummyListener listener; + return &listener; } void WindowManager::startRecharge(MWWorld::Ptr soulgem) @@ -1779,23 +1809,29 @@ namespace MWGui void WindowManager::fadeScreenIn(const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeOut(time); + */ } void WindowManager::fadeScreenOut(const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeIn(time); + */ } void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) { + /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeTo(percent, time); + */ } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index 675bd160a3..3161bb4130 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -1,23 +1,23 @@ #include "actor.hpp" -#include "character.hpp" +//#include "character.hpp" namespace MWMechanics { Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) { - mCharacterController.reset(new CharacterController(ptr, animation)); + //mCharacterController.reset(new CharacterController(ptr, animation)); } void Actor::updatePtr(const MWWorld::Ptr &newPtr) { - mCharacterController->updatePtr(newPtr); + //mCharacterController->updatePtr(newPtr); } CharacterController* Actor::getCharacterController() { - return mCharacterController.get(); + return 0;//mCharacterController.get(); } AiState& Actor::getAiState() diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2f68087e58..e570d1c33a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -16,13 +16,13 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -#include "character.hpp" // fixme: for getActiveWeapon +//#include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" #include "combat.hpp" @@ -188,6 +188,7 @@ namespace MWMechanics */ bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { +#if 0 // get or create temporary storage AiCombatStorage& storage = state.get(); @@ -673,7 +674,7 @@ namespace MWMechanics // FIXME: can fool actors to stay behind doors, etc. // Related to Bug#1102 and to some degree #1155 as well } - +#endif return false; } @@ -811,6 +812,7 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } +#if 0 void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) { if (!actor.getClass().hasInventoryStore(actor)) // creatures @@ -873,8 +875,8 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; } - } +#endif Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, float duration, int weapType, float strength) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 58c42ddb81..319d01495a 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0d4518f875..abfc793de5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -269,7 +269,7 @@ namespace MWMechanics creatureStats.getSpells().add(*it); // forced update and current value adjustments - mActors.updateActor (ptr, 0); + //mActors.updateActor (ptr, 0); for (int i=0; i<3; ++i) { @@ -294,22 +294,27 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { + /* if(ptr.getClass().isActor()) mActors.addActor(ptr); else mObjects.addObject(ptr); + */ } void MechanicsManager::remove(const MWWorld::Ptr& ptr) { + /* if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); mObjects.removeObject(ptr); + */ } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { + /* if(old == mWatched) mWatched = ptr; @@ -317,13 +322,16 @@ namespace MWMechanics mActors.updateActor(old, ptr); else mObjects.updateObject(old, ptr); + */ } void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { + /* mActors.dropActors(cellStore, mWatched); mObjects.dropObjects(cellStore); + */ } @@ -464,24 +472,24 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - mActors.removeActor(ptr); - mActors.addActor(ptr, true); + //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + //mActors.removeActor(ptr); + //mActors.addActor(ptr, true); } - mActors.update(duration, paused); - mObjects.update(duration, paused); + //mActors.update(duration, paused); + //mObjects.update(duration, paused); } void MechanicsManager::rest(bool sleep) { - mActors.restoreDynamicStats (sleep); - mActors.fastForwardAi(); + //mActors.restoreDynamicStats (sleep); + //mActors.fastForwardAi(); } int MechanicsManager::getHoursToRest() const { - return mActors.getHoursToRest(mWatched); + return 0;//mActors.getHoursToRest(mWatched); } void MechanicsManager::setPlayerName (const std::string& name) @@ -671,7 +679,7 @@ namespace MWMechanics int MechanicsManager::countDeaths (const std::string& id) const { - return mActors.countDeaths (id); + return 0;//mActors.countDeaths (id); } void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, @@ -827,35 +835,39 @@ namespace MWMechanics void MechanicsManager::forceStateUpdate(const MWWorld::Ptr &ptr) { - if(ptr.getClass().isActor()) - mActors.forceStateUpdate(ptr); + //if(ptr.getClass().isActor()) + //mActors.forceStateUpdate(ptr); } void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { + /* if(ptr.getClass().isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else mObjects.playAnimationGroup(ptr, groupName, mode, number); + */ } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { + /* if(ptr.getClass().isActor()) mActors.skipAnimation(ptr); else mObjects.skipAnimation(ptr); + */ } bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) { - if(ptr.getClass().isActor()) - return mActors.checkAnimationPlaying(ptr, groupName); - else + //if(ptr.getClass().isActor()) + // return mActors.checkAnimationPlaying(ptr, groupName); + //else return false; } void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) { - mActors.updateMagicEffects(ptr); + //mActors.updateMagicEffects(ptr); } bool MechanicsManager::toggleAI() @@ -1050,7 +1062,7 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - mActors.getObjectsInRange(from, radius, neighbors); + //mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1139,7 +1151,7 @@ namespace MWMechanics Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - mActors.getObjectsInRange(from, radius, neighbors); + //mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1394,6 +1406,7 @@ namespace MWMechanics // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { + /* for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) @@ -1406,6 +1419,7 @@ namespace MWMechanics } } } + */ } } @@ -1416,27 +1430,27 @@ namespace MWMechanics void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - mActors.getObjectsInRange(position, radius, objects); - mObjects.getObjectsInRange(position, radius, objects); + //mActors.getObjectsInRange(position, radius, objects); + //mObjects.getObjectsInRange(position, radius, objects); } void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - mActors.getObjectsInRange(position, radius, objects); + //mActors.getObjectsInRange(position, radius, objects); } std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowing(actor); + return std::list();//mActors.getActorsFollowing(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowingIndices(actor); + return std::list(); //mActors.getActorsFollowingIndices(actor); } std::list MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) { - return mActors.getActorsFighting(actor); + return std::list();// mActors.getActorsFighting(actor); } int MechanicsManager::countSavedGameRecords() const @@ -1447,7 +1461,7 @@ namespace MWMechanics void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { - mActors.write(writer, listener); + //mActors.write(writer, listener); ESM::StolenItems items; items.mStolenItems = mStolenItems; @@ -1464,13 +1478,13 @@ namespace MWMechanics items.load(reader); mStolenItems = items.mStolenItems; } - else - mActors.readRecord(reader, type); + //else + //mActors.readRecord(reader, type); } void MechanicsManager::clear() { - mActors.clear(); + //mActors.clear(); mStolenItems.clear(); } @@ -1516,6 +1530,6 @@ namespace MWMechanics bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const { - return mActors.isReadyToBlock(ptr); + return 0;//mActors.isReadyToBlock(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d08334ae8c..30cc207f74 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,8 +7,8 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -#include "objects.hpp" -#include "actors.hpp" +//#include "objects.hpp" +//#include "actors.hpp" namespace Ogre { @@ -32,8 +32,8 @@ namespace MWMechanics bool mRaceSelected; bool mAI;///< is AI active? - Objects mObjects; - Actors mActors; + //Objects mObjects; + //Actors mActors; typedef std::pair Owner; // < Owner id, bool isFaction > typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8a43cc9322..a7d3545b3a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,7 +19,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "magiceffects.hpp" #include "npcstats.hpp" @@ -419,8 +419,8 @@ namespace MWMechanics if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); @@ -467,8 +467,8 @@ namespace MWMechanics if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); + //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); magnitudeMult = 0; } @@ -574,9 +574,9 @@ namespace MWMechanics // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); - if (anim) - anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + //MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); + //if (anim) + // anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 668031141c..daf4424c55 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -12,7 +12,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "aifollow.hpp" @@ -143,8 +143,9 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); int creatureActorId = summonedCreatureStats.getActorId(); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + /*MWWorld::Ptr placed = */MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + /* MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) { @@ -153,6 +154,7 @@ namespace MWMechanics if (fx) anim->addEffect("meshes\\" + fx->mModel, -1, false); } + */ creatureMap.insert(std::make_pair(*it, creatureActorId)); } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 3da6c40c83..878712ecc4 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,13 +6,14 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" +/* #include "animation.hpp" #include "activatoranimation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" - +*/ #include "renderconst.hpp" @@ -22,19 +23,22 @@ using namespace Ogre; Actors::~Actors() { + /* PtrAnimationMap::iterator it = mAllActors.begin(); for(;it != mAllActors.end();++it) { delete it->second; it->second = NULL; } + */ } -void Actors::setRootNode(Ogre::SceneNode* root) -{ mRootNode = root; } +//void Actors::setRootNode(Ogre::SceneNode* root) +//{ mRootNode = root; } void Actors::insertBegin(const MWWorld::Ptr &ptr) { + /* Ogre::SceneNode* cellnode; CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); if(celliter != mCellSceneNodes.end()) @@ -61,18 +65,22 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) insert->setOrientation(zr); ptr.getRefData().setBaseNode(insert); + */ } void Actors::insertNPC(const MWWorld::Ptr& ptr) { + /* insertBegin(ptr); NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); + */ } void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) { + /* insertBegin(ptr); Animation* anim = NULL; if (weaponsShields) @@ -82,9 +90,11 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); + */ } void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) { + /* insertBegin(ptr); ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); @@ -98,10 +108,12 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, delete mAllActors[ptr]; mAllActors[ptr] = anim; + */ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + /* if (mAllActors.find(ptr) == mAllActors.end()) return false; @@ -127,12 +139,13 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr) return false; } - +*/ return true; } void Actors::removeCell(MWWorld::CellStore* store) { + /* for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) { if(iter->first.getCell() == store) @@ -153,26 +166,22 @@ void Actors::removeCell(MWWorld::CellStore* store) mCellSceneNodes.erase(celliter); } -} - -void Actors::update (Ogre::Camera* camera) -{ - for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end(); ++iter) - { - iter->second->preRender(camera); - } + */ } Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) { + /* PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); if(iter != mAllActors.end()) return iter->second; + */ return NULL; } void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + /* Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); @@ -196,20 +205,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) } mRendering->updateWaterRippleEmitterPtr (old, cur); -} - -void Actors::enableLights() -{ - PtrAnimationMap::const_iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - it->second->enableLights(true); -} - -void Actors::disableLights() -{ - PtrAnimationMap::const_iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - it->second->enableLights(false); + */ } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 4f6c1bec28..887ea68d1c 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,7 +1,17 @@ #ifndef GAME_RENDER_ACTORS_H #define GAME_RENDER_ACTORS_H -#include +//#include + +#include + +namespace OEngine +{ + namespace Render + { + class OgreRenderer; + } +} namespace MWWorld { @@ -17,15 +27,15 @@ namespace MWRender class Actors { - typedef std::map CellSceneNodeMap; - typedef std::map PtrAnimationMap; + //typedef std::map CellSceneNodeMap; + //typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; MWRender::RenderingManager* mRendering; - Ogre::SceneNode* mRootNode; + //Ogre::SceneNode* mRootNode; - CellSceneNodeMap mCellSceneNodes; - PtrAnimationMap mAllActors; + //CellSceneNodeMap mCellSceneNodes; + //PtrAnimationMap mAllActors; void insertBegin(const MWWorld::Ptr &ptr); @@ -33,11 +43,11 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) : mRend(_rend) , mRendering(rendering) - , mRootNode(NULL) + //, mRootNode(NULL) {} ~Actors(); - void setRootNode(Ogre::SceneNode* root); + //void setRootNode(Ogre::SceneNode* root); void insertNPC(const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); @@ -45,13 +55,8 @@ namespace MWRender bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? - void enableLights(); - void disableLights(); - void removeCell(MWWorld::CellStore* store); - void update (Ogre::Camera* camera); - /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bdaa2d5157..3c6a507e7d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -14,7 +14,7 @@ #include #include -#include +//#include #include #include "../mwworld/ptr.hpp" @@ -22,7 +22,7 @@ #include "../mwworld/cellstore.hpp" #include "renderconst.hpp" -#include "animation.hpp" +//#include "animation.hpp" using namespace MWRender; @@ -76,7 +76,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) { insertBegin(ptr); - +/* std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); if (!mesh.empty()) @@ -96,70 +96,16 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); - if(batch && - Settings::Manager::getBool("use static geometry", "Objects") && - anim->canBatch()) - { - Ogre::StaticGeometry* sg = 0; - - if (small) - { - if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) - { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometrySmall[ptr.getCell()] = sg; - - sg->setRenderingDistance(static_cast(Settings::Manager::getInt("small object distance", "Viewing distance"))); - } - else - sg = mStaticGeometrySmall[ptr.getCell()]; - } - else - { - if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) - { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometry[ptr.getCell()] = sg; - } - else - sg = mStaticGeometry[ptr.getCell()]; - } - - // This specifies the size of a single batch region. - // If it is set too high: - // - there will be problems choosing the correct lights - // - the culling will be more inefficient - // If it is set too low: - // - there will be too many batches. - if(ptr.getCell()->isExterior()) - sg->setRegionDimensions(Ogre::Vector3(2048,2048,2048)); - else - sg->setRegionDimensions(Ogre::Vector3(1024,1024,1024)); - - sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); - - sg->setCastShadows(true); - - sg->setRenderQueueGroup(RQG_Main); - - anim->fillBatch(sg); - /* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr - * ever needs to modify we can reattach it and rebuild the StaticGeometry object without - * it. Would require associating the Ptr with the StaticGeometry. */ - anim.reset(); - } } if(anim.get() != NULL) mObjects.insert(std::make_pair(ptr, anim.release())); + */ } bool Objects::deleteObject (const MWWorld::Ptr& ptr) { + /* if(!ptr.getRefData().getBaseNode()) return true; @@ -173,13 +119,14 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr) ptr.getRefData().setBaseNode(0); return true; } - +*/ return false; } void Objects::removeCell(MWWorld::CellStore* store) { + /* for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) { if(iter->first.getCell() == store) @@ -216,20 +163,7 @@ void Objects::removeCell(MWWorld::CellStore* store) mRenderer.getScene()->destroySceneNode(cell->second); mCellSceneNodes.erase(cell); } -} - -void Objects::buildStaticGeometry(MWWorld::CellStore& cell) -{ - if(mStaticGeometry.find(&cell) != mStaticGeometry.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometry[&cell]; - sg->build(); - } - if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; - sg->build(); - } + */ } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) @@ -239,33 +173,16 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) void Objects::update(float dt, Ogre::Camera* camera) { + /* PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) it->second->runAnimation(dt); - - it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->preRender(camera); - -} - -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 &old, const MWWorld::Ptr &cur) { + /* Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); @@ -286,13 +203,16 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) anim->updatePtr(cur); mObjects[cur] = anim; } + */ } ObjectAnimation* Objects::getAnimation(const MWWorld::Ptr &ptr) { + /* PtrAnimationMap::const_iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) return iter->second; + */ return NULL; } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index adfe5ca26b..b2f07ab0fc 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -55,7 +55,6 @@ public: ///< \return found? void removeCell(MWWorld::CellStore* store); - void buildStaticGeometry(MWWorld::CellStore &cell); void setRootNode(Ogre::SceneNode* root); void rebuildStaticGeometry(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8fb1ee53c5..c64a265acf 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,7 +31,6 @@ #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 "../mwbase/statemanager.hpp" @@ -40,7 +39,6 @@ #include "../mwworld/ptr.hpp" -#include "shadows.hpp" #include "localmap.hpp" #include "water.hpp" #include "npcanimation.hpp" @@ -59,7 +57,6 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b : mRendering(_rend) , mFallback(fallback) , mPlayerAnimation(NULL) - , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) , mTerrain(NULL) @@ -162,15 +159,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mCamera = new MWRender::Camera(mRendering.getCamera()); - mShadows = new Shadows(&mRendering); - mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mSun = 0; - mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); @@ -185,8 +179,6 @@ RenderingManager::~RenderingManager () delete mPlayerAnimation; delete mCamera; delete mSkyManager; - delete mDebugging; - delete mShadows; delete mTerrain; delete mLocalMap; delete mOcclusionQuery; @@ -222,7 +214,6 @@ void RenderingManager::removeCell (MWWorld::CellStore *store) mLocalMap->saveFogOfWar(store); mObjects->removeCell(store); mActors->removeCell(store); - mDebugging->cellRemoved(store); } void RenderingManager::removeWater () @@ -251,7 +242,6 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store) mObjects->buildStaticGeometry (*store); sh::Factory::getInstance().unloadUnreferencedMaterials(); - mDebugging->cellAdded(store); } void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ @@ -477,9 +467,10 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { +#if 0 if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid) return mDebugging->toggleRenderMode(mode); - else if (mode == MWBase::World::Render_Wireframe) + if (mode == MWBase::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { @@ -498,6 +489,8 @@ bool RenderingManager::toggleRenderMode(int mode) mRendering.getScene()->showBoundingBoxes(show); return show; } +#endif + return 0; } void RenderingManager::configureFog(const MWWorld::CellStore &mCell) @@ -547,20 +540,7 @@ void RenderingManager::applyFog (bool underwater) void RenderingManager::setAmbientMode() { - switch (mAmbientMode) - { - case 0: - setAmbientColour(mAmbientColor); - break; - - case 1: - setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); - break; - - case 2: - setAmbientColour(ColourValue(1,1,1)); - break; - } + setAmbientColour(mAmbientColor); } void RenderingManager::configureAmbient(MWWorld::CellStore &mCell) @@ -805,12 +785,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setCurrentLanguage (lang); rebuild = true; } - else if (it->first == "Shadows") - { - mShadows->recreate (); - - rebuild = true; - } } if (changeRes) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 9f029c1b91..5bfd8ae775 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -248,9 +248,6 @@ private: MWRender::NpcAnimation *mPlayerAnimation; - // 0 normal, 1 more bright, 2 max - int mAmbientMode; - Ogre::ColourValue mAmbientColor; Ogre::Light* mSun; @@ -264,12 +261,8 @@ private: MWRender::Camera *mCamera; - MWRender::Debugging *mDebugging; - MWRender::LocalMap* mLocalMap; - MWRender::Shadows* mShadows; - bool mRenderWorld; }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a8c04aa4bc..fab65b1523 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,6 +270,7 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { + /* MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) @@ -286,6 +287,7 @@ namespace MWScript return input->getActionKeyBindingName (*it); } } + */ return "None"; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 06c40dd8e8..5fc39f03e8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -211,6 +211,7 @@ namespace MWSound Ogre::StringVector filelist; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { +#if 0 Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) { @@ -219,6 +220,8 @@ namespace MWSound filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); } mMusicFiles[mCurrentPlaylist] = filelist; + +#endif } else filelist = mMusicFiles[mCurrentPlaylist]; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d31ae520bd..a59efecfee 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -14,10 +14,9 @@ #include #include #include -#include +//#include #include -#include #include #include @@ -31,7 +30,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" -#include "../apps/openmw/mwrender/animation.hpp" +//#include "../apps/openmw/mwrender/animation.hpp" #include "../apps/openmw/mwbase/world.hpp" #include "../apps/openmw/mwbase/environment.hpp" @@ -45,6 +44,7 @@ namespace void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) { + /* for (std::map::iterator it = map.begin(); it != map.end(); ++it) { @@ -85,6 +85,7 @@ void animateCollisionShapes (std::mapupdateSingleAabb(it->first); } + */ } } @@ -502,8 +503,8 @@ namespace MWWorld mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() @@ -521,7 +522,7 @@ namespace MWWorld std::pair PhysicsSystem::getFacedHandle(float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); Ogre::Vector3 origin_ = ray.getOrigin(); btVector3 origin(origin_.x, origin_.y, origin_.z); @@ -537,7 +538,7 @@ namespace MWWorld std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); Ogre::Vector3 origin_ = ray.getOrigin(); btVector3 origin(origin_.x, origin_.y, origin_.z); @@ -555,7 +556,7 @@ namespace MWWorld std::vector < std::pair > PhysicsSystem::getFacedHandles (float mouseX, float mouseY, float queryDistance) { - Ray ray = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); + Ray ray;// = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); Ogre::Vector3 from = ray.getOrigin(); Ogre::Vector3 to = ray.getPoint(queryDistance); @@ -628,9 +629,9 @@ namespace MWWorld std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit) { - Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( - mouseX, - mouseY); + Ogre::Ray ray;// = mRender.getCamera()->getCameraToViewportRay( + //mouseX, + //mouseY); Ogre::Vector3 from = ray.getOrigin(); Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable @@ -755,7 +756,7 @@ namespace MWWorld if(handleToMesh.find(handle) != handleToMesh.end()) { std::string model = ptr.getClass().getModel(ptr); - model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model + //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model bool placeable = false; if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) @@ -803,8 +804,9 @@ namespace MWWorld bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) { + // FIXME: since raycasting shapes are going away, this should use the osg ComputeBoundingBoxVisitor std::string model = ptr.getClass().getModel(ptr); - model = Misc::ResourceHelpers::correctActorModelPath(model); + //model = Misc::ResourceHelpers::correctActorModelPath(model); if (model.empty()) { return false; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8d689240b6..6d74086079 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -11,7 +12,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "physicssystem.hpp" +//#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -22,6 +23,7 @@ namespace { +#if 0 void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { @@ -113,6 +115,7 @@ namespace return true; } +#endif } @@ -121,15 +124,15 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); + //::updateObjectLocalRotation(ptr, *mPhysics, mRendering); } void Scene::updateObjectRotation (const Ptr& ptr) { if(ptr.getRefData().getBaseNode() != 0) { - mRendering.rotateObject(ptr); - mPhysics->rotateObject(ptr); + //mRendering.rotateObject(ptr); + //mPhysics->rotateObject(ptr); } } @@ -161,8 +164,8 @@ namespace MWWorld { // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different // (and objects in a different cell can "bleed" into another cells map if they cross the border) - for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - mRendering.requestMap(*active); + //for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) + //mRendering.requestMap(*active); mNeedMapUpdate = false; if (mCurrentCell->isExterior()) @@ -173,7 +176,7 @@ namespace MWWorld } } - mRendering.update (duration, paused); + //mRendering.update (duration, paused); } void Scene::unloadCell (CellStoreCollection::iterator iter) @@ -188,7 +191,7 @@ namespace MWWorld iter2!=functor.mHandles.end(); ++iter2) { Ogre::SceneNode* node = *iter2; - mPhysics->removeObject (node->getName()); + //mPhysics->removeObject (node->getName()); } } @@ -199,11 +202,11 @@ namespace MWWorld (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land && land->mDataTypes&ESM::Land::DATA_VHGT) - mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + //if (land && land->mDataTypes&ESM::Land::DATA_VHGT) + //mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } - mRendering.removeCell(*iter); + //mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); @@ -224,6 +227,7 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; +#if 0 // Load terrain physics first... if (cell->getCell()->isExterior()) { @@ -248,6 +252,7 @@ namespace MWWorld ; } } +#endif cell->respawn(); @@ -255,6 +260,7 @@ namespace MWWorld /// \todo rescale depending on the state of a new GMST insertCell (*cell, true, loadingListener); +#if 0 mRendering.cellAdded (cell); bool waterEnabled = cell->getCell()->hasWater(); mRendering.setWaterEnabled(waterEnabled); @@ -267,6 +273,7 @@ namespace MWWorld mPhysics->disableWater(); mRendering.configureAmbient(*cell); +#endif } // register local scripts @@ -300,7 +307,7 @@ namespace MWWorld int newX, newY; MWBase::Environment::get().getWorld()->positionToIndex(pos.x, pos.y, newX, newY); changeCellGrid(newX, newY); - mRendering.updateTerrain(); + //mRendering.updateTerrain(); } } @@ -309,7 +316,7 @@ namespace MWWorld Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); - mRendering.enableTerrain(true); + //mRendering.enableTerrain(true); std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); @@ -404,7 +411,7 @@ namespace MWWorld world->getPlayer().setCell(cell); MWWorld::Ptr player = world->getPlayerPtr(); - mRendering.updatePlayerPtr(player); + //mRendering.updatePlayerPtr(player); if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); @@ -428,7 +435,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics), mRendering(rendering),*/ mNeedMapUpdate(false) { } @@ -460,7 +467,7 @@ namespace MWWorld loadingListener->setLabel(loadingInteriorText); Loading::ScopedLoad load(loadingListener); - mRendering.enableTerrain(false); + //mRendering.enableTerrain(false); if(!loadcell) { @@ -497,7 +504,7 @@ namespace MWWorld changePlayerCell(cell, position, true); // adjust fog - mRendering.configureFog(*mCurrentCell); + //mRendering.configureFog(*mCurrentCell); // Sky system MWBase::Environment::get().getWorld()->adjustSky(); @@ -523,7 +530,7 @@ namespace MWWorld CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); - mRendering.updateTerrain(); + //mRendering.updateTerrain(); } CellStore* Scene::getCurrentCell () @@ -538,17 +545,17 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - cell.forEach (functor); + //InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); + //cell.forEach (functor); } void Scene::addObjectToScene (const Ptr& ptr) { try { - addObject(ptr, *mPhysics, mRendering); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + //addObject(ptr, *mPhysics, mRendering); + //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) { @@ -560,8 +567,8 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - mPhysics->removeObject (ptr.getRefData().getHandle()); - mRendering.removeObject (ptr); + //mPhysics->removeObject (ptr.getRefData().getHandle()); + //mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index a9d80bf178..341a89a78e 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,11 +1,13 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" #include "ptr.hpp" #include "globals.hpp" +#include + namespace Ogre { class Vector3; @@ -35,6 +37,7 @@ namespace MWRender { class SkyManager; class CellRender; + class RenderingManager; } namespace MWWorld @@ -55,8 +58,8 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - PhysicsSystem *mPhysics; - MWRender::RenderingManager& mRendering; + //PhysicsSystem *mPhysics; + //MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a9ca8e72b5..82814b623e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -13,7 +13,7 @@ #include "../mwsound/sound.hpp" -#include "../mwrender/renderingmanager.hpp" +//#include "../mwrender/renderingmanager.hpp" #include "player.hpp" #include "esmstore.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 013386f8f9..8b2035fe96 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,7 +16,6 @@ #include -#include #include #include #include @@ -37,8 +36,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors -#include "../mwrender/sky.hpp" -#include "../mwrender/animation.hpp" +//#include "../mwrender/animation.hpp" #include "../mwscript/interpretercontext.hpp" @@ -51,7 +49,8 @@ #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" -#include "projectilemanager.hpp" +//#include "projectilemanager.hpp" +#include "weather.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -129,6 +128,7 @@ namespace MWWorld void World::adjustSky() { +#if 0 if (mSky && (isCellExterior() || isCellQuasiExterior())) { mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); @@ -139,9 +139,10 @@ namespace MWWorld } else mRendering->skyDisable(); +#endif } - World::World (OEngine::Render::OgreRenderer& renderer, + World::World ( const Files::Collections& fileCollections, const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, @@ -156,16 +157,16 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(renderer); - mPhysEngine = mPhysics->getEngine(); - + //mPhysics = new PhysicsSystem(renderer); + //mPhysEngine = mPhysics->getEngine(); +#if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); +#endif + //mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); - mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); + //mPhysEngine->setSceneManager(renderer.getScene()); - mPhysEngine->setSceneManager(renderer.getScene()); - - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); @@ -195,7 +196,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWorldScene = new Scene(*mRendering, mPhysics); + mWorldScene = new Scene(*mRendering, NULL/*mPhysics*/); } void World::startNewGame (bool bypass) @@ -208,7 +209,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); - mRendering->resetCamera(); + //mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -257,13 +258,13 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); // enable collision - if (!mPhysics->toggleCollisionMode()) - mPhysics->toggleCollisionMode(); + //if (!mPhysics->toggleCollisionMode()) + // mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game - delete mWeatherManager; - mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + //delete mWeatherManager; + //mWeatherManager = 0; + //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); @@ -271,11 +272,11 @@ namespace MWWorld void World::clear() { - mWeatherManager->clear(); - mRendering->clear(); - + //mWeatherManager->clear(); + //mRendering->clear(); +#if 0 mProjectileManager->clear(); - +#endif mLocalScripts.clear(); mWorldScene->changeToVoid(); @@ -310,7 +311,9 @@ namespace MWWorld mCells.countSavedGameRecords() +mStore.countSavedGameRecords() +mGlobalVariables.countSavedGameRecords() + #if 0 +mProjectileManager->countSavedGameRecords() + #endif +1 // player record +1 // weather record +1 // actorId counter @@ -329,8 +332,8 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - CellStore* cellstore = *iter; - mRendering->writeFog(cellstore); + //CellStore* cellstore = *iter; + //mRendering->writeFog(cellstore); } MWMechanics::CreatureStats::writeActorIdCounter(writer); @@ -340,9 +343,10 @@ namespace MWWorld mCells.write (writer, progress); mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); - mWeatherManager->write (writer, progress); + //mWeatherManager->write (writer, progress); +#if 0 mProjectileManager->write (writer, progress); - +#endif writer.startRecord(ESM::REC_ENAB); writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); @@ -369,9 +373,12 @@ namespace MWWorld if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - !mWeatherManager->readRecord (reader, type) && - !mCells.readRecord (reader, type, contentFileMap) && - !mProjectileManager->readRecord (reader, type)) + //!mWeatherManager->readRecord (reader, type) && + !mCells.readRecord (reader, type, contentFileMap) + #if 0 + && !mProjectileManager->readRecord (reader, type) + #endif + ) { throw std::runtime_error ("unknown record in saved game"); } @@ -463,13 +470,14 @@ namespace MWWorld World::~World() { +#if 0 // Must be cleared before mRendering is destroyed mProjectileManager->clear(); - - delete mWeatherManager; +#endif + //delete mWeatherManager; delete mWorldScene; - delete mRendering; - delete mPhysics; + //delete mRendering; + //delete mPhysics; delete mPlayer; } @@ -521,6 +529,7 @@ namespace MWWorld void World::useDeathCamera() { +#if 0 if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) { mRendering->getCamera()->togglePreviewMode(false); @@ -528,6 +537,7 @@ namespace MWWorld } if(mRendering->getCamera()->isFirstPerson()) mRendering->getCamera()->toggleViewMode(true); +#endif } MWWorld::Player& World::getPlayer() @@ -804,7 +814,7 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - mWeatherManager->advanceTime (hours); + //mWeatherManager->advanceTime (hours); hours += mGlobalVariables["gamehour"].getFloat(); @@ -828,9 +838,9 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - mRendering->skySetHour (hour); + //mRendering->skySetHour (hour); - mWeatherManager->setHour(static_cast(hour)); + //mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -865,7 +875,7 @@ namespace MWWorld mGlobalVariables["day"].setInteger (day); mGlobalVariables["month"].setInteger (month); - mRendering->skySetDate (day, month); + //mRendering->skySetDate (day, month); } void World::setMonth (int month) @@ -886,7 +896,7 @@ namespace MWWorld if (years>0) mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); } int World::getDay() const @@ -932,6 +942,7 @@ namespace MWWorld bool World::toggleSky() { +#if 0 if (mSky) { mSky = false; @@ -944,21 +955,23 @@ namespace MWWorld mRendering->skyEnable(); return true; } +#endif + return 0; } int World::getMasserPhase() const { - return mRendering->skyGetMasserPhase(); + return 0;//mRendering->skyGetMasserPhase(); } int World::getSecundaPhase() const { - return mRendering->skyGetSecundaPhase(); + return 0;//mRendering->skyGetSecundaPhase(); } void World::setMoonColour (bool red) { - mRendering->skySetMoonColour (red); + //mRendering->skySetMoonColour (red); } float World::getTimeScaleFactor() const @@ -968,13 +981,15 @@ namespace MWWorld void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - mPhysics->clearQueuedMovement(); + //mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != cellName) { // changed worldspace +#if 0 mProjectileManager->clear(); mRendering->notifyWorldSpaceChanged(); +#endif mCurrentWorldSpace = cellName; } @@ -985,13 +1000,15 @@ namespace MWWorld void World::changeToExteriorCell (const ESM::Position& position) { - mPhysics->clearQueuedMovement(); + //mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != "sys::default") // FIXME { // changed worldspace +#if 0 mProjectileManager->clear(); mRendering->notifyWorldSpaceChanged(); +#endif } removeContainerScripts(getPlayerPtr()); mWorldScene->changeToExteriorCell(position, true); @@ -1049,6 +1066,7 @@ namespace MWWorld std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { + /* const ESM::Position &posdata = ptr.getRefData().getPosition(); Ogre::Vector3 pos(posdata.pos); Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1063,9 +1081,10 @@ namespace MWWorld if(node != NULL) pos += node->_getDerivedPosition(); } + */ - std::pair result = mPhysics->getHitContact(ptr.getRefData().getHandle(), - pos, rot, distance); + std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), + // pos, rot, distance); if(result.first.empty()) return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); @@ -1174,7 +1193,7 @@ namespace MWWorld MWWorld::Ptr copy = ptr.getClass().copyToCell(ptr, *newCell, pos); - mRendering->updateObjectCell(ptr, copy); + //mRendering->updateObjectCell(ptr, copy); ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); @@ -1196,8 +1215,8 @@ namespace MWWorld } if (haveToMove && ptr.getRefData().getBaseNode()) { - mRendering->moveObject(ptr, vec); - mPhysics->moveObject (ptr); + //mRendering->moveObject(ptr, vec); + //mPhysics->moveObject (ptr); } if (isPlayer) { @@ -1235,8 +1254,8 @@ namespace MWWorld if(ptr.getRefData().getBaseNode() == 0) return; - mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); - mPhysics->scaleObject(ptr); + //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); + //mPhysics->scaleObject(ptr); } void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) @@ -1322,7 +1341,7 @@ namespace MWWorld return; } - float terrainHeight = mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = 0;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; @@ -1333,7 +1352,7 @@ namespace MWWorld if (force || !isFlying(ptr)) { - Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); + Ogre::Vector3 traced;// = mPhysics->traceDown(ptr, 500); if (traced.z < pos.pos[2]) pos.pos[2] = traced.z; } @@ -1348,7 +1367,7 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1f); + Ogre::Vector3 traced;// = mPhysics->traceDown(actor, dist*1.1f); moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); } @@ -1389,12 +1408,13 @@ namespace MWWorld void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) { - mPhysics->queueObjectMovement(ptr, velocity); + //mPhysics->queueObjectMovement(ptr, velocity); } void World::doPhysics(float duration) { - mPhysics->stepSimulation(duration); +#if 0 + //mPhysics->stepSimulation(duration); processDoors(duration); @@ -1414,17 +1434,19 @@ namespace MWWorld } if(player != results.end()) moveObjectImp(player->first, player->second.x, player->second.y, player->second.z); +#endif } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) { Ogre::Vector3 a(x1,y1,z1); Ogre::Vector3 b(x2,y2,z2); - return mPhysics->castRay(a,b,false,true); + return 0;//mPhysics->castRay(a,b,false,true); } void World::processDoors(float duration) { +#if 0 std::map::iterator it = mDoorStates.begin(); while (it != mDoorStates.end()) { @@ -1475,16 +1497,17 @@ namespace MWWorld ++it; } } +#endif } bool World::toggleCollisionMode() { - return mPhysics->toggleCollisionMode(); + return 0;//mPhysics->toggleCollisionMode(); } bool World::toggleRenderMode (RenderMode mode) { - return mRendering->toggleRenderMode (mode); + return 0;//mRendering->toggleRenderMode (mode); } const ESM::Potion *World::createRecord (const ESM::Potion& record) @@ -1544,7 +1567,7 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - mRendering->renderPlayer(mPlayer->getPlayer()); + //mRendering->renderPlayer(mPlayer->getPlayer()); } return ret; } @@ -1581,8 +1604,8 @@ namespace MWWorld updateWeather(duration, paused); - if (!paused) - doPhysics (duration); + //if (!paused) + // doPhysics (duration); mWorldScene->update (duration, paused); @@ -1625,7 +1648,7 @@ namespace MWWorld Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { - Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); + Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } @@ -1634,6 +1657,7 @@ namespace MWWorld void World::performUpdateSceneQueries () { +#if 0 if (!mRendering->occlusionQuerySupported()) { // cast a ray from player to sun to detect if the sun is visible @@ -1643,22 +1667,23 @@ namespace MWWorld Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } +#endif } void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) { - maxDistance += mRendering->getCameraDistance(); + //maxDistance += mRendering->getCameraDistance(); std::vector < std::pair < float, std::string > > results; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedHandles(x, y, maxDistance); + //results = mPhysics->getFacedHandles(x, y, maxDistance); } else { - results = mPhysics->getFacedHandles(maxDistance); + //results = mPhysics->getFacedHandles(maxDistance); } if (ignorePlayer && @@ -1697,17 +1722,17 @@ namespace MWWorld int World::getCurrentWeather() const { - return mWeatherManager->getWeatherID(); + return 0;//mWeatherManager->getWeatherID(); } void World::changeWeather(const std::string& region, const unsigned int id) { - mWeatherManager->changeWeather(region, id); + //mWeatherManager->changeWeather(region, id); } void World::modRegion(const std::string ®ionid, const std::vector &chances) { - mWeatherManager->modRegion(regionid, chances); + //mWeatherManager->modRegion(regionid, chances); } Ogre::Vector2 World::getNorthVector (CellStore* cell) @@ -1767,33 +1792,33 @@ namespace MWWorld void World::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) { - mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); + //mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); } Ogre::Vector2 World::interiorMapToWorldPosition(float nX, float nY, int x, int y) { - return mRendering->interiorMapToWorldPosition(nX, nY, x, y); + return Ogre::Vector2();//mRendering->interiorMapToWorldPosition(nX, nY, x, y); } bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return mRendering->isPositionExplored(nX, nY, x, y, interior); + return 0;//mRendering->isPositionExplored(nX, nY, x, y, interior); } void World::setWaterHeight(const float height) { - mPhysics->setWaterHeight(height); - mRendering->setWaterHeight(height); + //mPhysics->setWaterHeight(height); + //mRendering->setWaterHeight(height); } bool World::toggleWater() { - return mRendering->toggleWater(); + return 0;//mRendering->toggleWater(); } bool World::toggleWorld() { - return mRendering->toggleWorld(); + return 0;//mRendering->toggleWorld(); } void World::PCDropped (const Ptr& item) @@ -1807,7 +1832,7 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - std::pair result = mPhysics->castRay(cursorX, cursorY); + std::pair result;// = mPhysics->castRay(cursorX, cursorY); if (!result.first) return MWWorld::Ptr(); @@ -1838,7 +1863,7 @@ namespace MWWorld { Ogre::Vector3 normal(0,0,0); std::string handle; - std::pair result = mPhysics->castRay(cursorX, cursorY, &normal, &handle); + std::pair result;// = mPhysics->castRay(cursorX, cursorY, &normal, &handle); if (result.first) { @@ -1859,6 +1884,7 @@ namespace MWWorld Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { +#if 0 if (!object.getClass().isActor() && adjustPos) { // Adjust position so the location we wanted ends up in the middle of the object bounding box @@ -1879,6 +1905,7 @@ namespace MWWorld pos.pos[2] -= adjust.z; } } +#endif if (cell->isExterior()) { @@ -1926,12 +1953,12 @@ namespace MWWorld Ogre::Vector3 orig = Ogre::Vector3(pos.pos); orig.z += 20; - Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); + //Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); - float len = 100.0; + //float len = 100.0; - std::pair hit = - mPhysics->castRay(orig, dir, len); + std::pair hit;// = + //mPhysics->castRay(orig, dir, len); if (hit.first) pos.pos[2] = hit.second.z; @@ -1948,12 +1975,12 @@ namespace MWWorld void World::processChangedSettings(const Settings::CategorySettingVector& settings) { - mRendering->processChangedSettings(settings); + //mRendering->processChangedSettings(settings); } void World::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) { - mRendering->getTriangleBatchCount(triangles, batches); + //mRendering->getTriangleBatchCount(triangles, batches); } bool World::isFlying(const MWWorld::Ptr &ptr) const @@ -2072,12 +2099,12 @@ namespace MWWorld bool World::vanityRotateCamera(float * rot) { - return mRendering->vanityRotateCamera(rot); + return 0;//mRendering->vanityRotateCamera(rot); } void World::setCameraDistance(float dist, bool adjust, bool override_) { - return mRendering->setCameraDistance(dist, adjust, override_); + //mRendering->setCameraDistance(dist, adjust, override_); } void World::setupPlayer() @@ -2093,13 +2120,13 @@ namespace MWWorld mPlayer->set(player); } - Ptr ptr = mPlayer->getPlayer(); - mRendering->setupPlayer(ptr); + //Ptr ptr = mPlayer->getPlayer(); + //mRendering->setupPlayer(ptr); } void World::renderPlayer() { - mRendering->renderPlayer(mPlayer->getPlayer()); + //mRendering->renderPlayer(mPlayer->getPlayer()); // At this point the Animation object is live, and the CharacterController associated with it must be created. // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate @@ -2107,8 +2134,8 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); - model = Misc::ResourceHelpers::correctActorModelPath(model); - mPhysics->addActor(mPlayer->getPlayer(), model); + //model = Misc::ResourceHelpers::correctActorModelPath(model); + //mPhysics->addActor(mPlayer->getPlayer(), model); } int World::canRest () @@ -2134,17 +2161,17 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - return mRendering->getAnimation(ptr); + return 0;//return mRendering->getAnimation(ptr); } void World::frameStarted (float dt, bool paused) { - mRendering->frameStarted(dt, paused); + //mRendering->frameStarted(dt, paused); } void World::screenshot(Ogre::Image &image, int w, int h) { - mRendering->screenshot(image, w, h); + //mRendering->screenshot(image, w, h); } void World::activateDoor(const MWWorld::Ptr& door) @@ -2180,27 +2207,27 @@ namespace MWWorld bool World::getPlayerStandingOn (const MWWorld::Ptr& object) { - MWWorld::Ptr player = getPlayerPtr(); - return mPhysics->isActorStandingOn(player, object); + //MWWorld::Ptr player = getPlayerPtr(); + return 0;//mPhysics->isActorStandingOn(player, object); } bool World::getActorStandingOn (const MWWorld::Ptr& object) { std::vector actors; - mPhysics->getActorsStandingOn(object, actors); + //mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) { - MWWorld::Ptr player = getPlayerPtr(); - return mPhysics->isActorCollidingWith(player, object); + //MWWorld::Ptr player = getPlayerPtr(); + return 0;//mPhysics->isActorCollidingWith(player, object); } bool World::getActorCollidingWith (const MWWorld::Ptr& object) { std::vector actors; - mPhysics->getActorsCollidingWith(object, actors); + //mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } @@ -2210,7 +2237,7 @@ namespace MWWorld return; std::vector actors; - mPhysics->getActorsStandingOn(object, actors); + //mPhysics->getActorsStandingOn(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2241,7 +2268,7 @@ namespace MWWorld return; std::vector actors; - mPhysics->getActorsCollidingWith(object, actors); + //mPhysics->getActorsCollidingWith(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2269,7 +2296,7 @@ namespace MWWorld float World::getWindSpeed() { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->getWindSpeed(); + return 0;//mWeatherManager->getWindSpeed(); else return 0.f; } @@ -2277,7 +2304,7 @@ namespace MWWorld bool World::isInStorm() const { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->isInStorm(); + return 0;//mWeatherManager->isInStorm(); else return false; } @@ -2285,7 +2312,7 @@ namespace MWWorld Ogre::Vector3 World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) - return mWeatherManager->getStormDirection(); + return Ogre::Vector3();//mWeatherManager->getStormDirection(); else return Ogre::Vector3(0,1,0); } @@ -2479,7 +2506,7 @@ namespace MWWorld void World::reattachPlayerCamera() { - mRendering->rebuildPtr(getPlayerPtr()); + //mRendering->rebuildPtr(getPlayerPtr()); } void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) @@ -2512,7 +2539,7 @@ namespace MWWorld // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. // the following is just for reattaching the camera properly. - mRendering->rebuildPtr(actor); + //mRendering->rebuildPtr(actor); if(actor == getPlayerPtr()) { @@ -2684,6 +2711,7 @@ namespace MWWorld { // For NPCs use facing direction from Head node Ogre::Vector3 origin(actor.getRefData().getPosition().pos); +#if 0 MWRender::Animation *anim = mRendering->getAnimation(actor); if(anim != NULL) { @@ -2693,6 +2721,7 @@ namespace MWWorld if(node != NULL) origin += node->_getDerivedPosition(); } +#endif Ogre::Quaternion orient; orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); @@ -2739,14 +2768,18 @@ namespace MWWorld void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) { +#if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); +#endif } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) { +#if 0 mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection); +#endif } const std::vector& World::getContentFiles() const @@ -2768,7 +2801,7 @@ namespace MWWorld { MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); if (cell->isExterior()) - return mWeatherManager->isDark(); + return 0;//mWeatherManager->isDark(); else { uint32_t ambient = cell->getCell()->mAmbi.mAmbient; @@ -2933,10 +2966,10 @@ namespace MWWorld if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->switchToNextWeather(true); + //mWeatherManager->switchToNextWeather(true); } - mWeatherManager->update(duration, paused); + //mWeatherManager->update(duration, paused); } struct AddDetectedReference @@ -3190,12 +3223,12 @@ namespace MWWorld modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); - mRendering->spawnEffect(model, texture, worldPosition); + //mRendering->spawnEffect(model, texture, worldPosition); } void World::spawnEffect(const std::string &model, const std::string &textureOverride, const Vector3 &worldPos) { - mRendering->spawnEffect(model, textureOverride, worldPos); + //mRendering->spawnEffect(model, textureOverride, worldPos); } void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, @@ -3211,6 +3244,7 @@ namespace MWWorld continue; // Not an area effect // Spawn the explosion orb effect + /* const ESM::Static* areaStatic; if (!effect->mCasting.empty()) areaStatic = getStore().get().find (effect->mArea); @@ -3218,6 +3252,7 @@ namespace MWWorld areaStatic = getStore().get().find ("VFX_DefaultArea"); mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); + */ // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 63d6506de0..07698aae52 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -8,7 +8,7 @@ #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" -#include "physicssystem.hpp" +//#include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" @@ -19,6 +19,8 @@ #include "contentloader.hpp" +#include + namespace Ogre { class Vector3; @@ -62,7 +64,7 @@ namespace MWWorld MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; - MWWorld::WeatherManager* mWeatherManager; + //MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; @@ -152,7 +154,7 @@ namespace MWWorld public: - World (OEngine::Render::OgreRenderer& renderer, + World ( const Files::Collections& fileCollections, const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, @@ -465,31 +467,31 @@ namespace MWWorld virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { - mRendering->togglePOV(); + //mRendering->togglePOV(); } virtual bool isFirstPerson() const { - return mRendering->getCamera()->isFirstPerson(); + return 0;//mRendering->getCamera()->isFirstPerson(); } virtual void togglePreviewMode(bool enable) { - mRendering->togglePreviewMode(enable); + //mRendering->togglePreviewMode(enable); } virtual bool toggleVanityMode(bool enable) { - return mRendering->toggleVanityMode(enable); + return 0;//mRendering->toggleVanityMode(enable); } virtual void allowVanityMode(bool allow) { - mRendering->allowVanityMode(allow); + //mRendering->allowVanityMode(allow); } virtual void togglePlayerLooking(bool enable) { - mRendering->togglePlayerLooking(enable); + //mRendering->togglePlayerLooking(enable); } virtual void changeVanityModeScale(float factor) { - mRendering->changeVanityModeScale(factor); + //mRendering->changeVanityModeScale(factor); } virtual bool vanityRotateCamera(float * rot); diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 40fa2373f0..b5c4e8ade7 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -67,11 +67,11 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -81,7 +81,7 @@ ELSE (WIN32) #Unix FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -92,11 +92,11 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9d9ae4f314..1debf3495d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -26,10 +26,6 @@ add_component_dir (settings settings ) -add_component_dir (nifoverrides - nifoverrides - ) - add_component_dir (bsa bsa_file ) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 933d890994..87c000d9a0 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -25,6 +25,7 @@ ESMReader::ESMReader() , mIdx(0) , mGlobalReaderList(NULL) , mEncoder(NULL) + , mFileSize(0) { } @@ -64,7 +65,7 @@ void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) mEsm = _esm; mCtx.filename = name; mEsm->seekg(0, mEsm->end); - mCtx.leftFile = mEsm->tellg(); + mCtx.leftFile = mFileSize = mEsm->tellg(); mEsm->seekg(0, mEsm->beg); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 89062bd27a..709008a90e 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -261,6 +261,8 @@ public: /// Get record flags of last record unsigned int getRecordFlags() { return mRecordFlags; } + size_t getFileSize() const { return mFileSize; } + private: Files::IStreamPtr mEsm; @@ -277,6 +279,9 @@ private: std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; + + size_t mFileSize; + }; } #endif diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index eb7dd901d7..1b61aea90f 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -147,6 +147,7 @@ namespace Gui void FontLoader::loadAllFonts(bool exportToFile) { + /* Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) { @@ -156,6 +157,7 @@ namespace Gui loadFont(*resource, exportToFile); } } + */ } diff --git a/components/nifoverrides/nifoverrides.cpp b/components/nifoverrides/nifoverrides.cpp deleted file mode 100644 index 972cf1b843..0000000000 --- a/components/nifoverrides/nifoverrides.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "nifoverrides.hpp" - -#include - -#include <../components/misc/stringops.hpp> - -#include "../extern/shiny/Main/MaterialInstance.hpp" - -#include - - -using namespace NifOverrides; - -Overrides::TransparencyOverrideMap Overrides::mTransparencyOverrides = Overrides::TransparencyOverrideMap(); -Overrides::MaterialOverrideMap Overrides::mMaterialOverrides = Overrides::MaterialOverrideMap(); - -void Overrides::loadTransparencyOverrides (const std::string& file) -{ - Ogre::ConfigFile cf; - cf.load(file); - - Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); - while (seci.hasMoreElements()) - { - Ogre::String sectionName = seci.peekNextKey(); - mTransparencyOverrides[sectionName] = - Ogre::StringConverter::parseInt(cf.getSetting("alphaRejectValue", sectionName)); - seci.getNext(); - } -} - -void Overrides::loadMaterialOverrides(const std::string &file) -{ - Ogre::ConfigFile cf; - cf.load(file); - - Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); - while (seci.hasMoreElements()) - { - Ogre::String sectionName = seci.peekNextKey(); - - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - std::map overrides; - for (i = settings->begin(); i != settings->end(); ++i) - { - overrides[i->first] = i->second; - } - mMaterialOverrides[sectionName] = overrides; - } - -} - -TransparencyResult Overrides::getTransparencyOverride(const std::string& texture) -{ - TransparencyResult result; - result.first = false; - - TransparencyOverrideMap::iterator it = mTransparencyOverrides.find(Misc::StringUtils::lowerCase(texture)); - if (it != mTransparencyOverrides.end()) - { - result.first = true; - result.second = it->second; - } - - return result; -} - -void Overrides::getMaterialOverrides(const std::string &texture, sh::MaterialInstance* material) -{ - MaterialOverrideMap::iterator it = mMaterialOverrides.find(Misc::StringUtils::lowerCase(texture)); - if (it != mMaterialOverrides.end()) - { - const std::map& overrides = it->second; - for (std::map::const_iterator it = overrides.begin(); it != overrides.end(); ++it) - { - material->setProperty(it->first, sh::makeProperty(it->second)); - } - } -} diff --git a/components/nifoverrides/nifoverrides.hpp b/components/nifoverrides/nifoverrides.hpp deleted file mode 100644 index edff876d44..0000000000 --- a/components/nifoverrides/nifoverrides.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP -#define OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP - -#include - -namespace sh -{ - class MaterialInstance; -} - -namespace NifOverrides -{ - - typedef std::pair TransparencyResult; - - /// Allows to provide overrides for some material properties in NIF files. - /// NIFs are a bit limited in that they don't allow specifying a material externally, which is - /// painful for texture modding. - /// We also use this to patch up transparency settings in certain NIFs that bethesda has chosen poorly. - class Overrides - { - public: - typedef std::map TransparencyOverrideMap; - static TransparencyOverrideMap mTransparencyOverrides; - - typedef std::map > MaterialOverrideMap; - static MaterialOverrideMap mMaterialOverrides; - - void loadTransparencyOverrides (const std::string& file); - void loadMaterialOverrides (const std::string& file); - - static TransparencyResult getTransparencyOverride(const std::string& texture); - static void getMaterialOverrides (const std::string& texture, sh::MaterialInstance* instance); - }; - -} - -#endif diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg deleted file mode 100644 index 65f9b477af..0000000000 --- a/files/transparency-overrides.cfg +++ /dev/null @@ -1,623 +0,0 @@ -# Bethesda has used wrong transparency settings for many textures -# (who would have guessed) -# This is very unfortunate because objects with real transparency: -# - cannot cast shadows -# - cannot receive advanced framebuffer effects like depth of field or ambient occlusion -# - cannot cover lens flare effects (the lens flare will just shine through) - -# This file lists textures that should be using alpha rejection instead of transparency -# basically these are textures that are not translucent (i.e. at one spot on the texture, either transparent or opaque) - -# Note: all the texture names here have to be lowercase - -# fauna -[textures\tx_wickwheat_01.dds] - alphaRejectValue = 128 - -[textures\tx_wickwheat_03.dds] - alphaRejectValue = 128 - -[textures\tx_red_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_stone_flower_01.dds] - alphaRejectValue = 128 - -[textures\tx_ivy_02.dds] - alphaRejectValue = 128 - -[textures\tx_ivy_01.dds] - alphaRejectValue = 128 - -[textures\tx_saltrice_04.dds] - alphaRejectValue = 128 - -[textures\tx_black_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_01.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_02.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_03.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_04.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_06.dds] - alphaRejectValue = 128 - -[textures\tx_leaves_07.dds] - alphaRejectValue = 128 - -[textures\tx_ai_heather_01.dds] - alphaRejectValue = 96 - -[textures\tx_goldkanet_01.dds] - alphaRejectValue = 128 - -[textures\tx_goldkanet_02.dds] - alphaRejectValue = 128 - -[textures\tx_plant_tails00.dds] - alphaRejectValue = 128 - -[textures\tx_vine_01.dds] - alphaRejectValue = 128 - -[textures\tx_comberry_01.dds] - alphaRejectValue = 128 - -[textures\tx_willow_flower_02.dds] - alphaRejectValue = 128 - -[textures\tx_cork_bulb_02.dds] - alphaRejectValue = 128 - -[textures\tx_green_lichen_01.dds] - alphaRejectValue = 128 - -[textures\tx_roobrush_01.dds] - alphaRejectValue = 128 - -[textures\tx_bittergreen_02.dds] - alphaRejectValue = 128 - -[textures\tx_chokeweed_01.dds] - alphaRejectValue = 128 - -[textures\tx_branches_01.dds] - alphaRejectValue = 128 - -[textures\tx_branches_02.dds] - alphaRejectValue = 128 - -[textures\tx_guarskin_hut_03.dds] - alphaRejectValue = 128 - -[textures\tx_hackle-lo_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_fern_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_fern_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_leaves_02.dds] - alphaRejectValue = 128 - -[textures\tx_marshmerrow_03.dds] - alphaRejectValue = 128 - -[textures\tx_bc_moss_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_moss_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_01.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_02.dds] - alphaRejectValue = 128 - -[textures\tx_bc_lilypad_03.dds] - alphaRejectValue = 128 - -[textures\tx_fire_fern_01.dds] - alphaRejectValue = 128 - -# banners and flags -[textures\tx_flag_imp_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_arena_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_comfort_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_child_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_count_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_faith_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_walk_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_imp_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_redoran_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_avs_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_serving_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_speak_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_stdeyln_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_stolms_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_thin_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_vivec_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_vivec_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_01.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_04.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_05.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_06.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_banner_07.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_a_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_e_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_u_banner.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_z_banner.dds] - alphaRejectValue = 128 - -[textures\tx_banner_6th.dds] - alphaRejectValue = 128 - -[textures\tx_banner_6th_tall.dds] - alphaRejectValue = 128 - -[textures\tx_banner_gnisis_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_gnisis_02.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_bhm_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_02.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_03.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_04.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_05.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_06.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_07.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_08.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_08.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_09.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_10.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_11.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_12.dds] - alphaRejectValue = 128 - -[textures\tx_de_tapestry_13.dds] - alphaRejectValue = 128 - -[textures\tx_de_lutestrings_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_imp_altar_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_akatosh_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_apprentice_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_arkay_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_dibella_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_golem_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_julianos_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_kynareth_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lady_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lord_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_lover_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_mara_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_ritual_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_shadow_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_steed_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_stendarr_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_thief_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_tower_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_warrior_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_wizard_01.dds] - alphaRejectValue = 128 - -[textures\tx_c_t_zenithar_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_dagoth_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_tavern_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_goods_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_danger_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_welcome_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_clothing_01.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_alchemy_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_hlaalu_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_redoran_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_03.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_book_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_ald_velothi.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_gnaar_mok.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_hla_oad.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_khull.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_pawn_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_sadrith_mora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_aruhn.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_branora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_fyr.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_mora.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_telvani_01.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_tel_vos.dds] - alphaRejectValue = 128 - -[textures\tx_de_banner_vos.dds] - alphaRejectValue = 128 - -[textures\tx_bannerd_w_a_shop_01.dds] - alphaRejectValue = 128 - -[textures\tx_banner_temple_02.dds] - alphaRejectValue = 128 - -[textures\tx_mural1_00.dds] - alphaRejectValue = 128 - -[textures\tx_mural1_01.dds] - alphaRejectValue = 128 - -[textures\tx_mural4_00.dds] - alphaRejectValue = 128 - -[textures\tx_mural4_01.dds] - alphaRejectValue = 128 - -[textures\tx_mural5_00.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_telvanni_01.dds] - alphaRejectValue = 128 - -[textures\tx_v_b_hlaalu_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_01.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_02.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_03.dds] - alphaRejectValue = 128 - -[textures\tx_fabric_tapestry_04.dds] - alphaRejectValue = 128 - -# characters -[textures\tx_netchgod00.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_f_hair02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_f_hair03.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair04.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_argonian_m_hair05.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_f_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_f_hair02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_khajiit_m_hair01.dds] - alphaRejectValue = 128 - -[textures\tx_corprus_stalker12.dds] - alphaRejectValue = 128 - -[textures\tx_a_clavicus02.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_dark elf_m_hair11.dds] - alphaRejectValue = 128 - -[textures\tx_b_n_dark elf_f_hair10.dds] - alphaRejectValue = 128 - -# misc items -[textures\tx_sail.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01a.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail01b.dds] - alphaRejectValue = 128 - -[textures\tx_longboatsail02.dds] - alphaRejectValue = 128 - -[textures\tx_quill.dds] - alphaRejectValue = 128 - -[textures\tx_note_01.dds] - alphaRejectValue = 128 - -[textures\tx_note_02.dds] - alphaRejectValue = 128 - -[textures\tx_parchment_02.dds] - alphaRejectValue = 128 - -[textures\tx_parchment_03.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_01.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_02.dds] - alphaRejectValue = 128 - -[textures\tx_scroll_03.dds] - alphaRejectValue = 128 - -[textures\tx_alpha_small_edge.dds] - alphaRejectValue = 128 - -[textures\tx_alpha_shadow_circular.dds] - alphaRejectValue = 128 - -# building materials -[textures\tx_shack_thatch_strip.dds] - alphaRejectValue = 128 - -[textures\tx_rug00.dds] - alphaRejectValue = 128 - -[textures\tx_rug_02.dds] - alphaRejectValue = 128 - -[textures\tx_rug_edge_01.dds] - alphaRejectValue = 128 - -[textures\tx_awning_thatch_02.dds] - alphaRejectValue = 128 - -[textures\tx_awning_woven_01.dds] - alphaRejectValue = 128 - -[textures\tx_bridgeropes.dds] - alphaRejectValue = 128 - -[textures\tx_rope_woven_01.dds] - alphaRejectValue = 128 - -[textures\tx_rope_woven_02.dds] - alphaRejectValue = 128 - -[textures\tx_ashl_tent_06.dds] - alphaRejectValue = 128 - -[textures\tx_guar_tarp.dds] - alphaRejectValue = 128 - -[textures\tx_velothi_glyph00.dds] - alphaRejectValue = 128 - - - -# Bloodmoon - -[textures\tx_bm_holly_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_holly_snow_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_04a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_03a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_02a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_pine_01a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_02.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_01a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_02a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_03a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_snow_pine_04a.dds] - alphaRejectValue = 128 - -[textures\tx_bm_deadpine_01.dds] - alphaRejectValue = 128 - -[textures\tx_bm_shrub_snow_02.dds] - alphaRejectValue = 128 - -[textures\tx_bm_s_deadpine_01.dds] - alphaRejectValue = 128 diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 3542becf64..492a6323b8 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,12 +1,12 @@ set(OENGINE_OGRE - ogre/renderer.cpp + #ogre/renderer.cpp ogre/lights.cpp ogre/selectionbuffer.cpp ) set(OENGINE_GUI gui/loglistener.cpp - gui/manager.cpp + #gui/manager.cpp gui/layout.cpp ) From af67de73a5b75cb4f95e0cd3de64ba2020d6b0b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Apr 2015 17:06:31 +0200 Subject: [PATCH 0092/1812] Delete shiny --- CMakeLists.txt | 6 - apps/opencs/CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 1 - components/terrain/chunk.cpp | 2 - extern/shiny/CMakeLists.txt | 54 - extern/shiny/Docs/Configurations.dox | 32 - extern/shiny/Docs/Doxyfile | 1826 ----------------- extern/shiny/Docs/GettingStarted.dox | 65 - extern/shiny/Docs/Lod.dox | 49 - extern/shiny/Docs/Macros.dox | 283 --- extern/shiny/Docs/Mainpage.dox | 13 - extern/shiny/Docs/Materials.dox | 131 -- extern/shiny/Editor/Actions.cpp | 195 -- extern/shiny/Editor/Actions.hpp | 307 --- extern/shiny/Editor/AddPropertyDialog.cpp | 31 - extern/shiny/Editor/AddPropertyDialog.h | 22 - extern/shiny/Editor/AddPropertyDialog.hpp | 29 - extern/shiny/Editor/CMakeLists.txt | 61 - extern/shiny/Editor/ColoredTabWidget.hpp | 24 - extern/shiny/Editor/Editor.cpp | 117 -- extern/shiny/Editor/Editor.hpp | 73 - extern/shiny/Editor/MainWindow.cpp | 952 --------- extern/shiny/Editor/MainWindow.hpp | 139 -- extern/shiny/Editor/NewMaterialDialog.cpp | 14 - extern/shiny/Editor/NewMaterialDialog.hpp | 22 - extern/shiny/Editor/PropertySortModel.cpp | 35 - extern/shiny/Editor/PropertySortModel.hpp | 21 - extern/shiny/Editor/Query.cpp | 134 -- extern/shiny/Editor/Query.hpp | 121 -- extern/shiny/Editor/addpropertydialog.ui | 118 -- extern/shiny/Editor/mainwindow.ui | 420 ---- extern/shiny/Editor/newmaterialdialog.ui | 98 - extern/shiny/Extra/core.h | 174 -- extern/shiny/License.txt | 9 - extern/shiny/Main/Factory.cpp | 817 -------- extern/shiny/Main/Factory.hpp | 271 --- extern/shiny/Main/Language.hpp | 17 - extern/shiny/Main/MaterialInstance.cpp | 261 --- extern/shiny/Main/MaterialInstance.hpp | 109 - extern/shiny/Main/MaterialInstancePass.cpp | 35 - extern/shiny/Main/MaterialInstancePass.hpp | 29 - .../Main/MaterialInstanceTextureUnit.cpp | 14 - .../Main/MaterialInstanceTextureUnit.hpp | 27 - extern/shiny/Main/Platform.cpp | 89 - extern/shiny/Main/Platform.hpp | 147 -- extern/shiny/Main/Preprocessor.cpp | 151 -- extern/shiny/Main/Preprocessor.hpp | 69 - extern/shiny/Main/PropertyBase.cpp | 302 --- extern/shiny/Main/PropertyBase.hpp | 244 --- extern/shiny/Main/ScriptLoader.cpp | 414 ---- extern/shiny/Main/ScriptLoader.hpp | 134 -- extern/shiny/Main/ShaderInstance.cpp | 698 ------- extern/shiny/Main/ShaderInstance.hpp | 71 - extern/shiny/Main/ShaderSet.cpp | 195 -- extern/shiny/Main/ShaderSet.hpp | 69 - .../shiny/Platforms/Ogre/OgreGpuProgram.cpp | 69 - .../shiny/Platforms/Ogre/OgreGpuProgram.hpp | 31 - extern/shiny/Platforms/Ogre/OgreMaterial.cpp | 120 -- extern/shiny/Platforms/Ogre/OgreMaterial.hpp | 43 - .../Platforms/Ogre/OgreMaterialSerializer.cpp | 85 - .../Platforms/Ogre/OgreMaterialSerializer.hpp | 29 - extern/shiny/Platforms/Ogre/OgrePass.cpp | 131 -- extern/shiny/Platforms/Ogre/OgrePass.hpp | 35 - extern/shiny/Platforms/Ogre/OgrePlatform.cpp | 193 -- extern/shiny/Platforms/Ogre/OgrePlatform.hpp | 74 - .../Platforms/Ogre/OgreTextureUnitState.cpp | 72 - .../Platforms/Ogre/OgreTextureUnitState.hpp | 27 - extern/shiny/Readme.txt | 33 - libs/openengine/CMakeLists.txt | 1 - libs/openengine/ogre/selectionbuffer.cpp | 164 -- libs/openengine/ogre/selectionbuffer.hpp | 62 - 71 files changed, 10911 deletions(-) delete mode 100644 extern/shiny/CMakeLists.txt delete mode 100644 extern/shiny/Docs/Configurations.dox delete mode 100644 extern/shiny/Docs/Doxyfile delete mode 100644 extern/shiny/Docs/GettingStarted.dox delete mode 100644 extern/shiny/Docs/Lod.dox delete mode 100644 extern/shiny/Docs/Macros.dox delete mode 100644 extern/shiny/Docs/Mainpage.dox delete mode 100644 extern/shiny/Docs/Materials.dox delete mode 100644 extern/shiny/Editor/Actions.cpp delete mode 100644 extern/shiny/Editor/Actions.hpp delete mode 100644 extern/shiny/Editor/AddPropertyDialog.cpp delete mode 100644 extern/shiny/Editor/AddPropertyDialog.h delete mode 100644 extern/shiny/Editor/AddPropertyDialog.hpp delete mode 100644 extern/shiny/Editor/CMakeLists.txt delete mode 100644 extern/shiny/Editor/ColoredTabWidget.hpp delete mode 100644 extern/shiny/Editor/Editor.cpp delete mode 100644 extern/shiny/Editor/Editor.hpp delete mode 100644 extern/shiny/Editor/MainWindow.cpp delete mode 100644 extern/shiny/Editor/MainWindow.hpp delete mode 100644 extern/shiny/Editor/NewMaterialDialog.cpp delete mode 100644 extern/shiny/Editor/NewMaterialDialog.hpp delete mode 100644 extern/shiny/Editor/PropertySortModel.cpp delete mode 100644 extern/shiny/Editor/PropertySortModel.hpp delete mode 100644 extern/shiny/Editor/Query.cpp delete mode 100644 extern/shiny/Editor/Query.hpp delete mode 100644 extern/shiny/Editor/addpropertydialog.ui delete mode 100644 extern/shiny/Editor/mainwindow.ui delete mode 100644 extern/shiny/Editor/newmaterialdialog.ui delete mode 100644 extern/shiny/Extra/core.h delete mode 100644 extern/shiny/License.txt delete mode 100644 extern/shiny/Main/Factory.cpp delete mode 100644 extern/shiny/Main/Factory.hpp delete mode 100644 extern/shiny/Main/Language.hpp delete mode 100644 extern/shiny/Main/MaterialInstance.cpp delete mode 100644 extern/shiny/Main/MaterialInstance.hpp delete mode 100644 extern/shiny/Main/MaterialInstancePass.cpp delete mode 100644 extern/shiny/Main/MaterialInstancePass.hpp delete mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.cpp delete mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.hpp delete mode 100644 extern/shiny/Main/Platform.cpp delete mode 100644 extern/shiny/Main/Platform.hpp delete mode 100644 extern/shiny/Main/Preprocessor.cpp delete mode 100644 extern/shiny/Main/Preprocessor.hpp delete mode 100644 extern/shiny/Main/PropertyBase.cpp delete mode 100644 extern/shiny/Main/PropertyBase.hpp delete mode 100644 extern/shiny/Main/ScriptLoader.cpp delete mode 100644 extern/shiny/Main/ScriptLoader.hpp delete mode 100644 extern/shiny/Main/ShaderInstance.cpp delete mode 100644 extern/shiny/Main/ShaderInstance.hpp delete mode 100644 extern/shiny/Main/ShaderSet.cpp delete mode 100644 extern/shiny/Main/ShaderSet.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePass.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePass.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.hpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp delete mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp delete mode 100644 extern/shiny/Readme.txt delete mode 100644 libs/openengine/ogre/selectionbuffer.cpp delete mode 100644 libs/openengine/ogre/selectionbuffer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bf525646d0..77bea373fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,7 +418,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install licenses INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) - INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") @@ -542,7 +541,6 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -#add_subdirectory (extern/shiny) #add_subdirectory (extern/ogre-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) @@ -680,10 +678,6 @@ if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") - # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here - set(SHINY_WARNINGS "${WARNINGS} /wd4245") - set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 103a56ecc6..bae1ec4d44 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -204,7 +204,6 @@ target_link_libraries(openmw-cs ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} - ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} ${QT_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 56ee82d7d5..50aeafc2aa 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -129,7 +129,6 @@ target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} - ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index cce5abd363..e3bae11732 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -27,8 +27,6 @@ #include #include -#include - namespace Terrain { diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt deleted file mode 100644 index daf2a9df8d..0000000000 --- a/extern/shiny/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. -# Make sure to link against Ogre and boost::filesystem. - -option(SHINY_BUILD_OGRE_PLATFORM "build the Ogre platform" ON) - -set(SHINY_LIBRARY "shiny") -set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") - -# Sources -set(SOURCE_FILES - Main/Factory.cpp - Main/MaterialInstance.cpp - Main/MaterialInstancePass.cpp - Main/MaterialInstanceTextureUnit.cpp - Main/Platform.cpp - Main/Preprocessor.cpp - Main/PropertyBase.cpp - Main/ScriptLoader.cpp - Main/ShaderInstance.cpp - Main/ShaderSet.cpp -) - -set(OGRE_PLATFORM_SOURCE_FILES - Platforms/Ogre/OgreGpuProgram.cpp - Platforms/Ogre/OgreMaterial.cpp - Platforms/Ogre/OgreMaterialSerializer.cpp - Platforms/Ogre/OgrePass.cpp - Platforms/Ogre/OgrePlatform.cpp - Platforms/Ogre/OgreTextureUnitState.cpp -) - -file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp) - -add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) - -set(SHINY_LIBRARIES ${SHINY_LIBRARY}) - -if (SHINY_BUILD_OGRE_PLATFORM) - add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY}) -endif() - -set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) - -if (DEFINED SHINY_BUILD_MATERIAL_EDITOR) - add_subdirectory(Editor) - - set(SHINY_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE) -endif() - -link_directories(${CMAKE_CURRENT_BINARY_DIR}) -set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) diff --git a/extern/shiny/Docs/Configurations.dox b/extern/shiny/Docs/Configurations.dox deleted file mode 100644 index 570e81d4af..0000000000 --- a/extern/shiny/Docs/Configurations.dox +++ /dev/null @@ -1,32 +0,0 @@ -/*! - - \page configurations Configurations - - A common task in shader development is to provide a different set of simpler shaders for all your materials. Some examples: - - When rendering cubic or planar reflection maps in real-time, you will want to disable shadows. - - For an in-game minimap render target, you don't want to have fog. - - For this task, the library provides a \a Configuration concept. - - A Configuration is a set of properties that can override global settings, as long as this Configuration is active. - - Here's an example. Say you have a global setting with the name 'shadows' that controls if your materials receive shadows. - - Now, lets create a configuration for our reflection render targets that disables shadows for all materials. Paste the following in a new file with the extension '.configuration': - - \code - configuration reflection_targets - { - shadows false - } - \endcode - - \note You may also create configurations using sh::Factory::createConfiguration. - - The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call - \code - viewport->setMaterialScheme ("reflection_targets"); - \endcode - on the Ogre viewport of your reflection render! - -*/ diff --git a/extern/shiny/Docs/Doxyfile b/extern/shiny/Docs/Doxyfile deleted file mode 100644 index 3564c45f67..0000000000 --- a/extern/shiny/Docs/Doxyfile +++ /dev/null @@ -1,1826 +0,0 @@ -# Doxyfile 1.8.1.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = shiny - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = /home/scrawl/sh_doxy/generated - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = ../ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.d \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.idl \ - *.odl \ - *.cs \ - *.php \ - *.php3 \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.for \ - *.vhd \ - *.vhdl - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/extern/shiny/Docs/GettingStarted.dox b/extern/shiny/Docs/GettingStarted.dox deleted file mode 100644 index b9cf58e23a..0000000000 --- a/extern/shiny/Docs/GettingStarted.dox +++ /dev/null @@ -1,65 +0,0 @@ -/*! - \page getting-started Getting started - - \section download Download the source - - \code - git clone git@github.com:scrawl/shiny.git - \endcode - - \section building Build the source - - The source files you want to build are: - - Main/*.cpp - - Preprocessor/*.cpp (unless you are using the system install of boost::wave, more below) - - Platforms/Ogre/*.cpp - - You can either build the sources as a static library, or simply add the sources to the source tree of your project. - - If you use CMake, you might find the included CMakeLists.txt useful. It builds static libraries with the names "shiny" and "shiny.OgrePlatform". - - \note The CMakeLists.txt is not intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. - - Make sure to link against OGRE and the boost filesystem library. - - If your boost version is older than 1.49, you must set the SHINY_USE_WAVE_SYSTEM_INSTALL variable and additionally link against the boost wave library. - - \code - set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") - \endcode - - \section code Basic initialisation code - - Add the following code to your application: - - \code{cpp} - - #include - #include - - .... - - sh::OgrePlatform* platform = new sh::OgrePlatform( - "General", // OGRE Resource group to use for creating materials. - myApplication.getDataPath() + "/" + "materials" // Path to look for materials and shaders. NOTE: This does NOT use the Ogre resource system, so you have to specify an absolute path. - ); - - sh::Factory* factory = new sh::Factory(platform); - - // Set a language. Valid options: CG, HLSL, GLSL - factory->setCurrentLanguage(sh::Language_GLSL); - - factory->loadAllFiles(); - - .... - your application runs here - .... - - // don't forget to delete on exit - delete factory; - - \endcode - - That's it! Now you can start defining materials. Refer to the page \ref defining-materials-shaders . - -*/ diff --git a/extern/shiny/Docs/Lod.dox b/extern/shiny/Docs/Lod.dox deleted file mode 100644 index 37d004638e..0000000000 --- a/extern/shiny/Docs/Lod.dox +++ /dev/null @@ -1,49 +0,0 @@ -/*! - - \page lod Material LOD - - \section howitworks How it works - - When Ogre requests a technique for a specific LOD index, the Factory selects the appropriate LOD configuration which then temporarily overrides the global settings in the shaders. We can use this to disable shader features one by one at a lower LOD, resulting in simpler and faster techniques for distant objects. - - \section howtouseit How to use it - - - Create a file with the extension '.lod'. There you can specify shader features to disable at a specific LOD level. Higher LOD index refers to a lower LOD. Example contents: - - \code - lod_configuration 1 - { - specular_mapping false - } - - lod_configuration 2 - { - specular_mapping false - normal_mapping false - } - - lod_configuration 3 - { - terrain_composite_map true - specular_mapping false - normal_mapping false - } - \endcode - - \note You can also add LOD configurations by calling \a sh::Factory::registerLodConfiguration. - - \note Do not use an index of 0. LOD 0 refers to the highest LOD, and you will never want to disable features at the highest LOD level. - - - - In your materials, specify the distances at which a lower LOD kicks in. Note that the actual distance might also be affected by the viewport and current entity LOD bias. In this example, the first LOD level (lod index 1) would normally be applied at a distance of 100 units, the next after 300, and the last after 1000 units. - - \code - material sample_material - { - lod_values 100 300 1000 - - ... your passes, texture units etc ... - } - \endcode - -*/ diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox deleted file mode 100644 index c04ebd3747..0000000000 --- a/extern/shiny/Docs/Macros.dox +++ /dev/null @@ -1,283 +0,0 @@ -/*! - \page macros Shader Macros - - \tableofcontents - - \section Shader Language - - These macros are automatically defined, depending on the shader language that has been set by the application using sh::Factory::setCurrentLanguage. - - - SH_GLSL - - SH_HLSL - - SH_CG - - Example: - - \code - #if SH_GLSL == 1 - // glsl porting code - #endif - - #if SH_CG == 1 || SH_HLSL == 1 - // cg / hlsl porting code (similiar syntax) - #endif - \endcode - - \note It is encouraged to use the shipped porting header (extra/core.h) by #include-ing it in your shaders. If you do that, you should not have to use the above macros directly. - - \section vertex-fragment Vertex / fragment shader - - These macros are automatically defined, depending on the type of shader that is currently being compiled. - - - SH_VERTEX_SHADER - - SH_FRAGMENT_SHADER - - If you use the same source file for both vertex and fragment shader, then it is advised to use these macros for blending out the unused source. This will reduce your compile time. - - \section passthrough Vertex -> Fragment passthrough - - In shader development, a common task is to pass variables from the vertex to the fragment shader. This is no problem if you have a deterministic shader source (i.e. no #ifdefs). - - However, as soon as you begin to have lots of permutations of the same shader source, a problem arises. All current GPUs have a limit of 8 vertex to fragment passthroughs (with 4 components each, for example a float4). - - A common optimization is to put several individual float values together in a float4 (so-called "Packing"). But if your shader has lots of permutations and the passthrough elements you actually need are not known beforehand, it can be very tedious to pack manually. With the following macros, packing can become easier. - - \subsection shAllocatePassthrough shAllocatePassthrough - - Usage: \@shAllocatePassthrough(num_components, name) - - Example: - \code - #if FRAGMENT_NEED_DEPTH - @shAllocatePassthrough(1, depth) - #endif - \endcode - - This is the first thing you should do before using any of the macros below. - - \subsection shPassthroughVertexOutputs shPassthroughVertexOutputs - - Usage: \@shPassthroughVertexOutputs - - Use this in the inputs/outputs section of your vertex shader, in order to declare all the outputs that are needed for packing the variables that you want passed to the fragment. - - \subsection shPassthroughFragmentInputs shPassthroughFragmentInputs - - Usage: \@shPassthroughFragmentInputs - - Use this in the inputs/outputs section of your fragment shader, in order to declare all the inputs that are needed for receiving the variables that you want passed to the fragment. - - \subsection shPassthroughAssign shPassthroughAssign - - Usage: \@shPassthroughAssign(name, value) - - Use this in the vertex shader for assigning a value to the variable you want passed to the fragment. - - Example: - \code - #if FRAGMENT_NEED_DEPTH - @shPassthroughAssign(depth, shOutputPosition.z); - #endif - - \endcode - - \subsection shPassthroughReceive shPassthroughReceive - - Usage: \@shPassthroughReceive(name) - - Use this in the fragment shader to receive the passed value. - - Example: - - \code - #if FRAGMENT_NEED_DEPTH - float depth = @shPassthroughReceive(depth); - #endif - \endcode - - \section texUnits Texture units - - \subsection shUseSampler shUseSampler - - Usage: \@shUseSampler(samplerName) - - Requests the texture unit with name \a samplerName to be available for use in this pass. - - Why is this necessary? If you have a derived material that does not use all of the texture units that its parent defines (for example, if an optional asset such as a normal map is not available), there would be no way to know which texture units are actually needed and which can be skipped in the creation process (those that are never referenced in the shader). - - \section properties Property retrieval / binding - - \subsection shPropertyHasValue shPropertyHasValue - - Usage: \@shPropertyHasValue(property) - - Gets replaced by 1 if the property's value is not empty, or 0 if it is empty. - Useful for checking whether an optional texture is present or not. - - Example: - \code - #if @shPropertyHasValue(specularMap) - // specular mapping code - #endif - #if @shPropertyHasValue(normalMap) - // normal mapping code - #endif - \endcode - - \subsection shUniformProperty shUniformProperty - - Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) - - Binds the value of \a property (from the shader_properties of the pass this shader belongs to) to the uniform with name \a uniformName. - - The following variants are available, depending on the type of your uniform variable: - - \@shUniformProperty4f - - \@shUniformProperty3f - - \@shUniformProperty2f - - \@shUniformProperty1f - - \@shUniformPropertyInt - - Example: \@shUniformProperty1f (uFresnelScale, fresnelScale) - - \subsection shPropertyBool shPropertyBool - - Retrieve a boolean property of the pass that this shader belongs to, gets replaced with either 0 or 1. - - Usage: \@shPropertyBool(propertyName) - - Example: - \code - #if @shPropertyBool(has_vertex_colors) - ... - #endif - \endcode - - \subsection shPropertyString shPropertyString - - Retrieve a string property of the pass that this shader belongs to - - Usage: \@shPropertyString(propertyName) - - \subsection shPropertyEqual shPropertyEqual - - Check if the value of a property equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. - - Usage: \@shPropertyEqual(propertyName, value) - - Example: - \code - #if @shPropertyEqual(lighting_mode, phong) - ... - #endif - \endcode - - \section globalSettings Global settings - - \subsection shGlobalSettingBool shGlobalSettingBool - - Retrieves the boolean value of a specific global setting, gets replaced with either 0 or 1. The value can be set using sh::Factory::setGlobalSetting. - - Usage: \@shGlobalSettingBool(settingName) - - \subsection shGlobalSettingEqual shGlobalSettingEqual - - Check if the value of a global setting equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. - - Usage: \@shGlobalSettingEqual(settingName, value) - - \subsection shGlobalSettingString shGlobalSettingString - - Gets replaced with the current value of a given global setting. The value can be set using sh::Factory::setGlobalSetting. - - Usage: \@shGlobalSettingString(settingName) - - \section sharedParams Shared parameters - - \subsection shSharedParameter shSharedParameter - - Allows you to bind a custom value to a uniform parameter. - - Usage: \@shSharedParameter(sharedParameterName) - - Example: \@shSharedParameter(pssmSplitPoints) - now the uniform parameter 'pssmSplitPoints' can be altered in all shaders that use it by executing sh::Factory::setSharedParameter("pssmSplitPoints", value) - - \note You may use the same shared parameter in as many shaders as you want. But don't forget to add the \@shSharedParameter macro to every shader that uses this shared parameter. - - \section autoconstants Auto constants - - \subsection shAutoConstant shAutoConstant - - Usage: \@shAutoConstant(uniformName, autoConstantName, [extraData]) - - Example: \@shAutoConstant(uModelViewMatrix, worldviewproj_matrix) - - Example: \@shAutoConstant(uLightPosition4, light_position, 4) - - Binds auto constant with name \a autoConstantName to the uniform \a uniformName. Optionally, you may specify extra data (for example the light index), as required by some auto constants. - - The auto constant names are the same as Ogre's. Read the section "3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass" of the Ogre manual for a list of all auto constant names. - - \section misc Misc - - \subsection shForeach shForeach - - Usage: \@shForeach(n) - - Repeats the content of this foreach block \a n times. The end of the block is marked via \@shEndForeach, and the current iteration number can be retrieved via \@shIterator. - - \note Nested foreach blocks are currently \a not supported. - - \note For technical reasons, you can only use constant numbers, properties (\@shPropertyString) or global settings (\@shGlobalSettingString) as \a n parameter. - - Example: - - \code - @shForeach(3) - this is iteration number @shIterator - @shEndForeach - - Gets replaced with: - - this is iteration number 0 - this is iteration number 1 - this is iteration number 2 - \endcode - - Optionally, you can pass a constant offset to \@shIterator. Example: - - \code - @shForeach(3) - this is iteration number @shIterator(7) - @shEndForeach - - Gets replaced with: - - this is iteration number 7 - this is iteration number 8 - this is iteration number 9 - \endcode - - \subsection shCounter shCounter - - Gets replaced after the preprocessing step with the number that equals the n-th occurence of counters of the same ID. - - Usage: \@shCounter(ID) - - Example: - \code - @shCounter(0) - @shCounter(0) - @shCounter(1) - @shCounter(0) - \endcode - - Gets replaced with: - - \code - 0 - 1 - 0 - 2 - \endcode - -*/ diff --git a/extern/shiny/Docs/Mainpage.dox b/extern/shiny/Docs/Mainpage.dox deleted file mode 100644 index fb8f596dc0..0000000000 --- a/extern/shiny/Docs/Mainpage.dox +++ /dev/null @@ -1,13 +0,0 @@ -/*! - - \mainpage - - - \ref getting-started - - \ref defining-materials-shaders - - \ref macros - - \ref configurations - - \ref lod - - - sh::Factory - the main interface class - -*/ diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox deleted file mode 100644 index d08599a04a..0000000000 --- a/extern/shiny/Docs/Materials.dox +++ /dev/null @@ -1,131 +0,0 @@ -/*! - - \page defining-materials-shaders Defining materials and shaders - - \section first-material Your first material - - Create a file called "myFirstMaterial.mat" and place it in the path you have used in your initialisation code (see \ref getting-started). Paste the following: - - \code - - material my_first_material - { - 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 - diffuseMap black.png - - pass - { - diffuse $diffuse - specular $specular - ambient $ambient - emissive $emissive - - texture_unit diffuseMap - { - texture $diffuseMap - create_in_ffp true // use this texture unit for fixed function pipeline - } - } - } - - material material1 - { - parent my_first_material - diffuseMap texture1.png - } - - material material2 - { - parent my_first_material - diffuseMap texture2.png - } - - \endcode - - \section first-shader The first shader - - Change the 'pass' section to include some shaders: - - \code - pass - { - vertex_program my_first_shader_vertex - fragment_program my_first_shader_fragment - ... - } - \endcode - - \note This does \a not refer to a single shader with a fixed source code, but in fact will automatically create a new \a instance of this shader (if necessary), which can have its own uniform variables, compile-time macros and much more! - - Next, we're going to define our shaders. Paste this in a new file called 'myfirstshader.shaderset' - - \code - shader_set my_first_shader_vertex - { - source example.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 - } - - shader_set my_first_shader_fragment - { - source example.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 - } - \endcode - - Some notes: - - There is no entry_point property because the entry point is always \a main. - - Both profiles_cg and profiles_hlsl are a list of shader profiles. The first profile that is supported is automatically picked. GLSL does not have shader profiles. - - Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'. - Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'. - - Important: a newline at the end of the file is required. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave. - - \code - #include "core.h" - - #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 - // NOTE: It is important that the sampler name here (diffuseMap) matches - // the name of the texture unit in the material. This is necessary because the system - // skips texture units that are never "referenced" in the shader. This can be the case - // when your base material has optional assets (for example a normal map) that are not - // used by some derived materials. - shSampler2D(diffuseMap) - shInput(float2, UV) - SH_START_PROGRAM - { - shOutputColour(0) = shSample(diffuseMap, UV); - } - - #endif - - \endcode - - There you have it! This shader will compile in several languages thanks to the porting defines in "core.h". If you need more defines, feel free to add them and don't forget to send them to me! - - For a full list of macros available when writing your shaders, refer to the page \ref macros - - In the future, some more in-depth shader examples might follow. -*/ diff --git a/extern/shiny/Editor/Actions.cpp b/extern/shiny/Editor/Actions.cpp deleted file mode 100644 index 135e819878..0000000000 --- a/extern/shiny/Editor/Actions.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "Actions.hpp" - -#include "../Main/Factory.hpp" - -namespace sh -{ - - void ActionDeleteMaterial::execute() - { - sh::Factory::getInstance().destroyMaterialInstance(mName); - } - - void ActionCloneMaterial::execute() - { - sh::MaterialInstance* sourceMaterial = sh::Factory::getInstance().getMaterialInstance(mSourceName); - std::string sourceMaterialParent = static_cast(sourceMaterial->getParent())->getName(); - sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance( - mDestName, sourceMaterialParent); - sourceMaterial->copyAll(material, sourceMaterial, false); - - material->setSourceFile(sourceMaterial->getSourceFile()); - } - - void ActionSaveAll::execute() - { - sh::Factory::getInstance().saveAll(); - } - - void ActionChangeGlobalSetting::execute() - { - sh::Factory::getInstance().setGlobalSetting(mName, mNewValue); - } - - void ActionCreateConfiguration::execute() - { - sh::Configuration newConfiguration; - sh::Factory::getInstance().createConfiguration(mName); - } - - void ActionDeleteConfiguration::execute() - { - sh::Factory::getInstance().destroyConfiguration(mName); - } - - void ActionChangeConfiguration::execute() - { - sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); - c->setProperty(mKey, sh::makeProperty(new sh::StringValue(mValue))); - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteConfigurationProperty::execute() - { - sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); - c->deleteProperty(mKey); - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetMaterialProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->setProperty(mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteMaterialProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionCreatePass::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->createPass(); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeletePass::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - m->deletePass(mPassIndex); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetPassProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).setProperty (mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeletePassProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetShaderProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).mShaderProperties.setProperty (mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteShaderProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).mShaderProperties.deleteProperty (mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionSetTextureProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).setProperty(mKey, sh::makeProperty(mValue)); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteTextureProperty::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).deleteProperty(mKey); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionCreateTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - m->getPasses()->at(mPassIndex).createTextureUnit(mTexUnitName); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionDeleteTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - - m->getPasses()->at(mPassIndex).mTexUnits.erase(m->getPasses()->at(mPassIndex).mTexUnits.begin() + mTextureIndex); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionMoveTextureUnit::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - if (!mMoveUp) - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex+1); - - std::vector textures = m->getPasses()->at(mPassIndex).mTexUnits; - if (mMoveUp) - std::swap(textures[mTextureIndex-1], textures[mTextureIndex]); - else - std::swap(textures[mTextureIndex+1], textures[mTextureIndex]); - m->getPasses()->at(mPassIndex).mTexUnits = textures; - - sh::Factory::getInstance().notifyConfigurationChanged(); - } - - void ActionChangeTextureUnitName::execute() - { - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - assert (m->getPasses()->size() > mPassIndex); - assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); - - m->getPasses()->at(mPassIndex).mTexUnits[mTextureIndex].setName(mTexUnitName); - - sh::Factory::getInstance().notifyConfigurationChanged(); - } -} diff --git a/extern/shiny/Editor/Actions.hpp b/extern/shiny/Editor/Actions.hpp deleted file mode 100644 index 1bbdbe5a98..0000000000 --- a/extern/shiny/Editor/Actions.hpp +++ /dev/null @@ -1,307 +0,0 @@ -#ifndef SH_ACTIONS_H -#define SH_ACTIONS_H - -#include - -namespace sh -{ - - class Action - { - public: - virtual void execute() = 0; - virtual ~Action() {} - }; - - class ActionDeleteMaterial : public Action - { - public: - ActionDeleteMaterial(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - }; - - class ActionCloneMaterial : public Action - { - public: - ActionCloneMaterial(const std::string& sourceName, const std::string& destName) - : mSourceName(sourceName), mDestName(destName) {} - - virtual void execute(); - private: - std::string mSourceName; - std::string mDestName; - }; - - class ActionSaveAll : public Action - { - public: - virtual void execute(); - }; - - class ActionChangeGlobalSetting : public Action - { - public: - ActionChangeGlobalSetting(const std::string& name, const std::string& newValue) - : mName(name), mNewValue(newValue) {} - - virtual void execute(); - private: - std::string mName; - std::string mNewValue; - }; - - // configuration - - class ActionCreateConfiguration : public Action - { - public: - ActionCreateConfiguration(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - - }; - - class ActionDeleteConfiguration : public Action - { - public: - ActionDeleteConfiguration(const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - - }; - - class ActionChangeConfiguration : public Action - { - public: - ActionChangeConfiguration (const std::string& name, const std::string& key, const std::string& value) - : mName(name), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteConfigurationProperty : public Action - { - public: - ActionDeleteConfigurationProperty (const std::string& name, const std::string& key) - : mName(name), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - }; - - // material - - class ActionSetMaterialProperty : public Action - { - public: - ActionSetMaterialProperty (const std::string& name, const std::string& key, const std::string& value) - : mName(name), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteMaterialProperty : public Action - { - public: - ActionDeleteMaterialProperty (const std::string& name, const std::string& key) - : mName(name), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - std::string mKey; - }; - - // pass - - class ActionCreatePass : public Action - { - public: - ActionCreatePass (const std::string& name) - : mName(name) {} - - virtual void execute(); - private: - std::string mName; - }; - - class ActionDeletePass : public Action - { - public: - ActionDeletePass (const std::string& name, int passIndex) - : mName(name), mPassIndex(passIndex) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - }; - - class ActionSetPassProperty : public Action - { - public: - ActionSetPassProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeletePassProperty : public Action - { - public: - ActionDeletePassProperty (const std::string& name, int passIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - }; - - // shader - - class ActionSetShaderProperty : public Action - { - public: - ActionSetShaderProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteShaderProperty : public Action - { - public: - ActionDeleteShaderProperty (const std::string& name, int passIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - std::string mKey; - }; - - // texture unit - - class ActionChangeTextureUnitName : public Action - { - public: - ActionChangeTextureUnitName (const std::string& name, int passIndex, int textureIndex, const std::string& texUnitName) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mTexUnitName(texUnitName) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mTexUnitName; - }; - - class ActionCreateTextureUnit : public Action - { - public: - ActionCreateTextureUnit (const std::string& name, int passIndex, const std::string& texUnitName) - : mName(name), mPassIndex(passIndex), mTexUnitName(texUnitName) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - std::string mTexUnitName; - }; - - class ActionDeleteTextureUnit : public Action - { - public: - ActionDeleteTextureUnit (const std::string& name, int passIndex, int textureIndex) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - }; - - class ActionMoveTextureUnit : public Action - { - public: - ActionMoveTextureUnit (const std::string& name, int passIndex, int textureIndex, bool moveUp) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mMoveUp(moveUp) {} - - virtual void execute(); - - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - bool mMoveUp; - }; - - class ActionSetTextureProperty : public Action - { - public: - ActionSetTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key, const std::string& value) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key), mValue(value) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mKey; - std::string mValue; - }; - - class ActionDeleteTextureProperty : public Action - { - public: - ActionDeleteTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key) - : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key) {} - - virtual void execute(); - private: - std::string mName; - int mPassIndex; - int mTextureIndex; - std::string mKey; - }; - -} - -#endif diff --git a/extern/shiny/Editor/AddPropertyDialog.cpp b/extern/shiny/Editor/AddPropertyDialog.cpp deleted file mode 100644 index 71b47feb19..0000000000 --- a/extern/shiny/Editor/AddPropertyDialog.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "AddPropertyDialog.hpp" -#include "ui_addpropertydialog.h" - -AddPropertyDialog::AddPropertyDialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::AddPropertyDialog) - , mType(0) -{ - ui->setupUi(this); - - connect(ui->buttonBox, SIGNAL(accepted()), - this, SLOT(accepted())); - connect(ui->buttonBox, SIGNAL(rejected()), - this, SLOT(rejected())); -} - -void AddPropertyDialog::accepted() -{ - mName = ui->lineEdit->text(); - mType = ui->comboBox->currentIndex(); -} - -void AddPropertyDialog::rejected() -{ - mName = ""; -} - -AddPropertyDialog::~AddPropertyDialog() -{ - delete ui; -} diff --git a/extern/shiny/Editor/AddPropertyDialog.h b/extern/shiny/Editor/AddPropertyDialog.h deleted file mode 100644 index c1d2c960b5..0000000000 --- a/extern/shiny/Editor/AddPropertyDialog.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ADDPROPERTYDIALOG_H -#define ADDPROPERTYDIALOG_H - -#include - -namespace Ui { -class AddPropertyDialog; -} - -class AddPropertyDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AddPropertyDialog(QWidget *parent = 0); - ~AddPropertyDialog(); - -private: - Ui::AddPropertyDialog *ui; -}; - -#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/AddPropertyDialog.hpp b/extern/shiny/Editor/AddPropertyDialog.hpp deleted file mode 100644 index b4e19b0870..0000000000 --- a/extern/shiny/Editor/AddPropertyDialog.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ADDPROPERTYDIALOG_H -#define ADDPROPERTYDIALOG_H - -#include - -namespace Ui { -class AddPropertyDialog; -} - -class AddPropertyDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AddPropertyDialog(QWidget *parent = 0); - ~AddPropertyDialog(); - - int mType; - QString mName; - -public slots: - void accepted(); - void rejected(); - -private: - Ui::AddPropertyDialog *ui; -}; - -#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/CMakeLists.txt b/extern/shiny/Editor/CMakeLists.txt deleted file mode 100644 index eead159f08..0000000000 --- a/extern/shiny/Editor/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -set(SHINY_EDITOR_LIBRARY "shiny.Editor") - -find_package(Qt4) - -if (QT_FOUND) - - add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=1) - set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=1 PARENT_SCOPE) - - set(QT_USE_QTGUI 1) - - # Headers that must be preprocessed - set(SHINY_EDITOR_HEADER_MOC - MainWindow.hpp - NewMaterialDialog.hpp - AddPropertyDialog.hpp - PropertySortModel.hpp - ) - - set(SHINY_EDITOR_UI - mainwindow.ui - newmaterialdialog.ui - addpropertydialog.ui - ) - - QT4_WRAP_CPP(MOC_SRCS ${SHINY_EDITOR_HEADER_MOC}) - QT4_WRAP_UI(UI_HDRS ${SHINY_EDITOR_UI}) - - set(SOURCE_FILES - NewMaterialDialog.cpp - AddPropertyDialog.cpp - ColoredTabWidget.hpp - MainWindow.cpp - Editor.cpp - Actions.cpp - Query.cpp - PropertySortModel.cpp - ${SHINY_EDITOR_UI} # Just to have them in the IDE's file explorer - ) - - include(${QT_USE_FILE}) - - set (CMAKE_INCLUDE_CURRENT_DIR "true") - - include_directories(${CMAKE_CURRENT_BINARY_DIR}) - - add_library(${SHINY_EDITOR_LIBRARY} STATIC ${SOURCE_FILES} ${MOC_SRCS} ${UI_HDRS}) - - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} - ${SHINY_EDITOR_LIBRARY} - ${QT_LIBRARIES} - ) - set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) - -else (QT_FOUND) - - add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=0) - set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=0 PARENT_SCOPE) - message(STATUS "QT4 was not found. You will not be able to use the material editor.") - -endif(QT_FOUND) diff --git a/extern/shiny/Editor/ColoredTabWidget.hpp b/extern/shiny/Editor/ColoredTabWidget.hpp deleted file mode 100644 index 0bf30f6dda..0000000000 --- a/extern/shiny/Editor/ColoredTabWidget.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SHINY_EDITOR_COLOREDTABWIDGET_H -#define SHINY_EDITOR_COLOREDTABWIDGET_H - -#include - -namespace sh -{ - -/// Makes tabBar() public to allow changing tab title colors. -class ColoredTabWidget : public QTabWidget -{ -public: - ColoredTabWidget(QWidget* parent = 0) - : QTabWidget(parent) {} - - QTabBar* tabBar() - { - return QTabWidget::tabBar(); - } -}; - -} - -#endif diff --git a/extern/shiny/Editor/Editor.cpp b/extern/shiny/Editor/Editor.cpp deleted file mode 100644 index 8c58d0e66d..0000000000 --- a/extern/shiny/Editor/Editor.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "Editor.hpp" - - -#include -#include - -#include - -#include "../Main/Factory.hpp" - -#include "MainWindow.hpp" - -namespace sh -{ - - Editor::Editor() - : mMainWindow(NULL) - , mApplication(NULL) - , mInitialized(false) - , mThread(NULL) - { - } - - Editor::~Editor() - { - if (mMainWindow) - mMainWindow->mRequestExit = true; - - if (mThread) - mThread->join(); - delete mThread; - } - - void Editor::show() - { - if (!mInitialized) - { - mInitialized = true; - - mThread = new boost::thread(boost::bind(&Editor::runThread, this)); - } - else - { - if (mMainWindow) - mMainWindow->mRequestShowWindow = true; - } - } - - void Editor::runThread() - { - int argc = 0; - char** argv = NULL; - mApplication = new QApplication(argc, argv); - mApplication->setQuitOnLastWindowClosed(false); - mMainWindow = new MainWindow(); - mMainWindow->mSync = &mSync; - mMainWindow->show(); - - mApplication->exec(); - - delete mApplication; - } - - void Editor::update() - { - sh::Factory::getInstance().doMonitorShaderFiles(); - - if (!mMainWindow) - return; - - - { - boost::mutex::scoped_lock lock(mSync.mActionMutex); - - // execute pending actions - while (mMainWindow->mActionQueue.size()) - { - Action* action = mMainWindow->mActionQueue.front(); - action->execute(); - delete action; - mMainWindow->mActionQueue.pop(); - } - } - { - boost::mutex::scoped_lock lock(mSync.mQueryMutex); - - // execute pending queries - for (std::vector::iterator it = mMainWindow->mQueries.begin(); it != mMainWindow->mQueries.end(); ++it) - { - Query* query = *it; - if (!query->mDone) - query->execute(); - } - } - - boost::mutex::scoped_lock lock2(mSync.mUpdateMutex); - - // update the list of materials - mMainWindow->mState.mMaterialList.clear(); - sh::Factory::getInstance().listMaterials(mMainWindow->mState.mMaterialList); - - // update global settings - mMainWindow->mState.mGlobalSettingsMap.clear(); - sh::Factory::getInstance().listGlobalSettings(mMainWindow->mState.mGlobalSettingsMap); - - // update configuration list - mMainWindow->mState.mConfigurationList.clear(); - sh::Factory::getInstance().listConfigurationNames(mMainWindow->mState.mConfigurationList); - - // update shader list - mMainWindow->mState.mShaderSets.clear(); - sh::Factory::getInstance().listShaderSets(mMainWindow->mState.mShaderSets); - - mMainWindow->mState.mErrors += sh::Factory::getInstance().getErrorLog(); - } - -} diff --git a/extern/shiny/Editor/Editor.hpp b/extern/shiny/Editor/Editor.hpp deleted file mode 100644 index 2b1e8040d0..0000000000 --- a/extern/shiny/Editor/Editor.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef SH_EDITOR_H -#define SH_EDITOR_H - -#if SHINY_BUILD_MATERIAL_EDITOR -class QApplication; - -#include -#include - -namespace boost -{ - class thread; -} - -namespace sh -{ - class MainWindow; - - struct SynchronizationState - { - boost::mutex mUpdateMutex; - boost::mutex mActionMutex; - boost::mutex mQueryMutex; - }; - - class Editor - { - public: - - Editor(); - ~Editor(); - - void show(); - void update(); - - - private: - bool mInitialized; - - MainWindow* mMainWindow; - QApplication* mApplication; - - SynchronizationState mSync; - - boost::thread* mThread; - - void runThread(); - - void processShowWindow(); - }; - -} - -#else - -// Dummy implementation, so that the user's code does not have to be polluted with #ifdefs -namespace sh -{ - - class Editor - { - public: - Editor() {} - ~Editor() {} - void show() {} - void update() {} - - }; -} - -#endif - -#endif diff --git a/extern/shiny/Editor/MainWindow.cpp b/extern/shiny/Editor/MainWindow.cpp deleted file mode 100644 index a2c52dc2f8..0000000000 --- a/extern/shiny/Editor/MainWindow.cpp +++ /dev/null @@ -1,952 +0,0 @@ -#include "MainWindow.hpp" -#include "ui_mainwindow.h" - -#include - -#include -#include - -#include -#include - -#include "Editor.hpp" -#include "ColoredTabWidget.hpp" -#include "AddPropertyDialog.hpp" - -sh::MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) - , mRequestShowWindow(false) - , mRequestExit(false) - , mIgnoreGlobalSettingChange(false) - , mIgnoreConfigurationChange(false) - , mIgnoreMaterialChange(false) - , mIgnoreMaterialPropertyChange(false) -{ - ui->setupUi(this); - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(onIdle())); - timer->start(50); - - QList sizes; - sizes << 250; - sizes << 550; - ui->splitter->setSizes(sizes); - - mMaterialModel = new QStringListModel(this); - - mMaterialProxyModel = new QSortFilterProxyModel(this); - mMaterialProxyModel->setSourceModel(mMaterialModel); - mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mMaterialProxyModel->setDynamicSortFilter(true); - mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - - ui->materialList->setModel(mMaterialProxyModel); - ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection); - ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->materialList->setAlternatingRowColors(true); - - connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex))); - - mMaterialPropertyModel = new QStandardItemModel(0, 2, this); - mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onMaterialPropertyChanged(QStandardItem*))); - - mMaterialSortModel = new PropertySortModel(this); - mMaterialSortModel->setSourceModel(mMaterialPropertyModel); - mMaterialSortModel->setDynamicSortFilter(true); - mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive); - - ui->materialView->setModel(mMaterialSortModel); - ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu); - ui->materialView->setAlternatingRowColors(true); - ui->materialView->setSortingEnabled(true); - connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(onContextMenuRequested(QPoint))); - - mGlobalSettingsModel = new QStandardItemModel(0, 2, this); - mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onGlobalSettingChanged(QStandardItem*))); - - ui->globalSettingsView->setModel(mGlobalSettingsModel); - ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); - ui->globalSettingsView->verticalHeader()->hide(); - ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); - ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection); - - ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection); - ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers); - connect(ui->configurationList, SIGNAL(currentTextChanged(QString)), - this, SLOT(onConfigurationSelectionChanged(QString))); - - mConfigurationModel = new QStandardItemModel(0, 2, this); - mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(onConfigurationChanged(QStandardItem*))); - - ui->configurationView->setModel(mConfigurationModel); - ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); - ui->configurationView->verticalHeader()->hide(); - ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); - ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection); -} - -sh::MainWindow::~MainWindow() -{ - delete ui; -} - -void sh::MainWindow::closeEvent(QCloseEvent *event) -{ - this->hide(); - event->ignore(); -} - -void sh::MainWindow::onIdle() -{ - if (mRequestShowWindow) - { - mRequestShowWindow = false; - show(); - } - - if (mRequestExit) - { - QApplication::exit(); - return; - } - - boost::mutex::scoped_lock lock(mSync->mUpdateMutex); - - - mIgnoreMaterialChange = true; - QString selected; - - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - if (selectedIndex.isValid()) - selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString(); - - QStringList list; - - for (std::vector::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it) - { - list.push_back(QString::fromStdString(*it)); - } - - if (mMaterialModel->stringList() != list) - { - mMaterialModel->setStringList(list); - - // quick hack to keep our selection when the model has changed - if (!selected.isEmpty()) - for (int i=0; irowCount(); ++i) - { - const QModelIndex& index = mMaterialModel->index(i,0); - if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected) - { - ui->materialList->setCurrentIndex(index); - break; - } - } - } - mIgnoreMaterialChange = false; - - mIgnoreGlobalSettingChange = true; - for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); - it != mState.mGlobalSettingsMap.end(); ++it) - { - QList list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first)); - if (!list.empty()) // item was already there - { - // if it changed, set the value column - if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString() - != QString::fromStdString(it->second)) - { - mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second))); - } - } - else // item wasn't there; insert new row - { - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - toAdd.push_back(name); - toAdd.push_back(value); - mGlobalSettingsModel->appendRow(toAdd); - } - } - mIgnoreGlobalSettingChange = false; - - - mIgnoreConfigurationChange = true; - QList selected_ = ui->configurationList->selectedItems(); - QString selectedStr; - if (selected_.size()) - selectedStr = selected_.front()->text(); - - ui->configurationList->clear(); - - for (std::vector::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it) - ui->configurationList->addItem(QString::fromStdString(*it)); - - if (!selectedStr.isEmpty()) - for (int i=0; iconfigurationList->count(); ++i) - { - if (ui->configurationList->item(i)->text() == selectedStr) - { - ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect); - } - } - - mIgnoreConfigurationChange = false; - - if (!mState.mErrors.empty()) - { - ui->errorLog->append(QString::fromStdString(mState.mErrors)); - mState.mErrors = ""; - QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link); - ui->tabWidget->tabBar()->setTabTextColor(3, color); - } - - - // process query results - boost::mutex::scoped_lock lock2(mSync->mQueryMutex); - for (std::vector::iterator it = mQueries.begin(); it != mQueries.end();) - { - if ((*it)->mDone) - { - if (typeid(**it) == typeid(ConfigurationQuery)) - buildConfigurationModel(static_cast(*it)); - else if (typeid(**it) == typeid(MaterialQuery)) - buildMaterialModel(static_cast(*it)); - else if (typeid(**it) == typeid(MaterialPropertyQuery)) - { - MaterialPropertyQuery* q = static_cast(*it); - mIgnoreMaterialPropertyChange = true; - if (getSelectedMaterial().toStdString() == q->mName) - { - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName)) - { - mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue)); - if (mMaterialPropertyModel->item(i,1)->isCheckable()) - mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true") - ? Qt::Checked : Qt::Unchecked); - } - } - } - mIgnoreMaterialPropertyChange = false; - } - - delete *it; - it = mQueries.erase(it); - } - else - ++it; - } -} - -void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous) -{ - if (mIgnoreMaterialChange) - return; - - QString name = getSelectedMaterial(); - if (!name.isEmpty()) - requestQuery(new sh::MaterialQuery(name.toStdString())); -} - -QString sh::MainWindow::getSelectedMaterial() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - if (!selectedIndex.isValid()) - return QString(""); - - return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); -} - -void sh::MainWindow::onConfigurationSelectionChanged (const QString& current) -{ - if (mIgnoreConfigurationChange) - return; - requestQuery(new sh::ConfigurationQuery(current.toStdString())); -} - -void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item) -{ - if (mIgnoreGlobalSettingChange) - return; // we are only interested in changes by the user, not by the backend. - - std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString(); - std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString(); - - queueAction(new sh::ActionChangeGlobalSetting(name, value)); -} - -void sh::MainWindow::onConfigurationChanged (QStandardItem* item) -{ - QList items = ui->configurationList->selectedItems(); - if (items.size()) - { - std::string name = items.front()->text().toStdString(); - std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString(); - std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString(); - - queueAction(new sh::ActionChangeConfiguration(name, key, value)); - - requestQuery(new sh::ConfigurationQuery(name)); - } -} - -void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1) -{ - mMaterialProxyModel->setFilterFixedString(arg1); -} - -void sh::MainWindow::on_actionSave_triggered() -{ - queueAction (new sh::ActionSaveAll()); -} - -void sh::MainWindow::on_actionNewMaterial_triggered() -{ - -} - -void sh::MainWindow::on_actionDeleteMaterial_triggered() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); - - queueAction (new sh::ActionDeleteMaterial(name.toStdString())); -} - -void sh::MainWindow::queueAction(Action* action) -{ - boost::mutex::scoped_lock lock(mSync->mActionMutex); - mActionQueue.push(action); -} - -void sh::MainWindow::requestQuery(Query *query) -{ - boost::mutex::scoped_lock lock(mSync->mActionMutex); - mQueries.push_back(query); -} - -void sh::MainWindow::on_actionQuit_triggered() -{ - hide(); -} - -void sh::MainWindow::on_actionNewConfiguration_triggered() -{ - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("New Configuration"), - tr("Configuration name:")); - - if (!text.isEmpty()) - { - queueAction(new ActionCreateConfiguration(text.toStdString())); - } -} - -void sh::MainWindow::on_actionDeleteConfiguration_triggered() -{ - QList items = ui->configurationList->selectedItems(); - if (items.size()) - queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString())); -} - -void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered() -{ - QList items = ui->configurationList->selectedItems(); - if (items.empty()) - return; - std::string configurationName = items.front()->text().toStdString(); - - QModelIndex current = ui->configurationView->currentIndex(); - if (!current.isValid()) - return; - - std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString(); - - queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName)); - requestQuery(new sh::ConfigurationQuery(configurationName)); -} - -void sh::MainWindow::on_actionCloneMaterial_triggered() -{ - QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); - QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); - if (name.isEmpty()) - return; - - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("Clone material"), - tr("Name:")); - - if (!text.isEmpty()) - { - queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString())); - } -} - -void sh::MainWindow::onContextMenuRequested(const QPoint &point) -{ - QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point); - - QMenu menu; - - QList actions; - actions.push_back(ui->actionNewProperty); - actions.push_back(ui->actionDeleteProperty); - actions.push_back(ui->actionCreatePass); - actions.push_back(ui->actionCreateTextureUnit); - menu.addActions(actions); - - menu.exec(globalPos); -} - -void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit) -{ - if (passIndex) - { - *passIndex = 0; - if (isInPass) - *isInPass = false; - QModelIndex passModelIndex = index; - // go up until we find the pass item. - while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid()) - passModelIndex = passModelIndex.parent(); - - if (passModelIndex.isValid()) - { - if (passModelIndex.column() != 0) - passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0); - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) - { - if (mMaterialPropertyModel->index(i, 0) == passModelIndex) - { - if (isInPass) - *isInPass = true; - break; - } - ++(*passIndex); - } - } - } - } - if (textureIndex) - { - *textureIndex = 0; - if (isInTextureUnit) - *isInTextureUnit = false; - QModelIndex texModelIndex = index; - // go up until we find the texture_unit item. - while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid()) - texModelIndex = texModelIndex.parent(); - if (texModelIndex.isValid()) - { - if (texModelIndex.column() != 0) - texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0); - for (int i=0; irowCount(texModelIndex.parent()); ++i) - { - if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit")) - { - if (texModelIndex.parent().child(i, 0) == texModelIndex) - { - if (isInTextureUnit) - *isInTextureUnit = true; - break; - } - ++(*textureIndex); - } - } - } - } -} - -std::string sh::MainWindow::getPropertyKey(QModelIndex index) -{ - if (!index.parent().isValid()) - return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString(); - else - return index.parent().child(index.row(), 0).data().toString().toStdString(); -} - -std::string sh::MainWindow::getPropertyValue(QModelIndex index) -{ - if (!index.parent().isValid()) - return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString(); - else - return index.parent().child(index.row(), 1).data().toString().toStdString(); -} - -void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item) -{ - if (mIgnoreMaterialPropertyChange) - return; - - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - // handle checkboxes being checked/unchecked - std::string value = getPropertyValue(item->index()); - if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean) - { - if (item->checkState() == Qt::Checked && value != "true") - value = "true"; - else if (item->checkState() == Qt::Unchecked && value == "true") - value = "false"; - item->setText(QString::fromStdString(value)); - } - - // handle inherited properties being changed, i.e. overridden by the current (derived) material - if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged) - { - QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText); - mIgnoreMaterialPropertyChange = true; - mMaterialPropertyModel->item(item->index().row(), 0) - ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); - mMaterialPropertyModel->item(item->index().row(), 0) - ->setData(normalColor, Qt::ForegroundRole); - mMaterialPropertyModel->item(item->index().row(), 1) - ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); - mMaterialPropertyModel->item(item->index().row(), 1) - ->setData(normalColor, Qt::ForegroundRole); - mIgnoreMaterialPropertyChange = false; - - ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index())); - } - - if (!item->index().parent().isValid()) - { - // top level material property - queueAction(new ActionSetMaterialProperty( - material.toStdString(), getPropertyKey(item->index()), value)); - } - else if (getPropertyKey(item->index()) == "texture_unit") - { - // texture unit name changed - int passIndex, textureIndex; - getContext(item->index(), &passIndex, &textureIndex); - std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl; - - queueAction(new ActionChangeTextureUnitName( - material.toStdString(), passIndex, textureIndex, value)); - - } - else if (item->index().parent().data().toString() == "pass") - { - // pass property - int passIndex; - getContext(item->index(), &passIndex, NULL); - /// \todo if shaders are changed, check that the material provides all properties needed by the shader - queueAction(new ActionSetPassProperty( - material.toStdString(), passIndex, getPropertyKey(item->index()), value)); - } - else if (item->index().parent().data().toString() == "shader_properties") - { - // shader property - int passIndex; - getContext(item->index(), &passIndex, NULL); - queueAction(new ActionSetShaderProperty( - material.toStdString(), passIndex, getPropertyKey(item->index()), value)); - } - else if (item->index().parent().data().toString() == "texture_unit") - { - // texture property - int passIndex, textureIndex; - getContext(item->index(), &passIndex, &textureIndex); - queueAction(new ActionSetTextureProperty( - material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value)); - } -} - -void sh::MainWindow::buildMaterialModel(MaterialQuery *data) -{ - mMaterialPropertyModel->clear(); - - mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); - mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); - - for (std::map::const_iterator it = data->mProperties.begin(); - it != data->mProperties.end(); ++it) - { - addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second); - } - - for (std::vector::iterator it = data->mPasses.begin(); - it != data->mPasses.end(); ++it) - { - QStandardItem* passItem = new QStandardItem (QString("pass")); - passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable); - passItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - if (it->mShaderProperties.size()) - { - QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties")); - shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable); - shaderPropertiesItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - for (std::map::iterator pit = it->mShaderProperties.begin(); - pit != it->mShaderProperties.end(); ++pit) - { - addProperty(shaderPropertiesItem, pit->first, pit->second); - } - passItem->appendRow(shaderPropertiesItem); - } - - for (std::map::iterator pit = it->mProperties.begin(); - pit != it->mProperties.end(); ++pit) - { - addProperty(passItem, pit->first, pit->second); - } - - for (std::vector::iterator tIt = it->mTextureUnits.begin(); - tIt != it->mTextureUnits.end(); ++tIt) - { - QStandardItem* unitItem = new QStandardItem (QString("texture_unit")); - unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable); - unitItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName)); - nameItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); - - QList texUnit; - texUnit << unitItem << nameItem; - - for (std::map::iterator pit = tIt->mProperties.begin(); - pit != tIt->mProperties.end(); ++pit) - { - addProperty(unitItem, pit->first, pit->second); - } - - passItem->appendRow(texUnit); - } - - QList toAdd; - toAdd << passItem; - toAdd << new QStandardItem(QString("")); - mMaterialPropertyModel->appendRow(toAdd); - } - - ui->materialView->expandAll(); - ui->materialView->resizeColumnToContents(0); - ui->materialView->resizeColumnToContents(1); -} - -void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo) -{ - QList toAdd; - QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key)); - keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); - keyItem->setData(QVariant(value.mType), Qt::UserRole); - keyItem->setData(QVariant(value.mSource), Qt::UserRole+1); - toAdd.push_back(keyItem); - - QStandardItem* valueItem = NULL; - if (value.mSource != MaterialProperty::None) - { - valueItem = new QStandardItem(QString::fromStdString(value.mValue)); - valueItem->setData(QVariant(value.mType), Qt::UserRole); - valueItem->setData(QVariant(value.mSource), Qt::UserRole+1); - toAdd.push_back(valueItem); - } - - - if (value.mSource == MaterialProperty::Inherited_Unchanged) - { - QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); - keyItem->setData(color, Qt::ForegroundRole); - if (valueItem) - valueItem->setData(color, Qt::ForegroundRole); - } - if (value.mType == MaterialProperty::Boolean && valueItem) - { - valueItem->setCheckable(true); - valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked); - } - - parent->appendRow(toAdd); - - if (scrollTo) - ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index())); -} - -void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data) -{ - while (mConfigurationModel->rowCount()) - mConfigurationModel->removeRow(0); - for (std::map::iterator it = data->mProperties.begin(); - it != data->mProperties.end(); ++it) - { - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - toAdd.push_back(name); - toAdd.push_back(value); - mConfigurationModel->appendRow(toAdd); - } - - // add items that are in global settings, but not in this configuration (with a "inactive" color) - for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); - it != mState.mGlobalSettingsMap.end(); ++it) - { - if (data->mProperties.find(it->first) == data->mProperties.end()) - { - QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); - QList toAdd; - QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); - name->setFlags(name->flags() &= ~Qt::ItemIsEditable); - name->setData(color, Qt::ForegroundRole); - QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); - value->setData(color, Qt::ForegroundRole); - toAdd.push_back(name); - toAdd.push_back(value); - mConfigurationModel->appendRow(toAdd); - } - } -} - -void sh::MainWindow::on_actionCreatePass_triggered() -{ - QString material = getSelectedMaterial(); - if (!material.isEmpty()) - { - addProperty(mMaterialPropertyModel->invisibleRootItem(), - "pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true); - - queueAction (new ActionCreatePass(material.toStdString())); - } -} - -void sh::MainWindow::on_actionDeleteProperty_triggered() -{ - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - mIgnoreMaterialPropertyChange = true; - - if (getPropertyKey(selectedIndex) == "pass") - { - // delete whole pass - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - if (passIndex == 0) - { - QMessageBox msgBox; - msgBox.setText("The first pass can not be deleted."); - msgBox.exec(); - } - else - { - queueAction(new ActionDeletePass(material.toStdString(), passIndex)); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - } - else if (getPropertyKey(selectedIndex) == "texture_unit") - { - // delete whole texture unit - int passIndex, textureIndex; - getContext(selectedIndex, &passIndex, &textureIndex); - queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex)); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (!selectedIndex.parent().isValid()) - { - // top level material property - MaterialProperty::Source source = static_cast( - mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt()); - if (source == MaterialProperty::Inherited_Unchanged) - { - QMessageBox msgBox; - msgBox.setText("Inherited properties can not be deleted."); - msgBox.exec(); - } - else - { - queueAction(new ActionDeleteMaterialProperty( - material.toStdString(), getPropertyKey(selectedIndex))); - std::cout << "source is " << source << std::endl; - if (source == MaterialProperty::Inherited_Changed) - { - QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText); - mMaterialPropertyModel->item(selectedIndex.row(), 0) - ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); - mMaterialPropertyModel->item(selectedIndex.row(), 0) - ->setData(inactiveColor, Qt::ForegroundRole); - mMaterialPropertyModel->item(selectedIndex.row(), 1) - ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); - mMaterialPropertyModel->item(selectedIndex.row(), 1) - ->setData(inactiveColor, Qt::ForegroundRole); - - // make sure to update the property's value - requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex))); - } - else - mMaterialPropertyModel->removeRow(selectedIndex.row()); - } - } - else if (selectedIndex.parent().data().toString() == "pass") - { - // pass property - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionDeletePassProperty( - material.toStdString(), passIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (selectedIndex.parent().data().toString() == "shader_properties") - { - // shader property - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionDeleteShaderProperty( - material.toStdString(), passIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - else if (selectedIndex.parent().data().toString() == "texture_unit") - { - // texture property - int passIndex, textureIndex; - getContext(selectedIndex, &passIndex, &textureIndex); - queueAction(new ActionDeleteTextureProperty( - material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex))); - mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); - } - mIgnoreMaterialPropertyChange = false; -} - -void sh::MainWindow::on_actionNewProperty_triggered() -{ - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - AddPropertyDialog* dialog = new AddPropertyDialog(this); - dialog->exec(); - QString propertyName = dialog->mName; - QString defaultValue = ""; - - /// \todo check if this property name exists already - - if (!propertyName.isEmpty()) - { - int passIndex, textureIndex; - bool isInPass, isInTextureUnit; - getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit); - - QList items; - QStandardItem* keyItem = new QStandardItem(propertyName); - keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); - items << keyItem; - items << new QStandardItem(defaultValue); - - // figure out which item the new property should be a child of - QModelIndex parentIndex = selectedIndex; - if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object) - parentIndex = selectedIndex.parent(); - QStandardItem* parentItem; - if (!parentIndex.isValid()) - parentItem = mMaterialPropertyModel->invisibleRootItem(); - else - parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex); - - if (isInTextureUnit) - { - queueAction(new ActionSetTextureProperty( - material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - else if (isInPass) - { - if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties" - || selectedIndex.parent().data().toString() == "shader_properties") - { - queueAction(new ActionSetShaderProperty( - material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - else - { - queueAction(new ActionSetPassProperty( - material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); - } - } - else - { - queueAction(new ActionSetMaterialProperty( - material.toStdString(), propertyName.toStdString(), defaultValue.toStdString())); - } - - addProperty(parentItem, propertyName.toStdString(), - MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true); - - /// \todo scroll to newly added property - } -} - -void sh::MainWindow::on_actionCreateTextureUnit_triggered() -{ - QString material = getSelectedMaterial(); - if (material.isEmpty()) - return; - - QInputDialog dialog(this); - - QString text = QInputDialog::getText(this, tr("New texture unit"), - tr("Texture unit name (for referencing in shaders):")); - if (!text.isEmpty()) - { - QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); - int passIndex; - getContext(selectedIndex, &passIndex, NULL); - queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString())); - - // add to model - int index = 0; - for (int i=0; irowCount(); ++i) - { - if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) - { - if (index == passIndex) - { - addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)), - "texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true); - break; - } - - ++index; - } - } - } -} - -void sh::MainWindow::on_clearButton_clicked() -{ - ui->errorLog->clear(); -} - -void sh::MainWindow::on_tabWidget_currentChanged(int index) -{ - QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText); - - if (index == 3) - ui->tabWidget->tabBar()->setTabTextColor(3, color); -} diff --git a/extern/shiny/Editor/MainWindow.hpp b/extern/shiny/Editor/MainWindow.hpp deleted file mode 100644 index 3f0dc295c0..0000000000 --- a/extern/shiny/Editor/MainWindow.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef SHINY_EDITOR_MAINWINDOW_HPP -#define SHINY_EDITOR_MAINWINDOW_HPP - -#include - -#include -#include -#include - -#include - -#include "Actions.hpp" -#include "Query.hpp" - -#include "PropertySortModel.hpp" - -namespace Ui { -class MainWindow; -} - -namespace sh -{ - -struct SynchronizationState; - - -/** - * @brief A snapshot of the material system's state. Lock the mUpdateMutex before accessing. - */ -struct MaterialSystemState -{ - std::vector mMaterialList; - - std::map mGlobalSettingsMap; - - std::vector mConfigurationList; - - std::vector mMaterialFiles; - std::vector mConfigurationFiles; - - std::vector mShaderSets; - - std::string mErrors; -}; - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - - // really should be an std::atomic - volatile bool mRequestShowWindow; - // dito - volatile bool mRequestExit; - - SynchronizationState* mSync; - - /// \todo Is there a better way to ignore manual model changes? - bool mIgnoreGlobalSettingChange; - bool mIgnoreConfigurationChange; - bool mIgnoreMaterialChange; - bool mIgnoreMaterialPropertyChange; - - std::queue mActionQueue; - std::vector mQueries; - - MaterialSystemState mState; - -private: - Ui::MainWindow *ui; - - // material tab - QStringListModel* mMaterialModel; - QSortFilterProxyModel* mMaterialProxyModel; - - QStandardItemModel* mMaterialPropertyModel; - PropertySortModel* mMaterialSortModel; - - // global settings tab - QStandardItemModel* mGlobalSettingsModel; - - // configuration tab - QStandardItemModel* mConfigurationModel; - - void queueAction(Action* action); - void requestQuery(Query* query); - - void buildMaterialModel (MaterialQuery* data); - void buildConfigurationModel (ConfigurationQuery* data); - - QString getSelectedMaterial(); - - /// get the context of an index in the material property model - void getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass=NULL, bool* isInTextureUnit=NULL); - - std::string getPropertyKey(QModelIndex index); - std::string getPropertyValue(QModelIndex index); - - void addProperty (QStandardItem* parent, const std::string& key, MaterialProperty value, bool scrollTo=false); - -protected: - void closeEvent(QCloseEvent *event); - -public slots: - void onIdle(); - - void onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous); - void onConfigurationSelectionChanged (const QString& current); - - void onGlobalSettingChanged (QStandardItem* item); - void onConfigurationChanged (QStandardItem* item); - void onMaterialPropertyChanged (QStandardItem* item); - - void onContextMenuRequested(const QPoint& point); - -private slots: - void on_lineEdit_textEdited(const QString &arg1); - void on_actionSave_triggered(); - void on_actionNewMaterial_triggered(); - void on_actionDeleteMaterial_triggered(); - void on_actionQuit_triggered(); - void on_actionNewConfiguration_triggered(); - void on_actionDeleteConfiguration_triggered(); - void on_actionDeleteConfigurationProperty_triggered(); - void on_actionCloneMaterial_triggered(); - void on_actionCreatePass_triggered(); - void on_actionDeleteProperty_triggered(); - void on_actionNewProperty_triggered(); - void on_actionCreateTextureUnit_triggered(); - void on_clearButton_clicked(); - void on_tabWidget_currentChanged(int index); -}; - -} - -#endif // MAINWINDOW_HPP diff --git a/extern/shiny/Editor/NewMaterialDialog.cpp b/extern/shiny/Editor/NewMaterialDialog.cpp deleted file mode 100644 index f1a716a9f0..0000000000 --- a/extern/shiny/Editor/NewMaterialDialog.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "NewMaterialDialog.hpp" -#include "ui_newmaterialdialog.h" - -NewMaterialDialog::NewMaterialDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::NewMaterialDialog) -{ - ui->setupUi(this); -} - -NewMaterialDialog::~NewMaterialDialog() -{ - delete ui; -} diff --git a/extern/shiny/Editor/NewMaterialDialog.hpp b/extern/shiny/Editor/NewMaterialDialog.hpp deleted file mode 100644 index 2a20bbb395..0000000000 --- a/extern/shiny/Editor/NewMaterialDialog.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NEWMATERIALDIALOG_HPP -#define NEWMATERIALDIALOG_HPP - -#include - -namespace Ui { -class NewMaterialDialog; -} - -class NewMaterialDialog : public QDialog -{ - Q_OBJECT - -public: - explicit NewMaterialDialog(QWidget *parent = 0); - ~NewMaterialDialog(); - -private: - Ui::NewMaterialDialog *ui; -}; - -#endif // NEWMATERIALDIALOG_HPP diff --git a/extern/shiny/Editor/PropertySortModel.cpp b/extern/shiny/Editor/PropertySortModel.cpp deleted file mode 100644 index 637fe11b02..0000000000 --- a/extern/shiny/Editor/PropertySortModel.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "PropertySortModel.hpp" - -#include "Query.hpp" - -#include -sh::PropertySortModel::PropertySortModel(QObject *parent) - : QSortFilterProxyModel(parent) -{ -} - -bool sh::PropertySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - if (left.data(Qt::UserRole+1).toInt() != 0 && right.data(Qt::UserRole+1).toInt() != 0) - { - int sourceL = left.data(Qt::UserRole+1).toInt(); - int sourceR = right.data(Qt::UserRole+1).toInt(); - - if (sourceL > sourceR) - return true; - else if (sourceR > sourceL) - return false; - } - - int typeL = left.data(Qt::UserRole).toInt(); - int typeR = right.data(Qt::UserRole).toInt(); - - if (typeL > typeR) - return true; - else if (typeR > typeL) - return false; - - QString nameL = left.data().toString(); - QString nameR = right.data().toString(); - return nameL > nameR; -} diff --git a/extern/shiny/Editor/PropertySortModel.hpp b/extern/shiny/Editor/PropertySortModel.hpp deleted file mode 100644 index f96927764e..0000000000 --- a/extern/shiny/Editor/PropertySortModel.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SHINY_EDITOR_PROPERTYSORTMODEL_H -#define SHINY_EDITOR_PROPERTYSORTMODEL_H - -#include - -namespace sh -{ - - class PropertySortModel : public QSortFilterProxyModel - { - Q_OBJECT - - public: - PropertySortModel(QObject* parent); - protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - }; - -} - -#endif diff --git a/extern/shiny/Editor/Query.cpp b/extern/shiny/Editor/Query.cpp deleted file mode 100644 index ccf07b62bc..0000000000 --- a/extern/shiny/Editor/Query.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "Query.hpp" - -#include "../Main/Factory.hpp" - -namespace sh -{ - -void Query::execute() -{ - executeImpl(); - mDone = true; -} - -ConfigurationQuery::ConfigurationQuery(const std::string &name) - : mName(name) -{ -} - -void ConfigurationQuery::executeImpl() -{ - sh::Factory::getInstance().listConfigurationSettings(mName, mProperties); -} - -void MaterialQuery::executeImpl() -{ - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(mName); - - if (instance->getParent()) - mParent = static_cast(instance->getParent())->getName(); - - // add the inherited properties - sh::PropertySetGet* parent = instance; - std::vector inheritedPropertiesVector; - while (parent->getParent()) - { - parent = parent->getParent(); - const sh::PropertyMap& parentProperties = parent->listProperties(); - - for (PropertyMap::const_iterator it = parentProperties.begin(); it != parentProperties.end(); ++it) - { - MaterialProperty::Source source = MaterialProperty::Inherited_Unchanged; - MaterialProperty::Type type = getType(it->first, parent->getProperty(it->first)); - mProperties[it->first] = MaterialProperty ( - retrieveValue(parent->getProperty(it->first), NULL).get(), - type, source); - inheritedPropertiesVector.push_back(it->first); - } - } - - // add our properties - const sh::PropertyMap& ourProperties = instance->listProperties(); - for (PropertyMap::const_iterator it = ourProperties.begin(); it != ourProperties.end(); ++it) - { - MaterialProperty::Source source = - (std::find(inheritedPropertiesVector.begin(), inheritedPropertiesVector.end(), it->first) - != inheritedPropertiesVector.end()) ? - MaterialProperty::Inherited_Changed : MaterialProperty::Normal; - MaterialProperty::Type type = getType(it->first, instance->getProperty(it->first)); - mProperties[it->first] = MaterialProperty ( - retrieveValue(instance->getProperty(it->first), NULL).get(), - type, source); - } - - std::vector* passes = instance->getPasses(); - for (std::vector::iterator it = passes->begin(); it != passes->end(); ++it) - { - mPasses.push_back(PassInfo()); - - const sh::PropertyMap& passProperties = it->listProperties(); - for (PropertyMap::const_iterator pit = passProperties.begin(); pit != passProperties.end(); ++pit) - { - PropertyValuePtr property = it->getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); - else - mPasses.back().mProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - - const sh::PropertyMap& shaderProperties = it->mShaderProperties.listProperties(); - for (PropertyMap::const_iterator pit = shaderProperties.begin(); pit != shaderProperties.end(); ++pit) - { - PropertyValuePtr property = it->mShaderProperties.getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mShaderProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); - else - mPasses.back().mShaderProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - - std::vector* texUnits = &it->mTexUnits; - for (std::vector::iterator tIt = texUnits->begin(); tIt != texUnits->end(); ++tIt) - { - mPasses.back().mTextureUnits.push_back(TextureUnitInfo()); - mPasses.back().mTextureUnits.back().mName = tIt->getName(); - const sh::PropertyMap& unitProperties = tIt->listProperties(); - for (PropertyMap::const_iterator pit = unitProperties.begin(); pit != unitProperties.end(); ++pit) - { - PropertyValuePtr property = tIt->getProperty(pit->first); - MaterialProperty::Type type = getType(pit->first, property); - if (typeid(*property).name() == typeid(sh::LinkedValue).name()) - mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( - "$" + property->_getStringValue(), MaterialProperty::Linked); - else - mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( - retrieveValue(property, NULL).get(), type); - } - } - } -} - -MaterialProperty::Type MaterialQuery::getType(const std::string &key, PropertyValuePtr value) -{ - if (typeid(*value).name() == typeid(sh::LinkedValue).name()) - return MaterialProperty::Linked; - - if (key == "vertex_program" || key == "fragment_program") - return MaterialProperty::Shader; - - std::string valueStr = retrieveValue(value, NULL).get(); - - if (valueStr == "false" || valueStr == "true") - return MaterialProperty::Boolean; -} - -void MaterialPropertyQuery::executeImpl() -{ - sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); - mValue = retrieveValue(m->getProperty(mPropertyName), m).get(); -} - -} diff --git a/extern/shiny/Editor/Query.hpp b/extern/shiny/Editor/Query.hpp deleted file mode 100644 index d98c8c9b27..0000000000 --- a/extern/shiny/Editor/Query.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef SH_QUERY_H -#define SH_QUERY_H - -#include -#include -#include - -#include "../Main/PropertyBase.hpp" - -namespace sh -{ - -class Query -{ -public: - Query() - : mDone(false) {} - virtual ~Query() {} - - void execute(); - - bool mDone; - -protected: - virtual void executeImpl() = 0; -}; - -class ConfigurationQuery : public Query -{ -public: - ConfigurationQuery(const std::string& name); - - std::map mProperties; -protected: - std::string mName; - virtual void executeImpl(); -}; - - -struct MaterialProperty -{ - - enum Type - { - Texture, - Color, - Boolean, - Shader, - Misc, - Linked, - Object // child object, i.e. pass, texture unit, shader properties - }; - - enum Source - { - Normal, - Inherited_Changed, - Inherited_Unchanged, - None // there is no property source (e.g. a pass, which does not have a name) - }; - - MaterialProperty() {} - MaterialProperty (const std::string& value, Type type, Source source=Normal) - : mValue(value), mType(type), mSource(source) {} - - std::string mValue; - Type mType; - Source mSource; -}; - - -struct TextureUnitInfo -{ - std::string mName; - std::map mProperties; -}; - -struct PassInfo -{ - std::map mShaderProperties; - - std::map mProperties; - std::vector mTextureUnits; -}; - -class MaterialQuery : public Query -{ -public: - MaterialQuery(const std::string& name) - : mName(name) {} - - std::string mParent; - std::vector mPasses; - std::map mProperties; - -protected: - std::string mName; - virtual void executeImpl(); - - MaterialProperty::Type getType (const std::string& key, PropertyValuePtr value); -}; - -class MaterialPropertyQuery : public Query -{ -public: - MaterialPropertyQuery(const std::string& name, const std::string& propertyName) - : mName(name), mPropertyName(propertyName) - { - } - - std::string mValue; - - std::string mName; - std::string mPropertyName; -protected: - virtual void executeImpl(); -}; - -} - -#endif diff --git a/extern/shiny/Editor/addpropertydialog.ui b/extern/shiny/Editor/addpropertydialog.ui deleted file mode 100644 index 63de7d1415..0000000000 --- a/extern/shiny/Editor/addpropertydialog.ui +++ /dev/null @@ -1,118 +0,0 @@ - - - AddPropertyDialog - - - - 0 - 0 - 257 - 133 - - - - Dialog - - - - - - - - - - - - - Property name - - - - - - - Editing widget - - - - - - - - Checkbox - - - - - Shader - - - - - Color - - - - - Texture - - - - - Other - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - AddPropertyDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - AddPropertyDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/extern/shiny/Editor/mainwindow.ui b/extern/shiny/Editor/mainwindow.ui deleted file mode 100644 index b27c8357de..0000000000 --- a/extern/shiny/Editor/mainwindow.ui +++ /dev/null @@ -1,420 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 647 - 512 - - - - MainWindow - - - - - - - 0 - - - - - - - Materials - - - - - - Qt::Horizontal - - - - - - - - - - Search - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 16 - 16 - - - - - - - - - - - - - - - - 1 - 0 - - - - - - - - - 1 - 0 - - - - - 16 - 16 - - - - Qt::ToolButtonIconOnly - - - - - - - - - - - - - - Global settings - - - - - - - - - - Configurations - - - - - - Qt::Horizontal - - - - - - - - - - - 16 - 16 - - - - - - - - - - - - - - - - - - 16 - 16 - - - - - - - - - - - - - - Errors - - - - - - - - true - - - - - - - - 0 - 0 - - - - Clear - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 647 - 25 - - - - false - - - - File - - - - - - - Material - - - - - - - - - History - - - - - - - - - - - - - - Quit - - - - - - - - - - Save - - - Save all - - - - - - - - - - Delete - - - Delete selected material - - - - - Change parent... - - - - - - - - - - New - - - Create a new material - - - - - - - - - - Clone - - - Clone selected material - - - - - - - - - - Delete - - - Delete selected configuration - - - Del - - - - - - - - - - New - - - Create a new configuration - - - - - - - - - - Delete - - - Delete property - - - - - - - - - - Delete - - - Delete item - - - - - - - - - - New property - - - - - - - - - - Create pass - - - - - - - - - - Create texture unit - - - - - - sh::ColoredTabWidget - QTabWidget -

ColoredTabWidget.hpp
- 1 - - - - - diff --git a/extern/shiny/Editor/newmaterialdialog.ui b/extern/shiny/Editor/newmaterialdialog.ui deleted file mode 100644 index f24561cf79..0000000000 --- a/extern/shiny/Editor/newmaterialdialog.ui +++ /dev/null @@ -1,98 +0,0 @@ - - - NewMaterialDialog - - - - 0 - 0 - 385 - 198 - - - - Dialog - - - - - - - - Name - - - - - - - Parent material - - - - - - - - - - - - - File - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - NewMaterialDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - NewMaterialDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/extern/shiny/Extra/core.h b/extern/shiny/Extra/core.h deleted file mode 100644 index 1687d5ed11..0000000000 --- a/extern/shiny/Extra/core.h +++ /dev/null @@ -1,174 +0,0 @@ -#if SH_HLSL == 1 || SH_CG == 1 - - #define shTexture2D sampler2D - #define shTexture3D sampler3D - #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 shSampler3D(name) , uniform sampler3D 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 shTexture3D sampler3D - #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 shSampler3D(name) uniform sampler3D 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/extern/shiny/License.txt b/extern/shiny/License.txt deleted file mode 100644 index d89bcf3ad2..0000000000 --- a/extern/shiny/License.txt +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2012 - -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. - - diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp deleted file mode 100644 index d7c4234cb7..0000000000 --- a/extern/shiny/Main/Factory.cpp +++ /dev/null @@ -1,817 +0,0 @@ -#include "Factory.hpp" - -#include -#include - -#include -#include -#include - -#include "Platform.hpp" -#include "ScriptLoader.hpp" -#include "ShaderSet.hpp" -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - Factory* Factory::sThis = 0; - const std::string Factory::mBinaryCacheName = "binaryCache"; - - Factory& Factory::getInstance() - { - assert (sThis); - return *sThis; - } - - Factory* Factory::getInstancePtr() - { - return sThis; - } - - Factory::Factory (Platform* platform) - : mPlatform(platform) - , mShadersEnabled(true) - , mShaderDebugOutputEnabled(false) - , mCurrentLanguage(Language_None) - , mListener(NULL) - , mCurrentConfiguration(NULL) - , mCurrentLodConfiguration(NULL) - , mReadMicrocodeCache(false) - , mWriteMicrocodeCache(false) - , mReadSourceCache(false) - , mWriteSourceCache(false) - { - assert (!sThis); - sThis = this; - - mPlatform->setFactory(this); - } - - void Factory::loadAllFiles() - { - assert(mCurrentLanguage != Language_None); - - try - { - if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) - { - std::ifstream file; - file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - - std::string line; - while (getline(file, line)) - { - std::string sourceFile = line; - - if (!getline(file, line)) - assert(0); - - int modified = boost::lexical_cast(line); - - mShadersLastModified[sourceFile] = modified; - } - } - } - catch (std::exception& e) - { - std::cerr << "Failed to load shader modification index: " << e.what() << std::endl; - mShadersLastModified.clear(); - } - - // load configurations - { - ScriptLoader shaderSetLoader(".configuration"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "configuration")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl; - break; - } - - Configuration newConfiguration; - newConfiguration.setParent(&mGlobalSettings); - newConfiguration.setSourceFile (it->second->mFileName); - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - std::string val = (*propIt)->getValue(); - - newConfiguration.setProperty (name, makeProperty(val)); - } - - mConfigurations[it->first] = newConfiguration; - } - } - - // load lod configurations - { - ScriptLoader lodLoader(".lod"); - ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath()); - std::map nodes = lodLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "lod_configuration")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl; - break; - } - - if (it->first == "0") - { - throw std::runtime_error("lod level 0 (max lod) can't have a configuration"); - } - - PropertySetGet newLod; - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - std::string val = (*propIt)->getValue(); - - newLod.setProperty (name, makeProperty(val)); - } - - mLodConfigurations[boost::lexical_cast(it->first)] = newLod; - } - } - - // load shader sets - bool removeBinaryCache = reloadShaders(); - - // load materials - { - ScriptLoader materialLoader(".mat"); - ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath()); - - std::map nodes = materialLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "material")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl; - break; - } - - MaterialInstance newInstance(it->first, this); - newInstance.create(mPlatform); - if (!mShadersEnabled) - newInstance.setShadersEnabled (false); - - newInstance.setSourceFile (it->second->mFileName); - - std::vector props = it->second->getChildren(); - for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) - { - std::string name = (*propIt)->getName(); - - std::string val = (*propIt)->getValue(); - - if (name == "pass") - { - MaterialInstancePass* newPass = newInstance.createPass(); - std::vector props2 = (*propIt)->getChildren(); - for (std::vector::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2) - { - std::string name2 = (*propIt2)->getName(); - std::string val2 = (*propIt2)->getValue(); - - if (name2 == "shader_properties") - { - std::vector shaderProps = (*propIt2)->getChildren(); - for (std::vector::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt) - { - std::string val = (*shaderPropIt)->getValue(); - newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val)); - } - } - else if (name2 == "texture_unit") - { - MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2); - std::vector texProps = (*propIt2)->getChildren(); - for (std::vector::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt) - { - std::string val = (*texPropIt)->getValue(); - newTex->setProperty((*texPropIt)->getName(), makeProperty(val)); - } - } - else - newPass->setProperty((*propIt2)->getName(), makeProperty(val2)); - } - } - else if (name == "parent") - newInstance.setParentInstance(val); - else - newInstance.setProperty((*propIt)->getName(), makeProperty(val)); - } - - if (newInstance.hasProperty("create_configuration")) - { - std::string config = retrieveValue(newInstance.getProperty("create_configuration"), NULL).get(); - newInstance.createForConfiguration (config, 0); - } - - mMaterials.insert (std::make_pair(it->first, newInstance)); - } - - // now that all materials are loaded, replace the parent names with the actual pointers to parent - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - std::string parent = it->second.getParentInstance(); - if (parent != "") - { - if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end()) - throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\""); - it->second.setParent(&mMaterials.find(parent)->second); - } - } - } - - if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) - { - std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; - if (boost::filesystem::exists(file)) - { - mPlatform->deserializeShaders (file); - } - } - } - - Factory::~Factory () - { - mShaderSets.clear(); - - if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) - { - std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; - mPlatform->serializeShaders (file); - } - - if (mReadSourceCache) - { - // save the last modified time of shader sources (as of when they were loaded) - std::ofstream file; - file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - - for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it) - { - file << it->first << "\n" << it->second << std::endl; - } - - file.close(); - } - - delete mPlatform; - sThis = 0; - } - - MaterialInstance* Factory::searchInstance (const std::string& name) - { - MaterialMap::iterator it = mMaterials.find(name); - if (it != mMaterials.end()) - return &(it->second); - else - return NULL; - } - - MaterialInstance* Factory::findInstance (const std::string& name) - { - MaterialInstance* m = searchInstance(name); - assert (m); - return m; - } - - MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex) - { - MaterialInstance* m = searchInstance (name); - - if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end()) - return NULL; - - if (m) - { - if (m->createForConfiguration (configuration, 0)) - { - if (mListener) - mListener->materialCreated (m, configuration, 0); - } - else - return NULL; - - for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it) - { - if (m->createForConfiguration (configuration, it->first)) - { - if (mListener) - mListener->materialCreated (m, configuration, it->first); - } - else - return NULL; - } - } - return m; - } - - MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance) - { - if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end()) - throw std::runtime_error ("trying to clone material that does not exist"); - - MaterialInstance newInstance(name, this); - - if (!mShadersEnabled) - newInstance.setShadersEnabled(false); - - if (parentInstance != "") - newInstance.setParent (&mMaterials.find(parentInstance)->second); - - newInstance.create(mPlatform); - - mMaterials.insert (std::make_pair(name, newInstance)); - - return &mMaterials.find(name)->second; - } - - void Factory::destroyMaterialInstance (const std::string& name) - { - if (mMaterials.find(name) != mMaterials.end()) - mMaterials.erase(name); - } - - void Factory::setShadersEnabled (bool enabled) - { - mShadersEnabled = enabled; - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.setShadersEnabled(enabled); - } - } - - void Factory::setGlobalSetting (const std::string& name, const std::string& value) - { - bool changed = true; - if (mGlobalSettings.hasProperty(name)) - changed = (retrieveValue(mGlobalSettings.getProperty(name), NULL).get() != value); - - mGlobalSettings.setProperty (name, makeProperty(new StringValue(value))); - - if (changed) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - } - - void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value) - { - mPlatform->setSharedParameter(name, value); - } - - ShaderSet* Factory::getShaderSet (const std::string& name) - { - if (mShaderSets.find(name) == mShaderSets.end()) - { - std::stringstream msg; - msg << "Shader '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return &mShaderSets.find(name)->second; - } - - Platform* Factory::getPlatform () - { - return mPlatform; - } - - Language Factory::getCurrentLanguage () - { - return mCurrentLanguage; - } - - void Factory::setCurrentLanguage (Language lang) - { - bool changed = (mCurrentLanguage != lang); - mCurrentLanguage = lang; - - if (changed) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - } - - void Factory::notifyConfigurationChanged() - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - it->second.destroyAll(); - } - } - - MaterialInstance* Factory::getMaterialInstance (const std::string& name) - { - return findInstance(name); - } - - void Factory::setTextureAlias (const std::string& alias, const std::string& realName) - { - mTextureAliases[alias] = realName; - - // update the already existing texture units - for (std::map::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it) - { - if (it->second == alias) - { - it->first->setTextureName(realName); - } - } - } - - std::string Factory::retrieveTextureAlias (const std::string& name) - { - TextureAliasMap::iterator it = mTextureAliases.find(name); - if (it != mTextureAliases.end()) - return it->second; - else - return ""; - } - - Configuration* Factory::getConfiguration (const std::string& name) - { - return &mConfigurations[name]; - } - - void Factory::createConfiguration (const std::string& name) - { - mConfigurations[name].setParent (&mGlobalSettings); - } - - void Factory::destroyConfiguration(const std::string &name) - { - mConfigurations.erase(name); - } - - void Factory::registerLodConfiguration (int index, PropertySetGet configuration) - { - mLodConfigurations[index] = configuration; - } - - void Factory::setMaterialListener (MaterialListener* listener) - { - mListener = listener; - } - - void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t) - { - mTextureAliasInstances[t] = name; - } - - void Factory::removeTextureAliasInstances (TextureUnitState* t) - { - mTextureAliasInstances.erase(t); - } - - void Factory::setActiveConfiguration (const std::string& configuration) - { - if (configuration == "Default") - mCurrentConfiguration = 0; - else - { - assert (mConfigurations.find(configuration) != mConfigurations.end()); - mCurrentConfiguration = &mConfigurations[configuration]; - } - } - - void Factory::setActiveLodLevel (int level) - { - if (level == 0) - mCurrentLodConfiguration = 0; - else - { - assert (mLodConfigurations.find(level) != mLodConfigurations.end()); - mCurrentLodConfiguration = &mLodConfigurations[level]; - } - } - - void Factory::setShaderDebugOutputEnabled (bool enabled) - { - mShaderDebugOutputEnabled = enabled; - } - - PropertySetGet* Factory::getCurrentGlobalSettings() - { - PropertySetGet* p = &mGlobalSettings; - - // current global settings are affected by active configuration & active lod configuration - - if (mCurrentConfiguration) - { - p = mCurrentConfiguration; - } - - if (mCurrentLodConfiguration) - { - mCurrentLodConfiguration->setParent(p); - p = mCurrentLodConfiguration; - } - - return p; - } - - void Factory::saveAll () - { - std::map files; - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - if (it->second.getSourceFile().empty()) - continue; - if (files.find(it->second.getSourceFile()) == files.end()) - { - /// \todo check if this is actually the same file, since there can be different paths to the same file - std::ofstream* stream = new std::ofstream(); - stream->open (it->second.getSourceFile().c_str()); - - files[it->second.getSourceFile()] = stream; - } - it->second.save (*files[it->second.getSourceFile()]); - } - - for (std::map::iterator it = files.begin(); it != files.end(); ++it) - { - delete it->second; - } - files.clear(); - - for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) - { - if (it->second.getSourceFile().empty()) - continue; - if (files.find(it->second.getSourceFile()) == files.end()) - { - /// \todo check if this is actually the same file, since there can be different paths to the same file - std::ofstream* stream = new std::ofstream(); - stream->open (it->second.getSourceFile().c_str()); - - files[it->second.getSourceFile()] = stream; - } - it->second.save (it->first, *files[it->second.getSourceFile()]); - } - - for (std::map::iterator it = files.begin(); it != files.end(); ++it) - { - delete it->second; - } - } - - void Factory::listMaterials(std::vector &out) - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::listGlobalSettings(std::map &out) - { - const PropertyMap& properties = mGlobalSettings.listProperties(); - - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - out[it->first] = retrieveValue(mGlobalSettings.getProperty(it->first), NULL).get(); - } - } - - void Factory::listConfigurationSettings(const std::string& name, std::map &out) - { - const PropertyMap& properties = mConfigurations[name].listProperties(); - - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - out[it->first] = retrieveValue(mConfigurations[name].getProperty(it->first), NULL).get(); - } - } - - void Factory::listConfigurationNames(std::vector &out) - { - for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::listShaderSets(std::vector &out) - { - for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it) - { - out.push_back(it->first); - } - } - - void Factory::_ensureMaterial(const std::string& name, const std::string& configuration) - { - MaterialInstance* m = searchInstance (name); - assert(m); - - m->createForConfiguration (configuration, 0); - - for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it) - { - m->createForConfiguration (configuration, it->first); - } - } - - bool Factory::removeCache(const std::string& pattern) - { - bool ret = false; - if ( boost::filesystem::exists(mPlatform->getCacheFolder()) - && boost::filesystem::is_directory(mPlatform->getCacheFolder())) - { - boost::filesystem::directory_iterator end_iter; - for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) - { - if (boost::filesystem::is_regular_file(dir_iter->status()) ) - { - boost::filesystem::path file = dir_iter->path(); - - std::string pathname = file.filename().string(); - - // get first part of filename, e.g. main_fragment_546457654 -> main_fragment - // there is probably a better method for this... - std::vector tokens; - boost::split(tokens, pathname, boost::is_any_of("_")); - tokens.erase(--tokens.end()); - std::string shaderName; - for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) - { - shaderName += *(vector_iter++); - if (vector_iter != tokens.end()) - shaderName += "_"; - } - - if (shaderName == pattern) - { - boost::filesystem::remove(file); - ret = true; - std::cout << "Removing outdated shader: " << file << std::endl; - } - } - } - } - return ret; - } - - bool Factory::reloadShaders() - { - mShaderSets.clear(); - notifyConfigurationChanged(); - - bool removeBinaryCache = false; - ScriptLoader shaderSetLoader(".shaderset"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "shader_set")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; - break; - } - - if (!it->second->findChild("profiles_cg")) - throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); - if (!it->second->findChild("profiles_hlsl")) - throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); - if (!it->second->findChild("source")) - throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); - if (!it->second->findChild("type")) - throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); - - std::vector profiles_cg; - boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); - std::string cg_profile; - for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - cg_profile = *it2; - break; - } - } - - std::vector profiles_hlsl; - boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); - std::string hlsl_profile; - for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - hlsl_profile = *it2; - break; - } - } - - std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); - std::string sourceRelative = it->second->findChild("source")->getValue(); - - ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, - sourceAbsolute, - mPlatform->getBasePath(), - it->first, - &mGlobalSettings); - - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); - mShadersLastModifiedNew[sourceRelative] = lastModified; - if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) - { - if (mShadersLastModified[sourceRelative] != lastModified) - { - // delete any outdated shaders based on this shader set - if (removeCache (it->first)) - removeBinaryCache = true; - } - } - else - { - // if we get here, this is either the first run or a new shader file was added - // in both cases we can safely delete - if (removeCache (it->first)) - removeBinaryCache = true; - } - mShaderSets.insert(std::make_pair(it->first, newSet)); - } - - // new is now current - mShadersLastModified = mShadersLastModifiedNew; - - return removeBinaryCache; - } - - void Factory::doMonitorShaderFiles() - { - bool reload=false; - ScriptLoader shaderSetLoader(".shaderset"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - - std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); - std::string sourceRelative = it->second->findChild("source")->getValue(); - - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); - if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) - { - if (mShadersLastModified[sourceRelative] != lastModified) - { - reload=true; - break; - } - } - } - if (reload) - reloadShaders(); - } - - void Factory::logError(const std::string &msg) - { - mErrorLog << msg << '\n'; - } - - std::string Factory::getErrorLog() - { - std::string errors = mErrorLog.str(); - mErrorLog.str(""); - return errors; - } - - void Factory::unloadUnreferencedMaterials() - { - for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) - { - if (it->second.getMaterial()->isUnreferenced()) - it->second.getMaterial()->unreferenceTextures(); - } - } - - void Configuration::save(const std::string& name, std::ofstream &stream) - { - stream << "configuration " << name << '\n'; - stream << "{\n"; - PropertySetGet::save(stream, "\t"); - stream << "}\n"; - } -} diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp deleted file mode 100644 index 721b4af7d9..0000000000 --- a/extern/shiny/Main/Factory.hpp +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef SH_FACTORY_H -#define SH_FACTORY_H - -#include -#include -#include - -#include "MaterialInstance.hpp" -#include "ShaderSet.hpp" -#include "Language.hpp" - -namespace sh -{ - class Platform; - - class Configuration : public PropertySetGet - { - public: - void setSourceFile (const std::string& file) { mSourceFile = file ; } - std::string getSourceFile () { return mSourceFile; } - - void save(const std::string& name, std::ofstream &stream); - - private: - std::string mSourceFile; - }; - - typedef std::map MaterialMap; - typedef std::map ShaderSetMap; - typedef std::map ConfigurationMap; - typedef std::map LodConfigurationMap; - typedef std::map LastModifiedMap; - - typedef std::map TextureAliasMap; - - /** - * @brief - * Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't - * do in a .mat script (for example a series of animated textures) \n - * When receiving the event, you can get the platform material by calling m->getMaterial() - * and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial) - */ - class MaterialListener - { - public: - virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0; - }; - - /** - * @brief - * The main interface class - */ - class Factory - { - public: - Factory(Platform* platform); - ///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it. - - ~Factory(); - - /** - * Create a MaterialInstance, optionally copying all properties from \a parentInstance - * @param name name of the new instance - * @param name of the parent (optional) - * @return newly created instance - */ - MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = ""); - - /// @note It is safe to call this if the instance does not exist - void destroyMaterialInstance (const std::string& name); - - /// Use this to enable or disable shaders on-the-fly - void setShadersEnabled (bool enabled); - - /// write generated shaders to current directory, useful for debugging - void setShaderDebugOutputEnabled (bool enabled); - - /// Use this to manage user settings. \n - /// Global settings can be retrieved in shaders through a macro. \n - /// When a global setting is changed, the shaders that depend on them are recompiled automatically. - void setGlobalSetting (const std::string& name, const std::string& value); - - /// Adjusts the given shared parameter. \n - /// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n - /// @param name of the shared parameter - /// @param value of the parameter, use sh::makeProperty to construct this value - void setSharedParameter (const std::string& name, PropertyValuePtr value); - - Language getCurrentLanguage (); - - /// Switch between different shader languages (cg, glsl, hlsl) - void setCurrentLanguage (Language lang); - - /// Get a MaterialInstance by name - MaterialInstance* getMaterialInstance (const std::string& name); - - /// Create a configuration, which can then be altered by using Factory::getConfiguration - void createConfiguration (const std::string& name); - - /// Register a lod configuration, which can then be used by setting up lod distance values for the material \n - /// 0 refers to highest lod, so use 1 or higher as index parameter - void registerLodConfiguration (int index, PropertySetGet configuration); - - /// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias" - /// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n - /// Example: \n - /// - In the material definition: texture_alias ReflectionMap \n - /// - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n - /// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated! - void setTextureAlias (const std::string& alias, const std::string& realName); - - /// Retrieve the real texture name for a texture alias (the real name is set by the user) - std::string retrieveTextureAlias (const std::string& name); - - /// Attach a listener for material created events - void setMaterialListener (MaterialListener* listener); - - /// Call this after you have set up basic stuff, like the shader language. - void loadAllFiles (); - - /// Controls writing of generated shader source code to the cache folder, so that the - /// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n - /// \note The default is off (no cache writing) - void setWriteSourceCache(bool write) { mWriteSourceCache = write; } - - /// Controls reading of generated shader sources from the cache folder - /// \note The default is off (no cache reading) - /// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros. - void setReadSourceCache(bool read) { mReadSourceCache = read; } - - /// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent - /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. - /// \note The default is off (no cache writing) - void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; } - - /// Controls reading of shader microcode from the cache folder. Microcode is machine independent - /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. - /// \note The default is off (no cache reading) - void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } - - /// Lists all materials currently registered with the factory. Whether they are - /// loaded or not does not matter. - void listMaterials (std::vector& out); - - /// Lists current name & value of all global settings. - void listGlobalSettings (std::map& out); - - /// Lists configuration names. - void listConfigurationNames (std::vector& out); - - /// Lists current name & value of settings for a given configuration. - void listConfigurationSettings (const std::string& name, std::map& out); - - /// Lists shader sets. - void listShaderSets (std::vector& out); - - /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache - /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. - bool reloadShaders(); - - /// Calls reloadShaders() if shader files have been modified since the last reload. - /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache - /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. - void doMonitorShaderFiles(); - - /// Unloads all materials that are currently not referenced. This will not unload the textures themselves, - /// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n - /// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period - /// of time should work just fine too. - void unloadUnreferencedMaterials(); - - void destroyConfiguration (const std::string& name); - - void notifyConfigurationChanged(); - - /// Saves all materials and configurations, by default to the file they were loaded from. - /// If you wish to save them elsewhere, use setSourceFile first. - void saveAll (); - - /// Returns the error log as a string, then clears it. - /// Note: Errors are also written to the standard error output, or thrown if they are fatal. - std::string getErrorLog (); - - static Factory& getInstance(); - ///< Return instance of this class. - - static Factory* getInstancePtr(); - - /// Make sure a material technique is loaded.\n - /// You will probably never have to use this. - void _ensureMaterial(const std::string& name, const std::string& configuration); - - - Configuration* getConfiguration (const std::string& name); - - private: - - MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); - ShaderSet* getShaderSet (const std::string& name); - Platform* getPlatform (); - - PropertySetGet* getCurrentGlobalSettings(); - - void addTextureAliasInstance (const std::string& name, TextureUnitState* t); - void removeTextureAliasInstances (TextureUnitState* t); - - std::string getCacheFolder () { return mPlatform->getCacheFolder (); } - bool getReadSourceCache() { return mReadSourceCache; } - bool getWriteSourceCache() { return mWriteSourceCache; } - public: - bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme - - private: - void setActiveConfiguration (const std::string& configuration); - void setActiveLodLevel (int level); - - bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; } - - std::map mTextureAliasInstances; - - void logError (const std::string& msg); - - friend class Platform; - friend class MaterialInstance; - friend class ShaderInstance; - friend class ShaderSet; - friend class TextureUnitState; - - private: - static Factory* sThis; - - bool mShadersEnabled; - bool mShaderDebugOutputEnabled; - - bool mReadMicrocodeCache; - bool mWriteMicrocodeCache; - bool mReadSourceCache; - bool mWriteSourceCache; - std::stringstream mErrorLog; - - MaterialMap mMaterials; - ShaderSetMap mShaderSets; - ConfigurationMap mConfigurations; - LodConfigurationMap mLodConfigurations; - LastModifiedMap mShadersLastModified; - LastModifiedMap mShadersLastModifiedNew; - - PropertySetGet mGlobalSettings; - - PropertySetGet* mCurrentConfiguration; - PropertySetGet* mCurrentLodConfiguration; - - TextureAliasMap mTextureAliases; - - Language mCurrentLanguage; - - MaterialListener* mListener; - - Platform* mPlatform; - - MaterialInstance* findInstance (const std::string& name); - MaterialInstance* searchInstance (const std::string& name); - - /// @return was anything removed? - bool removeCache (const std::string& pattern); - - static const std::string mBinaryCacheName; - }; -} - -#endif diff --git a/extern/shiny/Main/Language.hpp b/extern/shiny/Main/Language.hpp deleted file mode 100644 index 6b271cb86a..0000000000 --- a/extern/shiny/Main/Language.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef SH_LANGUAGE_H -#define SH_LANGUAGE_H - -namespace sh -{ - enum Language - { - Language_CG, - Language_HLSL, - Language_GLSL, - Language_GLSLES, - Language_Count, - Language_None - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp deleted file mode 100644 index c69d134010..0000000000 --- a/extern/shiny/Main/MaterialInstance.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "MaterialInstance.hpp" - -#include -#include - -#include "Factory.hpp" -#include "ShaderSet.hpp" - -namespace sh -{ - MaterialInstance::MaterialInstance (const std::string& name, Factory* f) - : mName(name) - , mShadersEnabled(true) - , mFactory(f) - , mListener(NULL) - , mFailedToCreate(false) - { - } - - MaterialInstance::~MaterialInstance () - { - } - - void MaterialInstance::setParentInstance (const std::string& name) - { - mParentInstance = name; - } - - std::string MaterialInstance::getParentInstance () - { - return mParentInstance; - } - - void MaterialInstance::create (Platform* platform) - { - mMaterial = platform->createMaterial(mName); - - if (hasProperty ("shadow_caster_material")) - mMaterial->setShadowCasterMaterial (retrieveValue(getProperty("shadow_caster_material"), NULL).get()); - - if (hasProperty ("lod_values")) - mMaterial->setLodLevels (retrieveValue(getProperty("lod_values"), NULL).get()); - } - - void MaterialInstance::destroyAll () - { - if (hasProperty("create_configuration")) - return; - mMaterial->removeAll(); - mTexUnits.clear(); - mFailedToCreate = false; - } - - void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) - { - PropertySetGet::setProperty (name, value); - destroyAll(); // trigger updates - } - - bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) - { - if (mFailedToCreate) - return false; - try{ - mMaterial->ensureLoaded(); - bool res = mMaterial->createConfiguration(configuration, lodIndex); - if (!res) - return false; // listener was false positive - - if (mListener) - mListener->requestedConfiguration (this, configuration); - - mFactory->setActiveConfiguration (configuration); - mFactory->setActiveLodLevel (lodIndex); - - bool allowFixedFunction = true; - if (!mShadersEnabled && hasProperty("allow_fixed_function")) - { - allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); - } - - bool useShaders = mShadersEnabled || !allowFixedFunction; - - // get passes of the top-most parent - PassVector* passes = getParentPasses(); - if (passes->empty()) - throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); - - for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it) - { - boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); - it->copyAll (pass.get(), this); - - // texture samplers used in the shaders - std::vector usedTextureSamplersVertex; - std::vector usedTextureSamplersFragment; - - PropertySetGet* context = this; - - // create or retrieve shaders - bool hasVertex = it->hasProperty("vertex_program") - && !retrieveValue(it->getProperty("vertex_program"), context).get().empty(); - bool hasFragment = it->hasProperty("fragment_program") - && !retrieveValue(it->getProperty("fragment_program"), context).get().empty(); - if (useShaders) - { - it->setContext(context); - it->mShaderProperties.setContext(context); - if (hasVertex) - { - ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); - ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); - if (v) - { - pass->assignProgram (GPT_Vertex, v->getName()); - v->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = v->getSharedParameters (); - for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) - { - pass->addSharedParameter (GPT_Vertex, *it2); - } - - std::vector vector = v->getUsedSamplers (); - usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); - } - } - if (hasFragment) - { - ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); - ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); - if (f) - { - pass->assignProgram (GPT_Fragment, f->getName()); - f->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = f->getSharedParameters (); - for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) - { - pass->addSharedParameter (GPT_Fragment, *it2); - } - - std::vector vector = f->getUsedSamplers (); - usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); - } - } - } - - // create texture units - std::vector* texUnits = &it->mTexUnits; - int i=0; - for (std::vector::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt ) - { - // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled - bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); - bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); - if ( (foundVertex || foundFragment) - || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) - { - boost::shared_ptr texUnit = pass->createTextureUnitState (texIt->getName()); - texIt->copyAll (texUnit.get(), context); - - mTexUnits.push_back(texUnit); - - // set texture unit indices (required by GLSL) - if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && (mFactory->getCurrentLanguage () == Language_GLSL - || mFactory->getCurrentLanguage() == Language_GLSLES)) - { - pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); - - ++i; - } - } - } - } - - if (mListener) - mListener->createdConfiguration (this, configuration); - return true; - - } catch (std::runtime_error& e) - { - destroyAll(); - mFailedToCreate = true; - std::stringstream msg; - msg << "Error while creating material " << mName << ": " << e.what(); - std::cerr << msg.str() << std::endl; - mFactory->logError(msg.str()); - return false; - } - } - - Material* MaterialInstance::getMaterial () - { - return mMaterial.get(); - } - - MaterialInstancePass* MaterialInstance::createPass () - { - mPasses.push_back (MaterialInstancePass()); - mPasses.back().setContext(this); - return &mPasses.back(); - } - - void MaterialInstance::deletePass(unsigned int index) - { - assert(mPasses.size() > index); - mPasses.erase(mPasses.begin()+index); - } - - PassVector* MaterialInstance::getParentPasses() - { - if (mParent) - return static_cast(mParent)->getParentPasses(); - else - return &mPasses; - } - - PassVector* MaterialInstance::getPasses() - { - return &mPasses; - } - - void MaterialInstance::setShadersEnabled (bool enabled) - { - if (enabled == mShadersEnabled) - return; - mShadersEnabled = enabled; - - // trigger updates - if (mMaterial.get()) - destroyAll(); - } - - void MaterialInstance::save (std::ofstream& stream) - { - stream << "material " << mName << "\n" - << "{\n"; - - if (mParent) - { - stream << "\t" << "parent " << static_cast(mParent)->getName() << "\n"; - } - - const PropertyMap& properties = listProperties (); - for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) - { - stream << "\t" << it->first << " " << retrieveValue(getProperty(it->first), NULL).get() << "\n"; - } - - for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it) - { - stream << "\tpass" << '\n'; - stream << "\t{" << '\n'; - it->save(stream); - stream << "\t}" << '\n'; - } - - stream << "}\n"; - } -} diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp deleted file mode 100644 index 72c78c7b7c..0000000000 --- a/extern/shiny/Main/MaterialInstance.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef SH_MATERIALINSTANCE_H -#define SH_MATERIALINSTANCE_H - -#include -#include - -#include "PropertyBase.hpp" -#include "Platform.hpp" -#include "MaterialInstancePass.hpp" - -namespace sh -{ - class Factory; - - typedef std::vector PassVector; - - /** - * @brief - * Allows you to be notified when a certain configuration for a material was just about to be created. \n - * Useful for adjusting some properties prior to the material being created (Or you could also re-create - * the whole material from scratch, i.e. use this as a method to create this material entirely in code) - */ - class MaterialInstanceListener - { - public: - virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating - virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating - virtual ~MaterialInstanceListener(){} - }; - - /** - * @brief - * A specific material instance, which has all required properties set - * (for example the diffuse & normal map, ambient/diffuse/specular values). \n - * Depending on these properties, the system will automatically select a shader permutation - * that suits these and create the backend materials / passes (provided by the \a Platform class). - */ - class MaterialInstance : public PropertySetGet - { - public: - MaterialInstance (const std::string& name, Factory* f); - virtual ~MaterialInstance (); - - PassVector* getParentPasses(); ///< gets the passes of the top-most parent - - PassVector* getPasses(); ///< get our passes (for derived materials, none) - - MaterialInstancePass* createPass (); - void deletePass (unsigned int index); - - /// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet! - /// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event! - Material* getMaterial(); - - /// attach a \a MaterialInstanceListener to this specific material (as opposed to \a MaterialListener, which listens to all materials) - void setListener (MaterialInstanceListener* l) { mListener = l; } - - std::string getName() { return mName; } - - virtual void setProperty (const std::string& name, PropertyValuePtr value); - - void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } - - std::string getSourceFile() { return mSourceFile; } - ///< get the name of the file this material was read from, or empty if it was created dynamically by code - - private: - void setParentInstance (const std::string& name); - std::string getParentInstance (); - - void create (Platform* platform); - bool createForConfiguration (const std::string& configuration, unsigned short lodIndex); - - void destroyAll (); - - void setShadersEnabled (bool enabled); - - void save (std::ofstream& stream); - - bool mFailedToCreate; - - friend class Factory; - - - private: - std::string mParentInstance; - ///< this is only used during the file-loading phase. an instance could be loaded before its parent is loaded, - /// so initially only the parent's name is written to this member. - /// once all instances are loaded, the actual mParent pointer (from PropertySetGet class) can be set - - std::vector< boost::shared_ptr > mTexUnits; - - MaterialInstanceListener* mListener; - - PassVector mPasses; - - std::string mName; - - std::string mSourceFile; - - boost::shared_ptr mMaterial; - - bool mShadersEnabled; - - Factory* mFactory; - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstancePass.cpp b/extern/shiny/Main/MaterialInstancePass.cpp deleted file mode 100644 index a628cd64c7..0000000000 --- a/extern/shiny/Main/MaterialInstancePass.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "MaterialInstancePass.hpp" - -#include - -namespace sh -{ - - MaterialInstanceTextureUnit* MaterialInstancePass::createTextureUnit (const std::string& name) - { - mTexUnits.push_back(MaterialInstanceTextureUnit(name)); - return &mTexUnits.back(); - } - - void MaterialInstancePass::save(std::ofstream &stream) - { - if (mShaderProperties.listProperties().size()) - { - stream << "\t\t" << "shader_properties" << '\n'; - stream << "\t\t{\n"; - mShaderProperties.save(stream, "\t\t\t"); - stream << "\t\t}\n"; - } - - PropertySetGet::save(stream, "\t\t"); - - for (std::vector ::iterator it = mTexUnits.begin(); - it != mTexUnits.end(); ++it) - { - stream << "\t\ttexture_unit " << it->getName() << '\n'; - stream << "\t\t{\n"; - it->save(stream, "\t\t\t"); - stream << "\t\t}\n"; - } - } -} diff --git a/extern/shiny/Main/MaterialInstancePass.hpp b/extern/shiny/Main/MaterialInstancePass.hpp deleted file mode 100644 index 3d83d8fa35..0000000000 --- a/extern/shiny/Main/MaterialInstancePass.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SH_MATERIALINSTANCEPASS_H -#define SH_MATERIALINSTANCEPASS_H - -#include - -#include "PropertyBase.hpp" -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - /** - * @brief - * Holds properties of a single texture unit in a \a MaterialInstancePass. \n - * No inheritance here for now. - */ - class MaterialInstancePass : public PropertySetGet - { - public: - MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); - - void save (std::ofstream& stream); - - PropertySetGet mShaderProperties; - - std::vector mTexUnits; - }; -} - -#endif diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp deleted file mode 100644 index 0e3078af34..0000000000 --- a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "MaterialInstanceTextureUnit.hpp" - -namespace sh -{ - MaterialInstanceTextureUnit::MaterialInstanceTextureUnit (const std::string& name) - : mName(name) - { - } - - std::string MaterialInstanceTextureUnit::getName() const - { - return mName; - } -} diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp deleted file mode 100644 index 5ca400fd49..0000000000 --- a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SH_MATERIALINSTANCETEXTUREUNIT_H -#define SH_MATERIALINSTANCETEXTUREUNIT_H - -#include "PropertyBase.hpp" - -namespace sh -{ - /** - * @brief - * A single texture unit state that belongs to a \a MaterialInstancePass \n - * this is not the real "backend" \a TextureUnitState (provided by \a Platform), - * it is merely a placeholder for properties. \n - * @note The backend \a TextureUnitState will only be created if this texture unit is - * actually used (i.e. referenced in the shader, or marked with property create_in_ffp = true). - */ - class MaterialInstanceTextureUnit : public PropertySetGet - { - public: - MaterialInstanceTextureUnit (const std::string& name); - std::string getName() const; - void setName (const std::string& name) { mName = name; } - private: - std::string mName; - }; -} - -#endif diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp deleted file mode 100644 index 3eb7f4ad34..0000000000 --- a/extern/shiny/Main/Platform.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "Platform.hpp" - -#include - -#include "Factory.hpp" - -namespace sh -{ - Platform::Platform (const std::string& basePath) - : mBasePath(basePath) - , mCacheFolder("./") - , mFactory(NULL) - { - } - - Platform::~Platform () - { - } - - void Platform::setFactory (Factory* factory) - { - mFactory = factory; - } - - std::string Platform::getBasePath () - { - return mBasePath; - } - - bool Platform::supportsMaterialQueuedListener () - { - return false; - } - - bool Platform::supportsShaderSerialization () - { - return false; - } - - MaterialInstance* Platform::fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex) - { - return mFactory->requestMaterial (name, configuration, lodIndex); - } - - void Platform::serializeShaders (const std::string& file) - { - throw std::runtime_error ("Shader serialization not supported by this platform"); - } - - void Platform::deserializeShaders (const std::string& file) - { - throw std::runtime_error ("Shader serialization not supported by this platform"); - } - - void Platform::setCacheFolder (const std::string& folder) - { - mCacheFolder = folder; - } - - std::string Platform::getCacheFolder() const - { - return mCacheFolder; - } - - // ------------------------------------------------------------------------------ - - bool TextureUnitState::setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context) - { - if (name == "texture_alias") - { - std::string aliasName = retrieveValue(value, context).get(); - - Factory::getInstance().addTextureAliasInstance (aliasName, this); - - setTextureName (Factory::getInstance().retrieveTextureAlias (aliasName)); - - return true; - } - else - return false; - } - - TextureUnitState::~TextureUnitState() - { - Factory* f = Factory::getInstancePtr (); - if (f) - f->removeTextureAliasInstances (this); - } -} diff --git a/extern/shiny/Main/Platform.hpp b/extern/shiny/Main/Platform.hpp deleted file mode 100644 index d3156e6801..0000000000 --- a/extern/shiny/Main/Platform.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef SH_PLATFORM_H -#define SH_PLATFORM_H - -#include - -#include - -#include "Language.hpp" -#include "PropertyBase.hpp" - -namespace sh -{ - class Factory; - class MaterialInstance; - - enum GpuProgramType - { - GPT_Vertex, - GPT_Fragment - // GPT_Geometry - }; - - // These classes are supposed to be filled by the platform implementation - class GpuProgram - { - public: - virtual ~GpuProgram() {} - virtual bool getSupported () = 0; ///< @return true if the compilation was successful - - /// @param name name of the uniform in the shader - /// @param autoConstantName name of the auto constant (for example world_viewproj_matrix) - /// @param extraInfo if any extra info is needed (e.g. light index), put it here - virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "") = 0; - }; - - class TextureUnitState : public PropertySet - { - public: - virtual ~TextureUnitState(); - virtual void setTextureName (const std::string& textureName) = 0; - - protected: - virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context); - }; - - class Pass : public PropertySet - { - public: - virtual boost::shared_ptr createTextureUnitState (const std::string& name) = 0; - virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; - - /// @param type gpu program type - /// @param name name of the uniform in the shader - /// @param vt type of value, e.g. vector4 - /// @param value value to set - /// @param context used for retrieving linked values - virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) = 0; - - virtual void setTextureUnitIndex (int programType, const std::string& name, int index) = 0; - - virtual void addSharedParameter (int type, const std::string& name) = 0; - }; - - class Material : public PropertySet - { - public: - virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex) = 0; - virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists - virtual void removeAll () = 0; ///< remove all configurations - - virtual bool isUnreferenced() = 0; - virtual void unreferenceTextures() = 0; - virtual void ensureLoaded() = 0; - - virtual void setLodLevels (const std::string& lodLevels) = 0; - - virtual void setShadowCasterMaterial (const std::string& name) = 0; - }; - - class Platform - { - public: - Platform (const std::string& basePath); - virtual ~Platform (); - - /// set the folder to use for shader caching - void setCacheFolder (const std::string& folder); - - private: - virtual boost::shared_ptr createMaterial (const std::string& name) = 0; - - virtual boost::shared_ptr createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang) = 0; - - virtual void destroyGpuProgram (const std::string& name) = 0; - - virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0; - - virtual bool isProfileSupported (const std::string& profile) = 0; - - virtual void serializeShaders (const std::string& file); - virtual void deserializeShaders (const std::string& file); - - std::string getCacheFolder () const; - - friend class Factory; - friend class MaterialInstance; - friend class ShaderInstance; - friend class ShaderSet; - - protected: - /** - * this will be \a true if the platform supports serialization (writing shader microcode - * to disk) and deserialization (create gpu program from saved microcode) - */ - virtual bool supportsShaderSerialization (); - - /** - * this will be \a true if the platform supports a listener that notifies the system - * whenever a material is requested for rendering. if this is supported, shaders can be - * compiled on-demand when needed (and not earlier) - * @todo the Factory is not designed yet to handle the case where this method returns false - */ - virtual bool supportsMaterialQueuedListener (); - - /** - * fire event: material requested for rendering - * @param name material name - * @param configuration requested configuration - */ - MaterialInstance* fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex); - - std::string mCacheFolder; - Factory* mFactory; - - private: - void setFactory (Factory* factory); - - std::string mBasePath; - std::string getBasePath(); - }; -} - -#endif diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp deleted file mode 100644 index 26481aa036..0000000000 --- a/extern/shiny/Main/Preprocessor.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "Preprocessor.hpp" - -#include -#include -#include - -#include - -/* - Almost exact copy of load_file_to_string policy found in - boost::wave headers with the only change that it uses - boost::filesystem facility to handle UTF-8 paths properly on windows. - - Original namespace is used due to required bost::wave - internal symbols. -*/ -namespace boost { -namespace wave { -namespace iteration_context_policies { - - struct load_utf8_path_to_string - { - template - class inner - { - public: - template - static void init_iterators(IterContextT &iter_ctx, - PositionT const &act_pos, language_support language) - { - typedef typename IterContextT::iterator_type iterator_type; - namespace bfs = boost::filesystem; - - // read in the file - bfs::ifstream instream(bfs::path(iter_ctx.filename.c_str())); - if (!instream.is_open()) { - BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception, - bad_include_file, iter_ctx.filename.c_str(), act_pos); - return; - } - instream.unsetf(std::ios::skipws); - - iter_ctx.instring.assign( - std::istreambuf_iterator(instream.rdbuf()), - std::istreambuf_iterator()); - - iter_ctx.first = iterator_type( - iter_ctx.instring.begin(), iter_ctx.instring.end(), - PositionT(iter_ctx.filename), language); - iter_ctx.last = iterator_type(); - } - - private: - std::string instring; - }; - }; -} } } - -namespace sh -{ - std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name) - { - std::stringstream returnString; - - // current file position is saved for exception handling - boost::wave::util::file_position_type current_position; - - try - { - // This token type is one of the central types used throughout the library. - // It is a template parameter to some of the public classes and instances - // of this type are returned from the iterators. - typedef boost::wave::cpplexer::lex_token<> token_type; - - // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to - // to use as the token source for the preprocessing engine. It is - // parametrized with the token type. - typedef boost::wave::cpplexer::lex_iterator lex_iterator_type; - - // This is the resulting context type. The first template parameter should - // match the iterator type used during construction of the context - // instance (see below). It is the type of the underlying input stream. - typedef boost::wave::context - context_type; - - // The preprocessor iterator shouldn't be constructed directly. It is - // generated through a wave::context<> object. This wave:context<> object - // is additionally used to initialize and define different parameters of - // the actual preprocessing. - // - // The preprocessing of the input stream is done on the fly behind the - // scenes during iteration over the range of context_type::iterator_type - // instances. - context_type ctx (source.begin(), source.end(), name.c_str()); - ctx.add_include_path(includePath.c_str()); - for (std::vector::iterator it = definitions.begin(); it != definitions.end(); ++it) - { - ctx.add_macro_definition(*it); - } - - // Get the preprocessor iterators and use them to generate the token - // sequence. - context_type::iterator_type first = ctx.begin(); - context_type::iterator_type last = ctx.end(); - - // The input stream is preprocessed for you while iterating over the range - // [first, last). The dereferenced iterator returns tokens holding - // information about the preprocessed input stream, such as token type, - // token value, and position. - while (first != last) - { - current_position = (*first).get_position(); - returnString << (*first).get_value(); - ++first; - } - } - catch (boost::wave::cpp_exception const& e) - { - // some preprocessing error - std::stringstream error; - error - << e.file_name() << "(" << e.line_no() << "): " - << e.description(); - throw std::runtime_error(error.str()); - } - catch (std::exception const& e) - { - // use last recognized token to retrieve the error position - std::stringstream error; - error - << current_position.get_file() - << "(" << current_position.get_line() << "): " - << "exception caught: " << e.what(); - throw std::runtime_error(error.str()); - } - catch (...) - { - // use last recognized token to retrieve the error position - std::stringstream error; - error - << current_position.get_file() - << "(" << current_position.get_line() << "): " - << "unexpected exception caught."; - throw std::runtime_error(error.str()); - } - - return returnString.str(); - } -} diff --git a/extern/shiny/Main/Preprocessor.hpp b/extern/shiny/Main/Preprocessor.hpp deleted file mode 100644 index 7ee30ae7fc..0000000000 --- a/extern/shiny/Main/Preprocessor.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SH_PREPROCESSOR_H -#define SH_PREPROCESSOR_H - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace sh -{ - /** - * @brief A simple interface for the boost::wave preprocessor - */ - class Preprocessor - { - public: - /** - * @brief Run a shader source string through the preprocessor - * @param source source string - * @param includePath path to search for includes (that are included with #include) - * @param definitions macros to predefine (vector of strings of the format MACRO=value, or just MACRO to define it as 1) - * @param name name to use for error messages - * @return processed string - */ - static std::string preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name); - }; - - - - class emit_custom_line_directives_hooks - : public boost::wave::context_policies::default_preprocessing_hooks - { - public: - - template - bool - emit_line_directive(ContextT const& ctx, ContainerT &pending, - typename ContextT::token_type const& act_token) - { - // emit a #line directive showing the relative filename instead - typename ContextT::position_type pos = act_token.get_position(); - unsigned int column = 1; - - typedef typename ContextT::token_type result_type; - - // no line directives for now - pos.set_column(column); - pending.push_back(result_type(boost::wave::T_GENERATEDNEWLINE, "\n", pos)); - - return true; - } - }; - - -} - -#endif diff --git a/extern/shiny/Main/PropertyBase.cpp b/extern/shiny/Main/PropertyBase.cpp deleted file mode 100644 index 8592712fa9..0000000000 --- a/extern/shiny/Main/PropertyBase.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "PropertyBase.hpp" - -#include -#include - -#include -#include - -#include - -namespace sh -{ - - IntValue::IntValue(int in) - : mValue(in) - { - } - - IntValue::IntValue(const std::string& in) - { - mValue = boost::lexical_cast(in); - } - - std::string IntValue::serialize() - { - return boost::lexical_cast(mValue); - } - - // ------------------------------------------------------------------------------ - - BooleanValue::BooleanValue (bool in) - : mValue(in) - { - } - - BooleanValue::BooleanValue (const std::string& in) - { - if (in == "true") - mValue = true; - else if (in == "false") - mValue = false; - else - { - std::stringstream msg; - msg << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue"; - throw std::runtime_error(msg.str()); - } - } - - std::string BooleanValue::serialize () - { - if (mValue) - return "true"; - else - return "false"; - } - - // ------------------------------------------------------------------------------ - - StringValue::StringValue (const std::string& in) - { - mStringValue = in; - } - - std::string StringValue::serialize() - { - return mStringValue; - } - - // ------------------------------------------------------------------------------ - - LinkedValue::LinkedValue (const std::string& in) - { - mStringValue = in; - mStringValue.erase(0, 1); - } - - std::string LinkedValue::serialize() - { - throw std::runtime_error ("can't directly get a linked value"); - } - - std::string LinkedValue::get(PropertySetGet* context) const - { - PropertyValuePtr p = context->getProperty(mStringValue); - return retrieveValue(p, NULL).get(); - } - - // ------------------------------------------------------------------------------ - - FloatValue::FloatValue (float in) - { - mValue = in; - } - - FloatValue::FloatValue (const std::string& in) - { - mValue = boost::lexical_cast(in); - } - - std::string FloatValue::serialize () - { - return boost::lexical_cast(mValue); - } - - // ------------------------------------------------------------------------------ - - Vector2::Vector2 (float x, float y) - : mX(x) - , mY(y) - { - } - - Vector2::Vector2 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 2) && "Invalid Vector2 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - } - - std::string Vector2::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY); - } - - // ------------------------------------------------------------------------------ - - Vector3::Vector3 (float x, float y, float z) - : mX(x) - , mY(y) - , mZ(z) - { - } - - Vector3::Vector3 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 3) && "Invalid Vector3 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - mZ = boost::lexical_cast (tokens[2]); - } - - std::string Vector3::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY) + " " - + boost::lexical_cast(mZ); - } - - // ------------------------------------------------------------------------------ - - Vector4::Vector4 (float x, float y, float z, float w) - : mX(x) - , mY(y) - , mZ(z) - , mW(w) - { - } - - Vector4::Vector4 (const std::string& in) - { - std::vector tokens; - boost::split(tokens, in, boost::is_any_of(" ")); - assert ((tokens.size() == 4) && "Invalid Vector4 conversion"); - mX = boost::lexical_cast (tokens[0]); - mY = boost::lexical_cast (tokens[1]); - mZ = boost::lexical_cast (tokens[2]); - mW = boost::lexical_cast (tokens[3]); - } - - std::string Vector4::serialize () - { - return boost::lexical_cast(mX) + " " - + boost::lexical_cast(mY) + " " - + boost::lexical_cast(mZ) + " " - + boost::lexical_cast(mW); - } - - // ------------------------------------------------------------------------------ - - void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) - { - if (!setPropertyOverride (name, value, context)) - { - std::stringstream msg; - msg << "sh::PropertySet: Warning: No match for property with name '" << name << "'"; - throw std::runtime_error(msg.str()); - } - } - - bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) - { - // if we got here, none of the sub-classes were able to make use of the property - return false; - } - - // ------------------------------------------------------------------------------ - - PropertySetGet::PropertySetGet (PropertySetGet* parent) - : mParent(parent) - , mContext(NULL) - { - } - - PropertySetGet::PropertySetGet () - : mParent(NULL) - , mContext(NULL) - { - } - - void PropertySetGet::setParent (PropertySetGet* parent) - { - mParent = parent; - } - - void PropertySetGet::setContext (PropertySetGet* context) - { - mContext = context; - } - - PropertySetGet* PropertySetGet::getContext() - { - return mContext; - } - - void PropertySetGet::setProperty (const std::string& name, PropertyValuePtr value) - { - mProperties [name] = value; - } - - void PropertySetGet::deleteProperty(const std::string &name) - { - mProperties.erase(name); - } - - PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) - { - bool found = (mProperties.find(name) != mProperties.end()); - - if (!found) - { - if (!mParent) - throw std::runtime_error ("Trying to retrieve property \"" + name + "\" that does not exist"); - else - return mParent->getProperty (name); - } - else - return mProperties[name]; - } - - bool PropertySetGet::hasProperty (const std::string& name) const - { - bool found = (mProperties.find(name) != mProperties.end()); - - if (!found) - { - if (!mParent) - return false; - else - return mParent->hasProperty (name); - } - else - return true; - } - - void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context, bool copyParent) - { - if (mParent && copyParent) - mParent->copyAll (target, context); - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - target->setProperty(it->first, it->second, context); - } - } - - void PropertySetGet::copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent) - { - if (mParent && copyParent) - mParent->copyAll (target, context); - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - std::string val = retrieveValue(it->second, this).get(); - target->setProperty(it->first, sh::makeProperty(new sh::StringValue(val))); - } - } - - void PropertySetGet::save(std::ofstream &stream, const std::string& indentation) - { - for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - if (typeid( *(it->second) ) == typeid(LinkedValue)) - stream << indentation << it->first << " " << "$" + static_cast(&*(it->second))->_getStringValue() << '\n'; - else - stream << indentation << it->first << " " << retrieveValue(it->second, this).get() << '\n'; - } - } -} diff --git a/extern/shiny/Main/PropertyBase.hpp b/extern/shiny/Main/PropertyBase.hpp deleted file mode 100644 index 13809443e2..0000000000 --- a/extern/shiny/Main/PropertyBase.hpp +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef SH_PROPERTYBASE_H -#define SH_PROPERTYBASE_H - -#include -#include - -#include - -namespace sh -{ - class StringValue; - class PropertySetGet; - class LinkedValue; - - enum ValueType - { - VT_String, - VT_Int, - VT_Float, - VT_Vector2, - VT_Vector3, - VT_Vector4 - }; - - class PropertyValue - { - public: - PropertyValue() {} - - virtual ~PropertyValue() {} - - std::string _getStringValue() { return mStringValue; } - - virtual std::string serialize() = 0; - - protected: - std::string mStringValue; ///< this will possibly not contain anything in the specialised classes - }; - typedef boost::shared_ptr PropertyValuePtr; - - class StringValue : public PropertyValue - { - public: - StringValue (const std::string& in); - std::string get() const { return mStringValue; } - - virtual std::string serialize(); - }; - - /** - * @brief Used for retrieving a named property from a context - */ - class LinkedValue : public PropertyValue - { - public: - LinkedValue (const std::string& in); - - std::string get(PropertySetGet* context) const; - - virtual std::string serialize(); - }; - - class FloatValue : public PropertyValue - { - public: - FloatValue (float in); - FloatValue (const std::string& in); - float get() const { return mValue; } - - virtual std::string serialize(); - private: - float mValue; - }; - - class IntValue : public PropertyValue - { - public: - IntValue (int in); - IntValue (const std::string& in); - int get() const { return mValue; } - - virtual std::string serialize(); - private: - int mValue; - }; - - class BooleanValue : public PropertyValue - { - public: - BooleanValue (bool in); - BooleanValue (const std::string& in); - bool get() const { return mValue; } - - virtual std::string serialize(); - private: - bool mValue; - }; - - class Vector2 : public PropertyValue - { - public: - Vector2 (float x, float y); - Vector2 (const std::string& in); - - float mX, mY; - - virtual std::string serialize(); - }; - - class Vector3 : public PropertyValue - { - public: - Vector3 (float x, float y, float z); - Vector3 (const std::string& in); - - float mX, mY, mZ; - - virtual std::string serialize(); - }; - - class Vector4 : public PropertyValue - { - public: - Vector4 (float x, float y, float z, float w); - Vector4 (const std::string& in); - - float mX, mY, mZ, mW; - - virtual std::string serialize(); - }; - - /// \brief base class that allows setting properties with any kind of value-type - class PropertySet - { - public: - virtual ~PropertySet() {} - void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); - - protected: - virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); - ///< @return \a true if the specified property was found, or false otherwise - }; - - typedef std::map PropertyMap; - - /// \brief base class that allows setting properties with any kind of value-type and retrieving them - class PropertySetGet - { - public: - PropertySetGet (PropertySetGet* parent); - PropertySetGet (); - - virtual ~PropertySetGet() {} - - void save (std::ofstream& stream, const std::string& indentation); - - void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true); - ///< call setProperty for each property/value pair stored in \a this - void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true); - ///< call setProperty for each property/value pair stored in \a this - - void setParent (PropertySetGet* parent); - PropertySetGet* getParent () { return mParent; } - void setContext (PropertySetGet* context); - PropertySetGet* getContext(); - - virtual void setProperty (const std::string& name, PropertyValuePtr value); - PropertyValuePtr& getProperty (const std::string& name); - - void deleteProperty (const std::string& name); - - const PropertyMap& listProperties() { return mProperties; } - - bool hasProperty (const std::string& name) const; - - private: - PropertyMap mProperties; - - protected: - PropertySetGet* mParent; - ///< the parent can provide properties as well (when they are retrieved via getProperty) \n - /// multiple levels of inheritance are also supported \n - /// children can override properties of their parents - - PropertySetGet* mContext; - ///< used to retrieve linked property values - }; - - template - static T retrieveValue (boost::shared_ptr& value, PropertySetGet* context) - { - if (typeid(*value).name() == typeid(LinkedValue).name()) - { - std::string v = static_cast(value.get())->get(context); - PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v)); - return retrieveValue(newVal, NULL); - } - if (typeid(T).name() == typeid(*value).name()) - { - // requested type is the same as source type, only have to cast it - return *static_cast(value.get()); - } - - if ((typeid(T).name() == typeid(StringValue).name()) - && typeid(*value).name() != typeid(StringValue).name()) - { - // if string type is requested and value is not string, use serialize method to convert to string - T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here - value = boost::shared_ptr (static_cast(ptr)); - return *ptr; - } - - { - // remaining case: deserialization from string by passing the string to constructor of class T - T* ptr = new T(value->_getStringValue()); - PropertyValuePtr newVal (static_cast(ptr)); - value = newVal; - return *ptr; - } - } - ///< - /// @brief alternate version that supports linked values (use of $variables in parent material) - /// @note \a value is changed in-place to the converted object - /// @return converted object \n - - /// Create a property from a string - inline PropertyValuePtr makeProperty (const std::string& prop) - { - if (prop.size() > 1 && prop[0] == '$') - return PropertyValuePtr (static_cast(new LinkedValue(prop))); - else - return PropertyValuePtr (static_cast (new StringValue(prop))); - } - - template - /// Create a property of any type - /// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1)) - inline PropertyValuePtr makeProperty (T* p) - { - return PropertyValuePtr ( static_cast(p) ); - } -} - -#endif diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp deleted file mode 100644 index bafe07fc8e..0000000000 --- a/extern/shiny/Main/ScriptLoader.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "ScriptLoader.hpp" - -#include -#include -#include -#include - -#include - -namespace sh -{ - void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path) - { - for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir ) - { - boost::filesystem::path p(*dir); - if(p.extension() == c->mFileEnding) - { - c->mCurrentFileName = (*dir).path().string(); - std::ifstream in((*dir).path().string().c_str(), std::ios::binary); - c->parseScript(in); - } - } - } - - ScriptLoader::ScriptLoader(const std::string& fileEnding) - : mLoadOrder(0) - , mToken(TOKEN_NewLine) - , mLastToken(TOKEN_NewLine) - - { - mFileEnding = fileEnding; - } - - ScriptLoader::~ScriptLoader() - { - clearScriptList(); - } - - void ScriptLoader::clearScriptList() - { - std::map ::iterator i; - for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i) - { - delete i->second; - } - m_scriptList.clear(); - } - - ScriptNode *ScriptLoader::getConfigScript(const std::string &name) - { - std::map ::iterator i; - - std::string key = name; - i = m_scriptList.find(key); - - //If found.. - if (i != m_scriptList.end()) - { - return i->second; - } - else - { - return NULL; - } - } - - std::map ScriptLoader::getAllConfigScripts () - { - return m_scriptList; - } - - void ScriptLoader::parseScript(std::ifstream &stream) - { - //Get first token - _nextToken(stream); - if (mToken == TOKEN_EOF) - { - stream.close(); - return; - } - - //Parse the script - _parseNodes(stream, 0); - - stream.close(); - } - - void ScriptLoader::_nextToken(std::ifstream &stream) - { - //EOF token - if (!stream.good()) - { - mToken = TOKEN_EOF; - return; - } - - //(Get next character) - int ch = stream.get(); - - while ((ch == ' ' || ch == 9) && !stream.eof()) - { //Skip leading spaces / tabs - ch = stream.get(); - } - - if (!stream.good()) - { - mToken = TOKEN_EOF; - return; - } - - //Newline token - if (ch == '\r' || ch == '\n') - { - do - { - ch = stream.get(); - } while ((ch == '\r' || ch == '\n') && !stream.eof()); - - stream.unget(); - - mToken = TOKEN_NewLine; - return; - } - - //Open brace token - else if (ch == '{') - { - mToken = TOKEN_OpenBrace; - return; - } - - //Close brace token - else if (ch == '}') - { - mToken = TOKEN_CloseBrace; - return; - } - - //Text token - if (ch < 32 || ch > 122) //Verify valid char - { - throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()"); - } - - mTokenValue = ""; - mToken = TOKEN_Text; - do - { - //Skip comments - if (ch == '/') - { - int ch2 = stream.peek(); - - //C++ style comment (//) - if (ch2 == '/') - { - stream.get(); - do - { - ch = stream.get(); - } while (ch != '\r' && ch != '\n' && !stream.eof()); - - mToken = TOKEN_NewLine; - return; - } - } - - //Add valid char to tokVal - mTokenValue += (char)ch; - - //Next char - ch = stream.get(); - - } while (ch > 32 && ch <= 122 && !stream.eof()); - - stream.unget(); - - return; - } - - void ScriptLoader::_skipNewLines(std::ifstream &stream) - { - while (mToken == TOKEN_NewLine) - { - _nextToken(stream); - } - } - - void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent) - { - typedef std::pair ScriptItem; - - while (true) - { - switch (mToken) - { - //Node - case TOKEN_Text: - { - //Add the new node - ScriptNode *newNode; - if (parent) - { - newNode = parent->addChild(mTokenValue); - } - else - { - newNode = new ScriptNode(0, mTokenValue); - } - - //Get values - _nextToken(stream); - std::string valueStr; - int i=0; - while (mToken == TOKEN_Text) - { - if (i == 0) - valueStr += mTokenValue; - else - valueStr += " " + mTokenValue; - _nextToken(stream); - ++i; - } - newNode->setValue(valueStr); - - //Add root nodes to scriptList - if (!parent) - { - std::string key; - - if (newNode->getValue() == "") - throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")"); - key = newNode->getValue(); - - m_scriptList.insert(ScriptItem(key, newNode)); - } - - _skipNewLines(stream); - - //Add any sub-nodes - if (mToken == TOKEN_OpenBrace) - { - //Parse nodes - _nextToken(stream); - _parseNodes(stream, newNode); - //Check for matching closing brace - if (mToken != TOKEN_CloseBrace) - { - throw std::runtime_error("Parse Error: Expecting closing brace"); - } - _nextToken(stream); - _skipNewLines(stream); - } - - newNode->mFileName = mCurrentFileName; - - break; - } - - //Out of place brace - case TOKEN_OpenBrace: - throw std::runtime_error("Parse Error: Opening brace out of plane"); - break; - - //Return if end of nodes have been reached - case TOKEN_CloseBrace: - return; - - //Return if reached end of file - case TOKEN_EOF: - return; - - case TOKEN_NewLine: - _nextToken(stream); - break; - } - }; - } - - ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name) - { - mName = name; - mParent = parent; - mRemoveSelf = true; //For proper destruction - mLastChildFound = -1; - - //Add self to parent's child list (unless this is the root node being created) - if (parent != NULL) - { - mParent->mChildren.push_back(this); - mIter = --(mParent->mChildren.end()); - } - } - - ScriptNode::~ScriptNode() - { - //Delete all children - std::vector::iterator i; - for (i = mChildren.begin(); i != mChildren.end(); ++i) - { - ScriptNode *node = *i; - node->mRemoveSelf = false; - delete node; - } - mChildren.clear(); - - //Remove self from parent's child list - if (mRemoveSelf && mParent != NULL) - { - mParent->mChildren.erase(mIter); - } - } - - ScriptNode *ScriptNode::addChild(const std::string &name, bool replaceExisting) - { - if (replaceExisting) - { - ScriptNode *node = findChild(name, false); - if (node) - { - return node; - } - } - return new ScriptNode(this, name); - } - - ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) - { - int indx; - int childCount = (int)mChildren.size(); - - if (mLastChildFound != -1) - { - //If possible, try checking the nodes neighboring the last successful search - //(often nodes searched for in sequence, so this will boost search speeds). - int prevC = mLastChildFound-1; - if (prevC < 0) - prevC = 0; - else if (prevC >= childCount) - prevC = childCount-1; - int nextC = mLastChildFound+1; - if (nextC < 0) - nextC = 0; - else if (nextC >= childCount) - nextC = childCount-1; - - for (indx = prevC; indx <= nextC; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) - { - mLastChildFound = indx; - return node; - } - } - - //If not found that way, search for the node from start to finish, avoiding the - //already searched area above. - for (indx = nextC + 1; indx < childCount; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - for (indx = 0; indx < prevC; ++indx) - { - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - } - else - { - //Search for the node from start to finish - for (indx = 0; indx < childCount; ++indx){ - ScriptNode *node = mChildren[indx]; - if (node->mName == name) { - mLastChildFound = indx; - return node; - } - } - } - - //If not found, search child nodes (if recursive == true) - if (recursive) - { - for (indx = 0; indx < childCount; ++indx) - { - mChildren[indx]->findChild(name, recursive); - } - } - - //Not found anywhere - return NULL; - } - - void ScriptNode::setParent(ScriptNode *newParent) - { - //Remove self from current parent - mParent->mChildren.erase(mIter); - - //Set new parent - mParent = newParent; - - //Add self to new parent - mParent->mChildren.push_back(this); - mIter = --(mParent->mChildren.end()); - } -} diff --git a/extern/shiny/Main/ScriptLoader.hpp b/extern/shiny/Main/ScriptLoader.hpp deleted file mode 100644 index 89720fb5d0..0000000000 --- a/extern/shiny/Main/ScriptLoader.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef SH_CONFIG_LOADER_H__ -#define SH_CONFIG_LOADER_H__ - -#include -#include -#include -#include - -namespace sh -{ - class ScriptNode; - - /** - * @brief The base class of loaders that read Ogre style script files to get configuration and settings. - * Heavily inspired by: http://www.ogre3d.org/tikiwiki/All-purpose+script+parser - * ( "Non-ogre version") - */ - class ScriptLoader - { - public: - static void loadAllFiles(ScriptLoader* c, const std::string& path); - - ScriptLoader(const std::string& fileEnding); - virtual ~ScriptLoader(); - - std::string mFileEnding; - - // For a line like - // entity animals/dog - // { - // ... - // } - // The type is "entity" and the name is "animals/dog" - // Or if animal/dog was not there then name is "" - ScriptNode *getConfigScript (const std::string &name); - - std::map getAllConfigScripts (); - - void parseScript(std::ifstream &stream); - - std::string mCurrentFileName; - - protected: - - float mLoadOrder; - // like "*.object" - - std::map m_scriptList; - - enum Token - { - TOKEN_Text, - TOKEN_NewLine, - TOKEN_OpenBrace, - TOKEN_CloseBrace, - TOKEN_EOF - }; - - Token mToken, mLastToken; - std::string mTokenValue; - - void _parseNodes(std::ifstream &stream, ScriptNode *parent); - void _nextToken(std::ifstream &stream); - void _skipNewLines(std::ifstream &stream); - - void clearScriptList(); - }; - - class ScriptNode - { - public: - ScriptNode(ScriptNode *parent, const std::string &name = "untitled"); - ~ScriptNode(); - - inline void setName(const std::string &name) - { - this->mName = name; - } - - inline std::string &getName() - { - return mName; - } - - inline void setValue(const std::string &value) - { - mValue = value; - } - - inline std::string &getValue() - { - return mValue; - } - - ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false); - ScriptNode *findChild(const std::string &name, bool recursive = false); - - inline std::vector &getChildren() - { - return mChildren; - } - - inline ScriptNode *getChild(unsigned int index = 0) - { - assert(index < mChildren.size()); - return mChildren[index]; - } - - void setParent(ScriptNode *newParent); - - inline ScriptNode *getParent() - { - return mParent; - } - - std::string mFileName; - - - private: - std::string mName; - std::string mValue; - std::vector mChildren; - ScriptNode *mParent; - - - int mLastChildFound; //The last child node's index found with a call to findChild() - - std::vector::iterator mIter; - bool mRemoveSelf; - }; - -} - -#endif diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp deleted file mode 100644 index 270aaba68f..0000000000 --- a/extern/shiny/Main/ShaderInstance.cpp +++ /dev/null @@ -1,698 +0,0 @@ -#include "ShaderInstance.hpp" - -#include -#include -#include - -#include -#include -#include - -#include - -#include "Preprocessor.hpp" -#include "Factory.hpp" -#include "ShaderSet.hpp" - -namespace -{ - std::string convertLang (sh::Language lang) - { - if (lang == sh::Language_CG) - return "SH_CG"; - else if (lang == sh::Language_HLSL) - return "SH_HLSL"; - else if (lang == sh::Language_GLSL) - return "SH_GLSL"; - else if (lang == sh::Language_GLSLES) - return "SH_GLSLES"; - throw std::runtime_error("invalid language"); - } - - char getComponent(int num) - { - if (num == 0) - return 'x'; - else if (num == 1) - return 'y'; - else if (num == 2) - return 'z'; - else if (num == 3) - return 'w'; - else - throw std::runtime_error("invalid component"); - } - - std::string getFloat(sh::Language lang, int num_components) - { - if (lang == sh::Language_CG || lang == sh::Language_HLSL) - return (num_components == 1) ? "float" : "float" + boost::lexical_cast(num_components); - else - return (num_components == 1) ? "float" : "vec" + boost::lexical_cast(num_components); - } - - bool isCmd (const std::string& source, size_t pos, const std::string& cmd) - { - return (source.size() >= pos + cmd.size() && source.substr(pos, cmd.size()) == cmd); - } - - void writeDebugFile (const std::string& content, const std::string& filename) - { - boost::filesystem::path full_path(boost::filesystem::current_path()); - std::ofstream of ((full_path / filename ).string().c_str() , std::ios_base::out); - of.write(content.c_str(), content.size()); - of.close(); - } -} - -namespace sh -{ - std::string Passthrough::expand_assign(std::string toAssign) - { - std::string res; - - int i = 0; - int current_passthrough = passthrough_number; - int current_component_left = component_start; - int current_component_right = 0; - int components_left = num_components; - int components_at_once; - while (i < num_components) - { - if (components_left + current_component_left <= 4) - components_at_once = components_left; - else - components_at_once = 4 - current_component_left; - - std::string componentStr = "."; - for (int j = 0; j < components_at_once; ++j) - componentStr += getComponent(j + current_component_left); - std::string componentStr2 = "."; - for (int j = 0; j < components_at_once; ++j) - componentStr2 += getComponent(j + current_component_right); - if (num_components == 1) - { - componentStr2 = ""; - } - res += "passthrough" + boost::lexical_cast(current_passthrough) + componentStr + " = " + toAssign + componentStr2; - - current_component_left += components_at_once; - current_component_right += components_at_once; - components_left -= components_at_once; - - i += components_at_once; - - if (components_left == 0) - { - // finished - return res; - } - else - { - // add semicolon to every instruction but the last - res += "; "; - } - - if (current_component_left == 4) - { - current_passthrough++; - current_component_left = 0; - } - } - throw std::runtime_error("expand_assign error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning - } - - std::string Passthrough::expand_receive() - { - std::string res; - - res += getFloat(lang, num_components) + "("; - - int i = 0; - int current_passthrough = passthrough_number; - int current_component = component_start; - int components_left = num_components; - while (i < num_components) - { - int components_at_once = std::min(components_left, 4 - current_component); - - std::string componentStr; - for (int j = 0; j < components_at_once; ++j) - componentStr += getComponent(j + current_component); - - res += "passthrough" + boost::lexical_cast(current_passthrough) + "." + componentStr; - - current_component += components_at_once; - - components_left -= components_at_once; - - i += components_at_once; - - if (components_left == 0) - { - // finished - return res + ")"; -; - } - else - { - // add comma to every variable but the last - res += ", "; - } - - if (current_component == 4) - { - current_passthrough++; - current_component = 0; - } - } - - throw std::runtime_error("expand_receive error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning - } - - // ------------------------------------------------------------------------------ - - void ShaderInstance::parse (std::string& source, PropertySetGet* properties) - { - size_t pos = 0; - while (true) - { - pos = source.find("@", pos); - if (pos == std::string::npos) - break; - - if (isCmd(source, pos, "@shProperty")) - { - std::vector args = extractMacroArguments (pos, source); - - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string cmd = source.substr(pos+1, start-(pos+1)); - - std::string replaceValue; - if (cmd == "shPropertyBool") - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - bool val = retrieveValue(value, properties->getContext()).get(); - replaceValue = val ? "1" : "0"; - } - else if (cmd == "shPropertyString") - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - replaceValue = retrieveValue(value, properties->getContext()).get(); - } - else if (cmd == "shPropertyEqual") - { - std::string propertyName = args[0]; - std::string comparedAgainst = args[1]; - std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); - replaceValue = (value == comparedAgainst) ? "1" : "0"; - } - else if (isCmd(source, pos, "@shPropertyHasValue")) - { - assert(args.size() == 1); - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - std::string val = retrieveValue(value, properties->getContext()).get(); - replaceValue = (val.empty() ? "0" : "1"); - } - else - throw std::runtime_error ("unknown command \"" + cmd + "\""); - source.replace(pos, (end+1)-pos, replaceValue); - } - else if (isCmd(source, pos, "@shGlobalSetting")) - { - std::vector args = extractMacroArguments (pos, source); - - std::string cmd = source.substr(pos+1, source.find("(", pos)-(pos+1)); - std::string replaceValue; - if (cmd == "shGlobalSettingBool") - { - std::string settingName = args[0]; - std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - replaceValue = (value == "true" || value == "1") ? "1" : "0"; - } - else if (cmd == "shGlobalSettingEqual") - { - std::string settingName = args[0]; - std::string comparedAgainst = args[1]; - std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - replaceValue = (value == comparedAgainst) ? "1" : "0"; - } - else if (cmd == "shGlobalSettingString") - { - std::string settingName = args[0]; - replaceValue = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); - } - else - throw std::runtime_error ("unknown command \"" + cmd + "\""); - - source.replace(pos, (source.find(")", pos)+1)-pos, replaceValue); - } - else if (isCmd(source, pos, "@shForeach")) - { - - assert(source.find("@shEndForeach", pos) != std::string::npos); - size_t block_end = source.find("@shEndForeach", pos); - - // get the argument for parsing - size_t start = source.find("(", pos); - size_t end = start; - int brace_depth = 1; - while (brace_depth > 0) - { - ++end; - if (source[end] == '(') - ++brace_depth; - else if (source[end] == ')') - --brace_depth; - } - std::string arg = source.substr(start+1, end-(start+1)); - parse(arg, properties); - - int num = boost::lexical_cast(arg); - - // get the content of the inner block - std::string content = source.substr(end+1, block_end - (end+1)); - - // replace both outer and inner block with content of inner block num times - std::string replaceStr; - for (int i=0; i 0) - { - ++_end; - if (addStr[_end] == '(') - ++_brace_depth; - else if (addStr[_end] == ')') - --_brace_depth; - } - std::string arg = addStr.substr(_start+1, _end-(_start+1)); - parse(arg, properties); - - int offset = boost::lexical_cast (arg); - addStr.replace(pos2, (_end+1)-pos2, boost::lexical_cast(i+offset)); - } - else - { - addStr.replace(pos2, std::string("@shIterator").length(), boost::lexical_cast(i)); - } - } - - replaceStr += addStr; - } - source.replace(pos, (block_end+std::string("@shEndForeach").length())-pos, replaceStr); - } - else if (source.size() > pos+1) - ++pos; // skip - } - - } - - ShaderInstance::ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties) - : mName(name) - , mParent(parent) - , mSupported(true) - , mCurrentPassthrough(0) - , mCurrentComponent(0) - { - std::string source = mParent->getSource(); - int type = mParent->getType(); - std::string basePath = mParent->getBasePath(); - size_t pos; - - bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( - Factory::getInstance ().getCacheFolder () + "/" + mName); - bool writeCache = Factory::getInstance ().getWriteSourceCache (); - - - if (readCache) - { - std::ifstream ifs( std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str() ); - std::stringstream ss; - ss << ifs.rdbuf(); - source = ss.str(); - } - else - { - std::vector definitions; - - if (mParent->getType() == GPT_Vertex) - definitions.push_back("SH_VERTEX_SHADER"); - else - definitions.push_back("SH_FRAGMENT_SHADER"); - definitions.push_back(convertLang(Factory::getInstance().getCurrentLanguage())); - - parse(source, properties); - - if (Factory::getInstance ().getShaderDebugOutputEnabled ()) - writeDebugFile(source, name + ".pre"); - - // why do we need our own preprocessor? there are several custom commands available in the shader files - // (for example for binding uniforms to properties or auto constants) - more below. it is important that these - // commands are _only executed if the specific code path actually "survives" the compilation. - // thus, we run the code through a preprocessor first to remove the parts that are unused because of - // unmet #if conditions (or other preprocessor directives). - source = Preprocessor::preprocess(source, basePath, definitions, name); - - // parse counter - std::map counters; - while (true) - { - pos = source.find("@shCounter"); - if (pos == std::string::npos) - break; - - size_t end = source.find(")", pos); - - std::vector args = extractMacroArguments (pos, source); - assert(args.size()); - - int index = boost::lexical_cast(args[0]); - - if (counters.find(index) == counters.end()) - counters[index] = 0; - - source.replace(pos, (end+1)-pos, boost::lexical_cast(counters[index]++)); - } - - // parse passthrough declarations - while (true) - { - pos = source.find("@shAllocatePassthrough"); - if (pos == std::string::npos) - break; - - if (mCurrentPassthrough > 7) - throw std::runtime_error ("too many passthrough's requested (max 8)"); - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t end = source.find(")", pos); - - Passthrough passthrough; - - passthrough.num_components = boost::lexical_cast(args[0]); - assert (passthrough.num_components != 0); - - std::string passthroughName = args[1]; - passthrough.lang = Factory::getInstance().getCurrentLanguage (); - passthrough.component_start = mCurrentComponent; - passthrough.passthrough_number = mCurrentPassthrough; - - mPassthroughMap[passthroughName] = passthrough; - - mCurrentComponent += passthrough.num_components; - if (mCurrentComponent > 3) - { - mCurrentComponent -= 4; - ++mCurrentPassthrough; - } - - source.erase(pos, (end+1)-pos); - } - - // passthrough assign - while (true) - { - pos = source.find("@shPassthroughAssign"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t end = source.find(")", pos); - - std::string passthroughName = args[0]; - std::string assignTo = args[1]; - - assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); - Passthrough& p = mPassthroughMap[passthroughName]; - - source.replace(pos, (end+1)-pos, p.expand_assign(assignTo)); - } - - // passthrough receive - while (true) - { - pos = source.find("@shPassthroughReceive"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 1); - - size_t end = source.find(")", pos); - std::string passthroughName = args[0]; - - assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); - Passthrough& p = mPassthroughMap[passthroughName]; - - source.replace(pos, (end+1)-pos, p.expand_receive()); - } - - // passthrough vertex outputs - while (true) - { - pos = source.find("@shPassthroughVertexOutputs"); - if (pos == std::string::npos) - break; - - std::string result; - for (int i = 0; i < mCurrentPassthrough+1; ++i) - { - // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. - if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) - result += ", out float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); - - /* - else - result += "out vec4 passthrough" + boost::lexical_cast(i) + "; "; - */ - else - result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; - } - - source.replace(pos, std::string("@shPassthroughVertexOutputs").length(), result); - } - - // passthrough fragment inputs - while (true) - { - pos = source.find("@shPassthroughFragmentInputs"); - if (pos == std::string::npos) - break; - - std::string result; - for (int i = 0; i < mCurrentPassthrough+1; ++i) - { - // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. - if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) - result += ", in float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); - /* - else - result += "in vec4 passthrough" + boost::lexical_cast(i) + "; "; - */ - else - result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; - } - - source.replace(pos, std::string("@shPassthroughFragmentInputs").length(), result); - } - } - - // save to cache _here_ - we want to preserve some macros - if (writeCache && !readCache) - { - std::ofstream of (std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str(), std::ios_base::out); - of.write(source.c_str(), source.size()); - of.close(); - } - - - // parse shared parameters - while (true) - { - pos = source.find("@shSharedParameter"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size()); - - size_t end = source.find(")", pos); - - mSharedParameters.push_back(args[0]); - - source.erase(pos, (end+1)-pos); - } - - // parse auto constants - typedef std::map< std::string, std::pair > AutoConstantMap; - AutoConstantMap autoConstants; - while (true) - { - pos = source.find("@shAutoConstant"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() >= 2); - - size_t end = source.find(")", pos); - - std::string autoConstantName, uniformName; - std::string extraData; - - uniformName = args[0]; - autoConstantName = args[1]; - if (args.size() > 2) - extraData = args[2]; - - autoConstants[uniformName] = std::make_pair(autoConstantName, extraData); - - source.erase(pos, (end+1)-pos); - } - - // parse uniform properties - while (true) - { - pos = source.find("@shUniformProperty"); - if (pos == std::string::npos) - break; - - std::vector args = extractMacroArguments (pos, source); - assert(args.size() == 2); - - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string cmd = source.substr(pos, start-pos); - - ValueType vt; - if (cmd == "@shUniformProperty4f") - vt = VT_Vector4; - else if (cmd == "@shUniformProperty3f") - vt = VT_Vector3; - else if (cmd == "@shUniformProperty2f") - vt = VT_Vector2; - else if (cmd == "@shUniformProperty1f") - vt = VT_Float; - else if (cmd == "@shUniformPropertyInt") - vt = VT_Int; - else - throw std::runtime_error ("unsupported command \"" + cmd + "\""); - - - std::string propertyName, uniformName; - uniformName = args[0]; - propertyName = args[1]; - mUniformProperties[uniformName] = std::make_pair(propertyName, vt); - - source.erase(pos, (end+1)-pos); - } - - // parse texture samplers used - while (true) - { - pos = source.find("@shUseSampler"); - if (pos == std::string::npos) - break; - - size_t end = source.find(")", pos); - - mUsedSamplers.push_back(extractMacroArguments (pos, source)[0]); - source.erase(pos, (end+1)-pos); - } - - // convert any left-over @'s to # - boost::algorithm::replace_all(source, "@", "#"); - - Platform* platform = Factory::getInstance().getPlatform(); - - std::string profile; - if (Factory::getInstance ().getCurrentLanguage () == Language_CG) - profile = mParent->getCgProfile (); - else if (Factory::getInstance ().getCurrentLanguage () == Language_HLSL) - profile = mParent->getHlslProfile (); - - - if (type == GPT_Vertex) - mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Vertex, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); - else if (type == GPT_Fragment) - mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Fragment, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); - - - if (Factory::getInstance ().getShaderDebugOutputEnabled ()) - writeDebugFile(source, name); - - if (!mProgram->getSupported()) - { - std::cerr << " Full source code below: \n" << source << std::endl; - mSupported = false; - return; - } - - // set auto constants - for (AutoConstantMap::iterator it = autoConstants.begin(); it != autoConstants.end(); ++it) - { - mProgram->setAutoConstant(it->first, it->second.first, it->second.second); - } - } - - std::string ShaderInstance::getName () - { - return mName; - } - - bool ShaderInstance::getSupported () const - { - return mSupported; - } - - std::vector ShaderInstance::getUsedSamplers() - { - return mUsedSamplers; - } - - void ShaderInstance::setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties) - { - for (UniformMap::iterator it = mUniformProperties.begin(); it != mUniformProperties.end(); ++it) - { - pass->setGpuConstant(mParent->getType(), it->first, it->second.second, properties->getProperty(it->second.first), properties->getContext()); - } - } - - std::vector ShaderInstance::extractMacroArguments (size_t pos, const std::string& source) - { - size_t start = source.find("(", pos); - size_t end = source.find(")", pos); - std::string args = source.substr(start+1, end-(start+1)); - std::vector results; - boost::algorithm::split(results, args, boost::is_any_of(",")); - std::for_each(results.begin(), results.end(), - boost::bind(&boost::trim, - _1, std::locale() )); - return results; - } -} diff --git a/extern/shiny/Main/ShaderInstance.hpp b/extern/shiny/Main/ShaderInstance.hpp deleted file mode 100644 index 76326ce0c3..0000000000 --- a/extern/shiny/Main/ShaderInstance.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef SH_SHADERINSTANCE_H -#define SH_SHADERINSTANCE_H - -#include - -#include "Platform.hpp" - -namespace sh -{ - class ShaderSet; - - typedef std::map< std::string, std::pair > UniformMap; - - struct Passthrough - { - Language lang; ///< language to generate for - - int num_components; ///< e.g. 4 for a float4 - - int passthrough_number; - int component_start; ///< 0 = x - - std::string expand_assign(std::string assignTo); - std::string expand_receive(); - }; - typedef std::map PassthroughMap; - - /** - * @brief A specific instance of a \a ShaderSet with a deterministic shader source - */ - class ShaderInstance - { - public: - ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties); - - std::string getName(); - - bool getSupported () const; - - std::vector getUsedSamplers(); - std::vector getSharedParameters() { return mSharedParameters; } - - void setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties); - - private: - boost::shared_ptr mProgram; - std::string mName; - ShaderSet* mParent; - bool mSupported; ///< shader compilation was sucessful? - - std::vector mUsedSamplers; - ///< names of the texture samplers that are used by this shader - - std::vector mSharedParameters; - - UniformMap mUniformProperties; - ///< uniforms that this depends on, and their property names / value-types - /// @note this lists shared uniform parameters as well - - int mCurrentPassthrough; ///< 0 - x - int mCurrentComponent; ///< 0:x, 1:y, 2:z, 3:w - - PassthroughMap mPassthroughMap; - - std::vector extractMacroArguments (size_t pos, const std::string& source); ///< take a macro invocation and return vector of arguments - - void parse (std::string& source, PropertySetGet* properties); - }; -} - -#endif diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp deleted file mode 100644 index 8fb530d394..0000000000 --- a/extern/shiny/Main/ShaderSet.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "ShaderSet.hpp" - -#include -#include - -#include -#include -#include -#include - -#include "Factory.hpp" - -namespace sh -{ - ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, - const std::string& name, PropertySetGet* globalSettingsPtr) - : mBasePath(basePath) - , mName(name) - , mCgProfile(cgProfile) - , mHlslProfile(hlslProfile) - { - if (type == "vertex") - mType = GPT_Vertex; - else // if (type == "fragment") - mType = GPT_Fragment; - - std::ifstream stream(sourceFile.c_str(), std::ifstream::in); - std::stringstream buffer; - - boost::filesystem::path p (sourceFile); - p = p.branch_path(); - mBasePath = p.string(); - - buffer << stream.rdbuf(); - stream.close(); - mSource = buffer.str(); - parse(); - } - - ShaderSet::~ShaderSet() - { - for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it) - { - sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName()); - } - } - - void ShaderSet::parse() - { - std::string currentToken; - bool tokenIsRecognized = false; - bool isInBraces = false; - for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it) - { - char c = *it; - if (((c == ' ') && !isInBraces) || (c == '\n') || - ( ((c == '(') || (c == ')')) - && !tokenIsRecognized)) - { - if (tokenIsRecognized) - { - if (boost::starts_with(currentToken, "@shGlobalSetting")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); - } - else if (boost::starts_with(currentToken, "@shPropertyHasValue")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); - } - else if (boost::starts_with(currentToken, "@shPropertyEqual")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) - && (currentToken.find(',') != std::string::npos)); - size_t start = currentToken.find('(')+1; - size_t end = currentToken.find(','); - mProperties.push_back(currentToken.substr(start, end-start)); - } - else if (boost::starts_with(currentToken, "@shProperty")) - { - assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); - size_t start = currentToken.find('(')+1; - std::string propertyName = currentToken.substr(start, currentToken.find(')')-start); - // if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do - if (propertyName.find("@") == std::string::npos) - mProperties.push_back(propertyName); - } - } - - currentToken = ""; - } - else - { - if (currentToken == "") - { - if (c == '@') - tokenIsRecognized = true; - else - tokenIsRecognized = false; - } - else - { - if (c == '@') - { - // ouch, there are nested macros - // ( for example @shForeach(@shPropertyString(foobar)) ) - currentToken = ""; - } - } - - if (c == '(' && tokenIsRecognized) - isInBraces = true; - else if (c == ')' && tokenIsRecognized) - isInBraces = false; - - currentToken += c; - - } - } - } - - ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties) - { - size_t h = buildHash (properties); - if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end()) - return NULL; - if (mInstances.find(h) == mInstances.end()) - { - ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast(h), properties); - if (!newInstance.getSupported()) - { - mFailedToCompile.push_back(h); - return NULL; - } - mInstances.insert(std::make_pair(h, newInstance)); - } - return &mInstances.find(h)->second; - } - - size_t ShaderSet::buildHash (PropertySetGet* properties) - { - size_t seed = 0; - PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings (); - - for (std::vector::iterator it = mProperties.begin(); it != mProperties.end(); ++it) - { - std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); - boost::hash_combine(seed, v); - } - for (std::vector ::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it) - { - boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); - } - for (std::vector::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) - { - std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); - boost::hash_combine(seed, static_cast(v != "")); - } - boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); - return seed; - } - - PropertySetGet* ShaderSet::getCurrentGlobalSettings() const - { - return Factory::getInstance ().getCurrentGlobalSettings (); - } - - std::string ShaderSet::getBasePath() const - { - return mBasePath; - } - - std::string ShaderSet::getSource() const - { - return mSource; - } - - std::string ShaderSet::getCgProfile() const - { - return mCgProfile; - } - - std::string ShaderSet::getHlslProfile() const - { - return mHlslProfile; - } - - int ShaderSet::getType() const - { - return mType; - } -} diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp deleted file mode 100644 index 988c6769fa..0000000000 --- a/extern/shiny/Main/ShaderSet.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SH_SHADERSET_H -#define SH_SHADERSET_H - -#include -#include -#include - -#include "ShaderInstance.hpp" - -namespace sh -{ - class PropertySetGet; - - typedef std::map ShaderInstanceMap; - - /** - * @brief Contains possible shader permutations of a single uber-shader (represented by one source file) - */ - class ShaderSet - { - public: - ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, - const std::string& name, PropertySetGet* globalSettingsPtr); - ~ShaderSet(); - - /// Retrieve a shader instance for the given properties. \n - /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n - /// Otherwise, creates a new \a ShaderInstance (i.e. compiles a new shader). \n - /// Might also return NULL if the shader failed to compile. \n - /// @note Only the properties that actually affect the shader source are taken into consideration here, - /// so it does not matter if you pass any extra properties that the shader does not care about. - ShaderInstance* getInstance (PropertySetGet* properties); - - private: - PropertySetGet* getCurrentGlobalSettings() const; - std::string getBasePath() const; - std::string getSource() const; - std::string getCgProfile() const; - std::string getHlslProfile() const; - int getType() const; - - friend class ShaderInstance; - - private: - GpuProgramType mType; - std::string mSource; - std::string mBasePath; - std::string mCgProfile; - std::string mHlslProfile; - std::string mName; - - std::vector mFailedToCompile; - - std::vector mGlobalSettings; ///< names of the global settings that affect the shader source - std::vector mProperties; ///< names of the per-material properties that affect the shader source - - std::vector mPropertiesToExist; - ///< same as mProperties, however in this case, it is only relevant if the property is empty or not - /// (we don't care about the value) - - ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance - - void parse(); ///< find out which properties and global settings affect the shader source - - size_t buildHash (PropertySetGet* properties); - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp deleted file mode 100644 index e718540197..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#include "OgreGpuProgram.hpp" - -#include - -#include -#include -#include - -namespace sh -{ - OgreGpuProgram::OgreGpuProgram( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, const std::string& lang, - const std::string& resourceGroup) - : GpuProgram() - { - Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton(); - assert (mgr.getByName(name).isNull() && "Vertex program already exists"); - - Ogre::GpuProgramType t; - if (type == GPT_Vertex) - t = Ogre::GPT_VERTEX_PROGRAM; - else - t = Ogre::GPT_FRAGMENT_PROGRAM; - - mProgram = mgr.createProgram(name, resourceGroup, lang, t); - if (lang != "glsl" && lang != "glsles") - mProgram->setParameter("entry_point", "main"); - if (lang == "hlsl") - mProgram->setParameter("target", profile); - else if (lang == "cg") - mProgram->setParameter("profiles", profile); - - mProgram->setSource(source); - mProgram->load(); - - if (mProgram.isNull() || !mProgram->isSupported()) - std::cerr << "Failed to compile shader \"" << name << "\". Consider the OGRE log for more information." << std::endl; - } - - bool OgreGpuProgram::getSupported() - { - return (!mProgram.isNull() && mProgram->isSupported()); - } - - void OgreGpuProgram::setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo) - { - assert (!mProgram.isNull() && mProgram->isSupported()); - const Ogre::GpuProgramParameters::AutoConstantDefinition* d = Ogre::GpuProgramParameters::getAutoConstantDefinition(autoConstantName); - - if (!d) - throw std::runtime_error ("can't find auto constant with name \"" + autoConstantName + "\""); - Ogre::GpuProgramParameters::AutoConstantType t = d->acType; - - // this simplifies debugging for CG a lot. - mProgram->getDefaultParameters()->setIgnoreMissingParams(true); - - if (d->dataType == Ogre::GpuProgramParameters::ACDT_NONE) - mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, 0); - else if (d->dataType == Ogre::GpuProgramParameters::ACDT_INT) - mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, extraInfo == "" ? 0 : boost::lexical_cast(extraInfo)); - else if (d->dataType == Ogre::GpuProgramParameters::ACDT_REAL) - mProgram->getDefaultParameters()->setNamedAutoConstantReal (name, t, extraInfo == "" ? 0.f : boost::lexical_cast(extraInfo)); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp deleted file mode 100644 index 42673ed9b4..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SH_OGREGPUPROGRAM_H -#define SH_OGREGPUPROGRAM_H - -#include - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreGpuProgram : public GpuProgram - { - public: - OgreGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, const std::string& lang, - const std::string& resourceGroup); - - virtual bool getSupported(); - - virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = ""); - - private: - Ogre::HighLevelGpuProgramPtr mProgram; - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp deleted file mode 100644 index 04560e1f9e..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "OgreMaterial.hpp" - -#include -#include -#include - -#include "OgrePass.hpp" -#include "OgreMaterialSerializer.hpp" -#include "OgrePlatform.hpp" - -namespace sh -{ - static const std::string sDefaultTechniqueName = "SH_DefaultTechnique"; - - OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) - : Material() - { - mName = name; - assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); - mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); - mMaterial->removeAllTechniques(); - mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); - mMaterial->compile(); - } - - void OgreMaterial::ensureLoaded() - { - if (mMaterial.isNull()) - mMaterial = Ogre::MaterialManager::getSingleton().getByName(mName); - } - - bool OgreMaterial::isUnreferenced() - { - // Resource system internals hold 3 shared pointers, we hold one, so usecount of 4 means unused - return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1); - } - - void OgreMaterial::unreferenceTextures() - { - mMaterial->unload(); - } - - OgreMaterial::~OgreMaterial() - { - if (!mMaterial.isNull()) - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - - boost::shared_ptr OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) - { - return boost::shared_ptr (new OgrePass (this, configuration, lodIndex)); - } - - void OgreMaterial::removeAll () - { - if (mMaterial.isNull()) - return; - mMaterial->removeAllTechniques(); - mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); - mMaterial->compile(); - } - - void OgreMaterial::setLodLevels (const std::string& lodLevels) - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - s.setMaterialProperty ("lod_values", lodLevels, mMaterial); - } - - bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex) - { - for (int i=0; igetNumTechniques(); ++i) - { - if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) - return false; - } - - Ogre::Technique* t = mMaterial->createTechnique(); - t->setSchemeName (name); - t->setLodIndex (lodIndex); - if (mShadowCasterMaterial != "") - t->setShadowCasterMaterial(mShadowCasterMaterial); - - mMaterial->compile(); - - return true; - } - - Ogre::MaterialPtr OgreMaterial::getOgreMaterial () - { - return mMaterial; - } - - Ogre::Technique* OgreMaterial::getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex) - { - for (int i=0; igetNumTechniques(); ++i) - { - if (mMaterial->getTechnique(i)->getSchemeName() == configurationName && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) - { - return mMaterial->getTechnique(i); - } - } - - // Prepare and throw error message - std::stringstream message; - message << "Could not find configurationName '" << configurationName - << "' and lodIndex " << lodIndex; - - throw std::runtime_error(message.str()); - } - - void OgreMaterial::setShadowCasterMaterial (const std::string& name) - { - mShadowCasterMaterial = name; - for (int i=0; igetNumTechniques(); ++i) - { - mMaterial->getTechnique(i)->setShadowCasterMaterial(mShadowCasterMaterial); - } - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp deleted file mode 100644 index 67a2c26e86..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SH_OGREMATERIAL_H -#define SH_OGREMATERIAL_H - -#include - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreMaterial : public Material - { - public: - OgreMaterial (const std::string& name, const std::string& resourceGroup); - virtual ~OgreMaterial(); - - virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex); - virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); - - virtual bool isUnreferenced(); - virtual void unreferenceTextures(); - virtual void ensureLoaded(); - - virtual void removeAll (); - - Ogre::MaterialPtr getOgreMaterial(); - - virtual void setLodLevels (const std::string& lodLevels); - - Ogre::Technique* getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex = 0); - - virtual void setShadowCasterMaterial (const std::string& name); - - private: - Ogre::MaterialPtr mMaterial; - std::string mName; - - std::string mShadowCasterMaterial; - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp deleted file mode 100644 index f45e641557..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "OgreMaterialSerializer.hpp" - -#include - -#include - -namespace sh -{ - void OgreMaterialSerializer::reset() - { - mScriptContext.section = Ogre::MSS_NONE; - mScriptContext.material.setNull(); - mScriptContext.technique = 0; - mScriptContext.pass = 0; - mScriptContext.textureUnit = 0; - mScriptContext.program.setNull(); - mScriptContext.lineNo = 0; - mScriptContext.filename.clear(); - mScriptContext.techLev = -1; - mScriptContext.passLev = -1; - mScriptContext.stateLev = -1; - } - - bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) - { - // workaround https://ogre3d.atlassian.net/browse/OGRE-158 - if (param == "transparent_sorting" && value == "force") - { - pass->setTransparentSortingForced(true); - return true; - } - - reset(); - - mScriptContext.section = Ogre::MSS_PASS; - mScriptContext.pass = pass; - - if (mPassAttribParsers.find (param) == mPassAttribParsers.end()) - return false; - else - { - mPassAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } - - bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) - { - // quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames - if (param == "num_mipmaps") - { - t->setNumMipmaps(Ogre::StringConverter::parseInt(value)); - return true; - } - - reset(); - - mScriptContext.section = Ogre::MSS_TEXTUREUNIT; - mScriptContext.textureUnit = t; - - if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end()) - return false; - else - { - mTextureUnitAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } - - bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m) - { - reset(); - - mScriptContext.section = Ogre::MSS_MATERIAL; - mScriptContext.material = m; - - if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end()) - return false; - else - { - mMaterialAttribParsers.find(param)->second(value, mScriptContext); - return true; - } - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp deleted file mode 100644 index acfc5a362f..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SH_OGREMATERIALSERIALIZER_H -#define SH_OGREMATERIALSERIALIZER_H - -#include - -namespace Ogre -{ - class Pass; -} - -namespace sh -{ - /** - * @brief This class allows me to let Ogre handle the pass & texture unit properties - */ - class OgreMaterialSerializer : public Ogre::MaterialSerializer - { - public: - bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass); - bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t); - bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m); - - private: - void reset(); - }; - -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp deleted file mode 100644 index 5cd501094f..0000000000 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include - -#include "OgrePass.hpp" - -#include -#include - -#include "OgreTextureUnitState.hpp" -#include "OgreGpuProgram.hpp" -#include "OgreMaterial.hpp" -#include "OgreMaterialSerializer.hpp" -#include "OgrePlatform.hpp" - -namespace sh -{ - OgrePass::OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex) - : Pass() - { - Ogre::Technique* t = parent->getOgreTechniqueForConfiguration(configuration, lodIndex); - mPass = t->createPass(); - } - - boost::shared_ptr OgrePass::createTextureUnitState (const std::string& name) - { - return boost::shared_ptr (new OgreTextureUnitState (this, name)); - } - - void OgrePass::assignProgram (GpuProgramType type, const std::string& name) - { - if (type == GPT_Vertex) - mPass->setVertexProgram (name); - else if (type == GPT_Fragment) - mPass->setFragmentProgram (name); - else - throw std::runtime_error("unsupported GpuProgramType"); - } - - Ogre::Pass* OgrePass::getOgrePass () - { - return mPass; - } - - bool OgrePass::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) - { - if (((typeid(*value) == typeid(StringValue)) || typeid(*value) == typeid(LinkedValue)) - && retrieveValue(value, context).get() == "default") - return true; - - if (name == "vertex_program") - return true; // handled already - else if (name == "fragment_program") - return true; // handled already - else - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - return s.setPassProperty (name, retrieveValue(value, context).get(), mPass); - } - } - - void OgrePass::setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) - { - Ogre::GpuProgramParametersSharedPtr params; - if (type == GPT_Vertex) - { - if (!mPass->hasVertexProgram ()) - return; - params = mPass->getVertexProgramParameters(); - } - else if (type == GPT_Fragment) - { - if (!mPass->hasFragmentProgram ()) - return; - params = mPass->getFragmentProgramParameters(); - } - - if (vt == VT_Float) - params->setNamedConstant (name, retrieveValue(value, context).get()); - else if (vt == VT_Int) - params->setNamedConstant (name, retrieveValue(value, context).get()); - else if (vt == VT_Vector4) - { - Vector4 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, v.mW)); - } - else if (vt == VT_Vector3) - { - Vector3 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, 1.0)); - } - else if (vt == VT_Vector2) - { - Vector2 v = retrieveValue(value, context); - params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, 1.0, 1.0)); - } - else - throw std::runtime_error ("unsupported constant type"); - } - - void OgrePass::addSharedParameter (int type, const std::string& name) - { - Ogre::GpuProgramParametersSharedPtr params; - if (type == GPT_Vertex) - params = mPass->getVertexProgramParameters(); - else if (type == GPT_Fragment) - params = mPass->getFragmentProgramParameters(); - - try - { - params->addSharedParameters (name); - } - catch (Ogre::Exception& ) - { - std::stringstream msg; - msg << "Could not create a shared parameter instance for '" - << name << "'. Make sure this shared parameter has a value set (via Factory::setSharedParameter)!"; - throw std::runtime_error(msg.str()); - } - } - - void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index) - { - Ogre::GpuProgramParametersSharedPtr params; - if (programType == GPT_Vertex) - params = mPass->getVertexProgramParameters(); - else if (programType == GPT_Fragment) - params = mPass->getFragmentProgramParameters(); - - params->setNamedConstant(name, index); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgrePass.hpp b/extern/shiny/Platforms/Ogre/OgrePass.hpp deleted file mode 100644 index e7cfd4e337..0000000000 --- a/extern/shiny/Platforms/Ogre/OgrePass.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef SH_OGREPASS_H -#define SH_OGREPASS_H - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgreMaterial; - - class OgrePass : public Pass - { - public: - OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); - - virtual boost::shared_ptr createTextureUnitState (const std::string& name); - virtual void assignProgram (GpuProgramType type, const std::string& name); - - Ogre::Pass* getOgrePass(); - - virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context); - - virtual void addSharedParameter (int type, const std::string& name); - virtual void setTextureUnitIndex (int programType, const std::string& name, int index); - - private: - Ogre::Pass* mPass; - - protected: - virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); - }; -} - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp deleted file mode 100644 index aa01c8ba14..0000000000 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include - -#include "OgrePlatform.hpp" - -#include -#include -#include -#include - -#include "OgreMaterial.hpp" -#include "OgreGpuProgram.hpp" -#include "OgreMaterialSerializer.hpp" - -#include "../../Main/MaterialInstance.hpp" -#include "../../Main/Factory.hpp" - -namespace -{ - std::string convertLang (sh::Language lang) - { - if (lang == sh::Language_CG) - return "cg"; - else if (lang == sh::Language_HLSL) - return "hlsl"; - else if (lang == sh::Language_GLSL) - return "glsl"; - else if (lang == sh::Language_GLSLES) - return "glsles"; - throw std::runtime_error ("invalid language, valid are: cg, hlsl, glsl, glsles"); - } -} - -namespace sh -{ - OgreMaterialSerializer* OgrePlatform::sSerializer = 0; - - OgrePlatform::OgrePlatform(const std::string& resourceGroupName, const std::string& basePath) - : Platform(basePath) - , mResourceGroup(resourceGroupName) - { - Ogre::MaterialManager::getSingleton().addListener(this); - - if (supportsShaderSerialization()) - Ogre::GpuProgramManager::getSingletonPtr()->setSaveMicrocodesToCache(true); - - sSerializer = new OgreMaterialSerializer(); - } - - OgreMaterialSerializer& OgrePlatform::getSerializer() - { - assert(sSerializer); - return *sSerializer; - } - - OgrePlatform::~OgrePlatform () - { - Ogre::MaterialManager::getSingleton().removeListener(this); - - delete sSerializer; - } - - bool OgrePlatform::isProfileSupported (const std::string& profile) - { - return Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(profile); - } - - bool OgrePlatform::supportsShaderSerialization () - { - #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) - return true; - #else - return Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") == std::string::npos; - #endif - } - - bool OgrePlatform::supportsMaterialQueuedListener () - { - return true; - } - - boost::shared_ptr OgrePlatform::createMaterial (const std::string& name) - { - OgreMaterial* material = new OgreMaterial(name, mResourceGroup); - return boost::shared_ptr (material); - } - - void OgrePlatform::destroyGpuProgram(const std::string &name) - { - Ogre::HighLevelGpuProgramManager::getSingleton().remove(name); - } - - boost::shared_ptr OgrePlatform::createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang) - { - OgreGpuProgram* prog = new OgreGpuProgram (type, compileArguments, name, profile, source, convertLang(lang), mResourceGroup); - return boost::shared_ptr (static_cast(prog)); - } - - Ogre::Technique* OgrePlatform::handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend) - { - MaterialInstance* m = fireMaterialRequested(originalMaterial->getName(), schemeName, lodIndex); - if (m) - { - OgreMaterial* _m = static_cast(m->getMaterial()); - return _m->getOgreTechniqueForConfiguration (schemeName, lodIndex); - } - else - return 0; // material does not belong to us - } - - void OgrePlatform::serializeShaders (const std::string& file) - { - #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) - if (Ogre::GpuProgramManager::getSingleton().isCacheDirty()) - #endif - { - std::fstream output; - output.open(file.c_str(), std::ios::out | std::ios::binary); - Ogre::DataStreamPtr shaderCache (OGRE_NEW Ogre::FileStreamDataStream(file, &output, false)); - Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCache); - } - } - - void OgrePlatform::deserializeShaders (const std::string& file) - { - std::ifstream inp; - inp.open(file.c_str(), std::ios::in | std::ios::binary); - Ogre::DataStreamPtr shaderCache(OGRE_NEW Ogre::FileStreamDataStream(file, &inp, false)); - Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(shaderCache); - } - - void OgrePlatform::setSharedParameter (const std::string& name, PropertyValuePtr value) - { - Ogre::GpuSharedParametersPtr params; - if (mSharedParameters.find(name) == mSharedParameters.end()) - { - params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); - - Ogre::GpuConstantType type; - if (typeid(*value) == typeid(Vector4)) - type = Ogre::GCT_FLOAT4; - else if (typeid(*value) == typeid(Vector3)) - type = Ogre::GCT_FLOAT3; - else if (typeid(*value) == typeid(Vector2)) - type = Ogre::GCT_FLOAT2; - else if (typeid(*value) == typeid(FloatValue)) - type = Ogre::GCT_FLOAT1; - else if (typeid(*value) == typeid(IntValue)) - type = Ogre::GCT_INT1; - else - throw std::runtime_error("unexpected type"); - params->addConstantDefinition(name, type); - mSharedParameters[name] = params; - } - else - params = mSharedParameters.find(name)->second; - - Ogre::Vector4 v (1.0, 1.0, 1.0, 1.0); - if (typeid(*value) == typeid(Vector4)) - { - Vector4 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - v.z = vec.mZ; - v.w = vec.mW; - } - else if (typeid(*value) == typeid(Vector3)) - { - Vector3 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - v.z = vec.mZ; - } - else if (typeid(*value) == typeid(Vector2)) - { - Vector2 vec = retrieveValue(value, NULL); - v.x = vec.mX; - v.y = vec.mY; - } - else if (typeid(*value) == typeid(FloatValue)) - v.x = retrieveValue(value, NULL).get(); - else if (typeid(*value) == typeid(IntValue)) - v.x = static_cast(retrieveValue(value, NULL).get()); - else - throw std::runtime_error ("unsupported property type for shared parameter \"" + name + "\""); - params->setNamedConstant(name, v); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp deleted file mode 100644 index d3a1a83608..0000000000 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef SH_OGREPLATFORM_H -#define SH_OGREPLATFORM_H - -/** - * @addtogroup Platforms - * @{ - */ - -/** - * @addtogroup Ogre - * A set of classes to interact with Ogre's material system - * @{ - */ - -#include "../../Main/Platform.hpp" - -#include -#include - -namespace sh -{ - class OgreMaterialSerializer; - - class OgrePlatform : public Platform, public Ogre::MaterialManager::Listener - { - public: - OgrePlatform (const std::string& resourceGroupName, const std::string& basePath); - virtual ~OgrePlatform (); - - virtual Ogre::Technique* handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend); - - static OgreMaterialSerializer& getSerializer(); - - private: - virtual bool isProfileSupported (const std::string& profile); - - virtual void serializeShaders (const std::string& file); - virtual void deserializeShaders (const std::string& file); - - virtual boost::shared_ptr createMaterial (const std::string& name); - - virtual boost::shared_ptr createGpuProgram ( - GpuProgramType type, - const std::string& compileArguments, - const std::string& name, const std::string& profile, - const std::string& source, Language lang); - - virtual void destroyGpuProgram (const std::string& name); - - virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); - - friend class ShaderInstance; - friend class Factory; - - protected: - virtual bool supportsShaderSerialization (); - virtual bool supportsMaterialQueuedListener (); - - std::string mResourceGroup; - - static OgreMaterialSerializer* sSerializer; - - std::map mSharedParameters; - }; -} - -/** - * @} - * @} - */ - -#endif diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp deleted file mode 100644 index ad8e6d2b03..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "OgreTextureUnitState.hpp" - -#include - -#include -#include - -#include "OgrePass.hpp" -#include "OgrePlatform.hpp" -#include "OgreMaterialSerializer.hpp" - -namespace sh -{ - OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name) - : TextureUnitState() - { - mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); - mTextureUnitState->setName(name); - } - - bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) - { - OgreMaterialSerializer& s = OgrePlatform::getSerializer(); - - if (name == "texture_alias") - { - // texture alias in this library refers to something else than in ogre - // delegate up - return TextureUnitState::setPropertyOverride (name, value, context); - } - else if (name == "direct_texture") - { - setTextureName (retrieveValue(value, context).get()); - return true; - } - else if (name == "anim_texture2") - { - std::string val = retrieveValue(value, context).get(); - std::vector tokens; - boost::split(tokens, val, boost::is_any_of(" ")); - assert(tokens.size() == 3); - std::string texture = tokens[0]; - int frames = boost::lexical_cast(tokens[1]); - float duration = boost::lexical_cast(tokens[2]); - - std::vector frameTextures; - for (int i=0; isetAnimatedTextureName(&frameTextures[0], frames, duration); - return true; - } - else if (name == "create_in_ffp") - return true; // handled elsewhere - - return s.setTextureUnitProperty (name, retrieveValue(value, context).get(), mTextureUnitState); - } - - void OgreTextureUnitState::setTextureName (const std::string& textureName) - { - mTextureUnitState->setTextureName(textureName); - } -} diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp deleted file mode 100644 index 0f1914f62e..0000000000 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SH_OGRETEXTUREUNITSTATE_H -#define SH_OGRETEXTUREUNITSTATE_H - -#include - -#include "../../Main/Platform.hpp" - -namespace sh -{ - class OgrePass; - - class OgreTextureUnitState : public TextureUnitState - { - public: - OgreTextureUnitState (OgrePass* parent, const std::string& name); - - virtual void setTextureName (const std::string& textureName); - - private: - Ogre::TextureUnitState* mTextureUnitState; - - protected: - virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); - }; -} - -#endif diff --git a/extern/shiny/Readme.txt b/extern/shiny/Readme.txt deleted file mode 100644 index 6133219906..0000000000 --- a/extern/shiny/Readme.txt +++ /dev/null @@ -1,33 +0,0 @@ -shiny - a shader and material management library for OGRE - -FEATURES - -- High-level layer on top of OGRE's material system. It allows you to generate multiple techniques for all your materials from a set of high-level per-material properties. - -- Several available Macros in shader source files. Just a few examples of the possibilities: binding OGRE auto constants, binding uniforms to material properties, foreach loops (repeat shader source a given number of times), retrieving per-material properties in an #if condition, automatic packing for vertex to fragment passthroughs. These macros allow you to generate even very complex shaders (for example the Ogre::Terrain shader) without assembling them in C++ code. - -- Integrated preprocessor (no, I didn't reinvent the wheel, I used boost::wave which turned out to be an excellent choice) that allows me to blend out macros that shouldn't be in use because e.g. the shader permutation doesn't need this specific feature. - -- User settings integration. They can be set by a C++ interface and retrieved through a macro in shader files. - -- Automatic handling of shader permutations, i.e. shaders are shared between materials in a smart way. - -- An optional "meta-language" (well, actually it's just a small header with some conditional defines) that you may use to compile the same shader source for different target languages. If you don't like it, you can still code in GLSL / CG etc separately. You can also switch between the languages at runtime. - -- On-demand material and shader creation. It uses Ogre's material listener to compile the shaders as soon as they are needed for rendering, and not earlier. - -- Shader changes are fully dynamic and real-time. Changing a user setting will recompile all shaders affected by this setting when they are next needed. - -- Serialization system that extends Ogre's material script system, it uses Ogre's script parser, but also adds some additional properties that are not available in Ogre's material system. - -- A concept called "Configuration" allowing you to create a different set of your shaders, doing the same thing except for some minor differences: the properties that are overridden by the active configuration. Possible uses for this are using simpler shaders (no shadows, no fog etc) when rendering for example realtime reflections or a minimap. You can easily switch between configurations by changing the active Ogre material scheme (for example on a viewport level). - -- Fixed function support. You can globally enable or disable shaders at any time, and for texture units you can specify if they're only needed for the shader-based path (e.g. normal maps) or if they should also be created in the fixed function path. - -LICENSE - -see License.txt - -AUTHOR - -scrawl diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 492a6323b8..eaf92c6734 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,6 @@ set(OENGINE_OGRE #ogre/renderer.cpp ogre/lights.cpp - ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp deleted file mode 100644 index 741b672ff1..0000000000 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "selectionbuffer.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -namespace OEngine -{ -namespace Render -{ - - SelectionBuffer::SelectionBuffer(Ogre::Camera *camera, int sizeX, int sizeY, int visibilityFlags) - : mCamera(camera) - , mVisibilityFlags(visibilityFlags) - { - mTexture = Ogre::TextureManager::getSingleton().createManual("SelectionBuffer", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, sizeX, sizeY, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET, this); - - setupRenderTarget(); - - mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f); - } - - void SelectionBuffer::setupRenderTarget() - { - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - mRenderTarget->removeAllViewports(); - Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); - vp->setShadowsEnabled(false); - vp->setMaterialScheme("selectionbuffer"); - if (mVisibilityFlags != 0) - vp->setVisibilityMask (mVisibilityFlags); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated (false); - } - - void SelectionBuffer::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - - mRenderTarget = NULL; - - // Don't need to re-render texture, because we have a copy in system memory (mBuffer) - } - - SelectionBuffer::~SelectionBuffer() - { - Ogre::TextureManager::getSingleton ().remove("SelectionBuffer"); - } - - void SelectionBuffer::update () - { - Ogre::MaterialManager::getSingleton ().addListener (this); - - mTexture->load(); - if (mRenderTarget == NULL) - setupRenderTarget(); - - mRenderTarget->update(); - - Ogre::MaterialManager::getSingleton ().removeListener (this); - - mTexture->convertToImage(mBuffer); - } - - int SelectionBuffer::getSelected(int xPos, int yPos) - { - Ogre::ColourValue clr = mBuffer.getColourAt (xPos, yPos, 0); - clr.a = 1; - if (mColourMap.find(clr) != mColourMap.end()) - return mColourMap[clr]; - else - return -1; // nothing selected - } - - Ogre::Technique* SelectionBuffer::handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend) - { - if (schemeName == "selectionbuffer") - { - sh::Factory::getInstance ()._ensureMaterial ("SelectionColour", "Default"); - - Ogre::MaterialPtr m = Ogre::MaterialManager::getSingleton ().getByName("SelectionColour"); - - - if(typeid(*rend) == typeid(Ogre::SubEntity)) - { - const Ogre::SubEntity *subEntity = static_cast(rend); - int id = Ogre::any_cast(subEntity->getParent ()->getUserObjectBindings().getUserAny()); - bool found = false; - Ogre::ColourValue colour; - for (std::map::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it) - { - if (it->second == id) - { - found = true; - colour = it->first; - } - } - - - if (!found) - { - getNextColour(); - const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(mCurrentColour.r, mCurrentColour.g, mCurrentColour.b, 1.0)); - mColourMap[mCurrentColour] = id; - } - else - { - const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(colour.r, colour.g, colour.b, 1.0)); - } - - assert(m->getTechnique(1)); - return m->getTechnique(1); - } - else - { - m = Ogre::MaterialManager::getSingleton().getByName("NullMaterial"); - if(m.isNull()) - { - m = Ogre::MaterialManager::getSingleton().create("NullMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - m->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true); - m->getTechnique(0)->getPass(0)->setDepthFunction(Ogre::CMPF_ALWAYS_FAIL); - } - return m->getTechnique(0); - } - } - return NULL; - } - - void SelectionBuffer::getNextColour () - { - Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); - - if (mCurrentColour.getAsARGB () == color) - { - getNextColour(); - return; - } - - mCurrentColour.setAsARGB(color); - mCurrentColour.a = 1; - } - - -} -} diff --git a/libs/openengine/ogre/selectionbuffer.hpp b/libs/openengine/ogre/selectionbuffer.hpp deleted file mode 100644 index 9bdc4c137b..0000000000 --- a/libs/openengine/ogre/selectionbuffer.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef OENGINE_SELECTIONBUFFER_H -#define OENGINE_SELECTIONBUFFER_H - - -#include -#include -#include -#include - -namespace OEngine -{ -namespace Render -{ - - struct cmp_ColourValue - { - bool operator()(const Ogre::ColourValue &a, const Ogre::ColourValue &b) const - { - return a.getAsBGRA() < b.getAsBGRA(); - } - }; - - class SelectionBuffer : public Ogre::MaterialManager::Listener, public Ogre::ManualResourceLoader - { - public: - SelectionBuffer(Ogre::Camera* camera, int sizeX, int sizeY, int visibilityFlags); - virtual ~SelectionBuffer(); - - int getSelected(int xPos, int yPos); - ///< @return ID of the selected object - - void update(); - - virtual void loadResource(Ogre::Resource* resource); - - virtual Ogre::Technique* handleSchemeNotFound ( - unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, - unsigned short lodIndex, const Ogre::Renderable *rend); - - - private: - Ogre::TexturePtr mTexture; - Ogre::RenderTexture* mRenderTarget; - - Ogre::Image mBuffer; - - std::map mColourMap; - - Ogre::ColourValue mCurrentColour; - - Ogre::Camera* mCamera; - int mVisibilityFlags; - - void getNextColour(); - - void setupRenderTarget(); - }; - -} -} - -#endif From ba3075dc110b5da47ab5e1b3aa069d54fecd444b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 16:28:16 +0200 Subject: [PATCH 0093/1812] Delete nifosgtest --- CMakeLists.txt | 2 - apps/nifosgtest/CMakeLists.txt | 7 -- apps/nifosgtest/test.cpp | 162 --------------------------------- 3 files changed, 171 deletions(-) delete mode 100644 apps/nifosgtest/CMakeLists.txt delete mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77bea373fd..5e510b29d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -559,8 +559,6 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/nifosgtest ) - if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt deleted file mode 100644 index 265577d989..0000000000 --- a/apps/nifosgtest/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set (FILES - test.cpp -) - -add_executable (test ${FILES}) - -target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp deleted file mode 100644 index 332867be5d..0000000000 --- a/apps/nifosgtest/test.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#include -#include - -#include - -#include - -// EventHandler to toggle wireframe when 'w' key is pressed -class WireframeKeyHandler : public osgGA::GUIEventHandler -{ -public: - WireframeKeyHandler(osg::Node* node) - : mWireframe(false) - , mNode(node) - { - - } - - virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) - { - switch (adapter.getEventType()) - { - case osgGA::GUIEventAdapter::KEYDOWN: - if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) - { - mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - - // Create a new stateset instead of changing the old one, this alleviates the need to set - // the StateSet to DYNAMIC DataVariance, which would have a performance impact. - - osg::StateSet* stateset = new osg::StateSet; - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - - mNode->setStateSet(stateset); - - return true; - } - default: - break; - } - return false; - } - -private: - bool mWireframe; - osg::Node* mNode; -}; - -int main(int argc, char** argv) -{ - if (argc < 2) - { - std::cout << "Usage: " << argv[0] << " " << std::endl; - return 1; - } - - Files::ConfigurationManager cfgMgr; - boost::program_options::options_description desc(""); - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()); - - boost::program_options::variables_map variables; - cfgMgr.readConfiguration(variables, desc); - - std::vector archives = variables["fallback-archive"].as >(); - bool fsStrict = variables["fs-strict"].as(); - Files::PathContainer dataDirs; - if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); - } - - cfgMgr.processPaths(dataDirs); - - VFS::Manager resourceMgr (fsStrict); - Files::Collections collections (dataDirs, !fsStrict); - - for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) - { - std::string filepath = collections.getPath(*it).string(); - resourceMgr.addArchive(new VFS::BsaArchive(filepath)); - } - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); - } - - resourceMgr.buildIndex(); - - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); - - // For NiStencilProperty - osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); - - osgViewer::Viewer viewer; - - osg::ref_ptr root(new osg::Group()); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - // To prevent lighting issues with scaled meshes - root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - - - //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; - NifOsg::Loader loader; - Resource::TextureManager texMgr(&resourceMgr); - loader.mTextureManager = &texMgr; - newNode->addChild(loader.load(nif)); - - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - root->addChild(trans); - - for (int x=0; x<1;++x) - { - //root->addChild(newNode); - trans->addChild(newNode); - } - - viewer.setSceneData(root); - - viewer.setUpViewInWindow(0, 0, 800, 600); - viewer.realize(); - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); - - // Mask to separate cull visitors from update visitors - viewer.getCamera()->setCullMask(~(0x1)); - - viewer.addEventHandler(new osgViewer::StatsHandler); - - while (!viewer.done()) - { - //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); - - viewer.frame(); - } - - return 0; -} From 31adaf24950dfd4b2d6069e2ef5cb52410bb4c01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:32:52 +0200 Subject: [PATCH 0094/1812] Use simulationTime instead of referenceTime --- components/nifosg/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 76d3c5e62d..463eb9e454 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -70,7 +70,7 @@ FrameTimeSource::FrameTimeSource() float FrameTimeSource::getValue(osg::NodeVisitor *nv) { - return nv->getFrameStamp()->getReferenceTime(); + return nv->getFrameStamp()->getSimulationTime(); } KeyframeController::KeyframeController() From 25f1c1ae764dc93cfc974b75bc2e8330e691d31e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:33:24 +0200 Subject: [PATCH 0095/1812] Remove persistent flag which will be unused --- components/esm/loadstat.cpp | 2 -- components/esm/loadstat.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index ed90b04751..b0ab89bedd 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -10,8 +10,6 @@ namespace ESM void Static::load(ESMReader &esm) { - mPersistent = (esm.getRecordFlags() & 0x0400) != 0; - mModel = esm.getHNString("MODL"); } void Static::save(ESMWriter &esm) const diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 45b05136ad..d912d10583 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,8 +26,6 @@ struct Static std::string mId, mModel; - bool mPersistent; - void load(ESMReader &esm); void save(ESMWriter &esm) const; From e5e1013c519a297aec6c09347c5878b9fae3823c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Apr 2015 17:34:44 +0200 Subject: [PATCH 0096/1812] TextKeys attached to root node as user data, add .kf loading to scenemanager --- components/nifosg/controller.cpp | 7 +- components/nifosg/controller.hpp | 8 +- components/nifosg/nifloader.cpp | 119 ++++++++++++++------------- components/nifosg/nifloader.hpp | 39 +++++++-- components/resource/scenemanager.cpp | 26 +++++- components/resource/scenemanager.hpp | 15 ++++ 6 files changed, 134 insertions(+), 80 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 463eb9e454..5916359c8b 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -477,22 +477,19 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } -SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data, int sourceIndex) +SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data) : KeyframeController(data) - , mSourceIndex(sourceIndex) , mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController() - : mSourceIndex(0) - , mEnabled(false) + : mEnabled(false) { } SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) : KeyframeController(copy, copyop) - , mSourceIndex(copy.mSourceIndex) , mEnabled(copy.mEnabled) { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e58853330..80e6090e49 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -169,14 +169,13 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; }; - // Specialization of KeyframeController that remembers a "source index" for the animation source - // it came from, and can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. + // Specialization that can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from // the relevant animation source. class SourcedKeyframeController : public KeyframeController { public: - SourcedKeyframeController(const Nif::NiKeyframeData* data, int sourceIndex); + SourcedKeyframeController(const Nif::NiKeyframeData* data); SourcedKeyframeController(); SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); @@ -184,12 +183,9 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); - int getSourceIndex() const; - void setEnabled(bool enabled); private: - int mSourceIndex; bool mEnabled; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 555105e354..94885a11b4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -298,6 +298,7 @@ namespace // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files + /* class LoadKfVisitor : public osg::NodeVisitor { public: @@ -332,6 +333,7 @@ namespace std::map mMap; int mSourceIndex; }; + */ // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. @@ -522,19 +524,15 @@ namespace NifOsg sShowMarkers = show; } + bool Loader::getShowMarkers() + { + return sShowMarkers; + } + class LoaderImpl { public: - Resource::TextureManager* mTextureManager; - bool mShowMarkers; - - LoaderImpl(Resource::TextureManager* textureManager, bool showMarkers) - : mTextureManager(textureManager) - , mShowMarkers(showMarkers) - { - } - - void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) + static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { if(nif->numRoots() < 1) { @@ -561,9 +559,7 @@ namespace NifOsg return; } - extractTextKeys(static_cast(extra.getPtr()), textKeys); - - std::map controllerMap; + extractTextKeys(static_cast(extra.getPtr()), target.mTextKeys); extra = extra->extra; Nif::ControllerPtr ctrl = seq->controller; @@ -584,17 +580,17 @@ namespace NifOsg if(key->data.empty()) continue; - controllerMap[strdata->string] = key; - } + osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(key->data.getPtr())); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); - LoadKfVisitor visitor(controllerMap, sourceIndex); - rootNode->accept(visitor); + target.mKeyframeControllers[strdata->string] = callback; + } } - osg::ref_ptr load(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->getUseSkinning()) - return loadAsSkeleton(nif, textKeys); + return loadAsSkeleton(nif, textureManager); if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -605,11 +601,16 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); - osg::ref_ptr created = handleNode(nifNode, NULL, false, std::map(), 0, 0, false, textKeys); + osg::ref_ptr textkeys (new TextKeyMapHolder); + + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, false, std::map(), 0, 0, false, &textkeys->mTextKeys); + + created->getOrCreateUserDataContainer()->addUserObject(textkeys); + return created; } - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, TextKeyMap* textKeys) + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -621,24 +622,28 @@ namespace NifOsg if (nifNode == NULL) nif->fail("First root was not a node, but a " + r->recName); + osg::ref_ptr textkeys (new TextKeyMapHolder); + osg::ref_ptr skel = new osgAnimation::Skeleton; skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy - handleNode(nifNode, skel, true, std::map(), 0, 0, false, textKeys); + handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); + + skel->getOrCreateUserDataContainer()->addUserObject(textkeys); return skel; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; @@ -698,7 +703,7 @@ namespace NifOsg const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - if(sd->string == "MRK" && !mShowMarkers) + if(sd->string == "MRK" && !Loader::getShowMarkers()) { // Marker objects. These meshes are only visible in the editor. skipMeshes = true; @@ -735,7 +740,7 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - applyNodeProperties(nifNode, transformNode, boundTextures, animflags); + applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -767,7 +772,8 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), transformNode, textureManager, + createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -775,7 +781,7 @@ namespace NifOsg return transformNode; } - void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -797,7 +803,7 @@ namespace NifOsg } } - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + static void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -825,7 +831,7 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -852,7 +858,7 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -878,8 +884,8 @@ namespace NifOsg wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); - osg::ref_ptr texture = mTextureManager->getTexture2D(filename, wrapS, wrapT); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); + osg::ref_ptr texture = textureManager->getTexture2D(filename, wrapS, wrapT); textures.push_back(texture); } osg::ref_ptr callback(new FlipController(flipctrl, textures)); @@ -892,7 +898,7 @@ namespace NifOsg } } - void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + static void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); @@ -934,7 +940,7 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + static void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -970,7 +976,7 @@ namespace NifOsg } } - osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) { std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController) @@ -1004,7 +1010,7 @@ namespace NifOsg return emitter; } - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -1100,7 +1106,7 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -1183,7 +1189,7 @@ namespace NifOsg applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -1215,7 +1221,7 @@ namespace NifOsg parentNode->addChild(geode); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1233,7 +1239,7 @@ namespace NifOsg return morphGeom; } - void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); geode->setName(triShape->name); // name will be used for part filtering @@ -1289,8 +1295,8 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, - osg::Node *node, std::map& boundTextures, int animflags) + static void handleProperty(const Nif::Property *property, + osg::Node *node, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1417,13 +1423,13 @@ namespace NifOsg continue; } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mTextureManager->getVFS()); + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, textureManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::Texture2D* texture2d = mTextureManager->getTexture2D(filename, + osg::Texture2D* texture2d = textureManager->getTexture2D(filename, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); @@ -1465,7 +1471,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, node, stateset, animflags); + handleTextureControllers(texprop, node, textureManager, stateset, animflags); } break; } @@ -1482,7 +1488,7 @@ namespace NifOsg } } - void applyMaterialProperties(osg::Node* node, const std::vector& properties, + static void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1550,22 +1556,19 @@ namespace NifOsg }; - osg::ref_ptr Loader::load(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.load(file, textKeys); + return LoaderImpl::load(file, textureManager); } - osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap *textKeys) + osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - LoaderImpl loader(mTextureManager, sShowMarkers); - return loader.loadAsSkeleton(file, textKeys); + return LoaderImpl::loadAsSkeleton(file, textureManager); } - void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys) + void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl loader(mTextureManager, sShowMarkers); - loader.loadKf(kf, rootNode, sourceIndex, textKeys); + LoaderImpl::loadKf(kf, target); } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 716cd1957e..1c403a4fe6 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -6,6 +6,9 @@ #include // NIFFilePtr #include +#include + +#include "controller.hpp" namespace osg { @@ -21,30 +24,52 @@ namespace NifOsg { typedef std::multimap TextKeyMap; + struct TextKeyMapHolder : public osg::Object + { + public: + TextKeyMapHolder() {} + TextKeyMapHolder(const TextKeyMapHolder& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop) + , mTextKeys(copy.mTextKeys) + {} + + TextKeyMap mTextKeys; + + META_Object(NifOsg, TextKeyMapHolder) + + }; + + class KeyframeHolder : public osg::Referenced + { + public: + TextKeyMap mTextKeys; + + std::map > mKeyframeControllers; + }; + /// The main class responsible for loading NIF files into an OSG-Scenegraph. /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. class Loader { public: + // TODO: add text keys as user data on the node /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. - osg::ref_ptr load(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. - osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, TextKeyMap* textKeys = NULL); + static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Load keyframe controllers from the given kf file onto the given scene graph. - /// @param sourceIndex The source index for this animation source, used for identifying - /// which animation source a keyframe controller came from. - void loadKf(Nif::NIFFilePtr kf, osg::Node* rootNode, int sourceIndex, TextKeyMap &textKeys); + /// Load keyframe controllers from the given kf file. + static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. /// These should be hidden ingame, but visible in the editior. /// Default: false. static void setShowMarkers(bool show); - Resource::TextureManager* mTextureManager; + static bool getShowMarkers(); private: diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3f38762caa..e626a9f082 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -82,10 +82,7 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - loader.mTextureManager = mTextureManager; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); - - // TODO: provide way for the user to get textKeys (attach to the node?) + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); mIndex[normalized] = loaded; return loaded; @@ -108,6 +105,27 @@ namespace Resource return cloned; } + osg::ref_ptr SceneManager::getKeyframes(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + KeyframeIndex::iterator it = mKeyframeIndex.find(normalized); + if (it == mKeyframeIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + NifOsg::Loader loader; + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); + loader.loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); + + mKeyframeIndex[normalized] = loaded; + return loaded; + } + else + return it->second; + } + void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 7b3bcb2d54..4d6ad48556 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace Resource { class TextureManager; @@ -17,6 +19,11 @@ namespace VFS class Manager; } +namespace NifOsg +{ + class KeyframeHolder; +} + namespace Resource { @@ -41,6 +48,11 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; + /// Get a read-only copy of the given keyframe file. + osg::ref_ptr getKeyframes(const std::string& name); + + /// Manually release created OpenGL objects for the given graphics context. This may be required + /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); private: @@ -50,6 +62,9 @@ namespace Resource // observer_ptr? typedef std::map > Index; Index mIndex; + + typedef std::map > KeyframeIndex; + KeyframeIndex mKeyframeIndex; }; } From 304d7e544f80e05f992facf6d78d743649c25ba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Apr 2015 19:19:01 +0200 Subject: [PATCH 0097/1812] Optimize RigGeometry to update skinning in CullCallback --- components/nifosg/nifloader.cpp | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 94885a11b4..dd9dbc3282 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -362,6 +362,56 @@ namespace } }; + struct FindNearestParentSkeleton : public osg::NodeVisitor + { + osg::ref_ptr _root; + FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} + void apply(osg::Transform& node) + { + if (_root.valid()) + return; + _root = dynamic_cast(&node); + traverse(node); + } + }; + + // RigGeometry is skinned from a CullCallback to prevent unnecessary updates of culled rig geometries. + // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. + struct UpdateRigGeometry : public osg::Drawable::CullCallback + { + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + { + osgAnimation::RigGeometry* geom = static_cast(drw); + if (!geom) + return false; + if (!geom->getSkeleton() && !geom->getParents().empty()) + { + FindNearestParentSkeleton finder; + if (geom->getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; + geom->getParents()[0]->accept(finder); + + if (!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; + return false; + } + geom->buildVertexInfluenceSet(); + geom->setSkeleton(finder._root.get()); + } + + if (!geom->getSkeleton()) + return false; + + if (geom->getNeedToComputeMatrix()) + geom->computeMatrixFromRootSkeleton(); + + geom->update(); + + return false; + } + }; + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: @@ -1284,6 +1334,10 @@ namespace NifOsg } rig->setInfluenceMap(map); + // Override default update using cull callback instead for efficiency. + rig->setUpdateCallback(NULL); + rig->setCullCallback(new UpdateRigGeometry); + osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix()); From 1eafecd30c99c2a84e48139d5515a65265477114 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 00:02:35 +0200 Subject: [PATCH 0098/1812] Add magic factor as in vanilla MW to gravity affector (Bug #2147) --- components/nifosg/particle.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c86a79af87..143a73e08c 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -183,19 +183,22 @@ void GravityAffector::beginOperate(osgParticle::Program* program) void GravityAffector::operate(osgParticle::Particle *particle, double dt) { + const float magic = 1.6f; switch (mType) { case Type_Wind: - particle->addVelocity(mCachedWorldPositionDirection * mForce * dt); + particle->addVelocity(mCachedWorldPositionDirection * mForce * dt * magic); break; case Type_Point: { osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); diff.normalize(); - particle->addVelocity(diff * mForce * dt); + particle->addVelocity(diff * mForce * dt * magic); break; } } + + // velocity *= e^-[(dist/decay)^2] } Emitter::Emitter() From c4738b11b1afcb4e9374bbeb8c191deb7e1b02bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 00:09:05 +0200 Subject: [PATCH 0099/1812] Identify unknown float in NiGravity --- components/nif/controlled.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 9db0c4a6f8..bf391d388b 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -54,7 +54,10 @@ namespace Nif { Controlled::read(nif); - /*unknown*/nif->getFloat(); + float decay = nif->getFloat(); + if (decay != 0.f) + nif->file->warn("Unhandled gravity decay factor"); + mForce = nif->getFloat(); mType = nif->getUInt(); mPosition = nif->getVector3(); From 74c56556cc474d205757b1f8111c19f6a80d299d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Apr 2015 14:10:05 +0200 Subject: [PATCH 0100/1812] More fixes for scaled particle systems --- components/nifosg/nifloader.cpp | 4 +--- components/nifosg/particle.cpp | 18 ++++++++---------- components/resource/scenemanager.cpp | 1 + 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index dd9dbc3282..2a3d0322d3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -974,7 +974,7 @@ namespace NifOsg } else if (affectors->recType == Nif::RC_NiParticleRotation) { - // unused? + // unused } else std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; @@ -1064,8 +1064,6 @@ namespace NifOsg { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); - // Scaling the particle node should also scale particles, even when the worldspace flag is enabled - partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); const Nif::NiParticleSystemController* partctrl = NULL; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 143a73e08c..c4bf69579f 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -50,8 +50,8 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::MatrixTransform* trans = dynamic_cast(node); osg::Matrix mat = osg::computeLocalToWorld( path ); - mat = osg::Matrix::inverse(mat); mat.orthoNormalize(mat); // don't undo the scale + mat = osg::Matrix::inverse(mat); trans->setMatrix(mat); } traverse(node,nv); @@ -239,6 +239,7 @@ void Emitter::setCounter(osgParticle::Counter *counter) void Emitter::emitParticles(double dt) { osg::Matrix worldToPs; + // maybe this could be optimized by halting at the lowest common ancestor of the particle and emitter nodes osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { @@ -246,14 +247,9 @@ void Emitter::emitParticles(double dt) worldToPs = osg::Matrix::inverse(psToWorld); } - worldToPs.orthoNormalize(worldToPs); - const osg::Matrix& ltw = getLocalToWorldMatrix(); - const osg::Matrix emitterToPs = ltw * worldToPs; + osg::Matrix emitterToPs = ltw * worldToPs; - int n = mCounter->numParticlesToCreate(dt); - - osg::Matrix transform; if (!mTargets.empty()) { int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; @@ -270,9 +266,13 @@ void Emitter::emitParticles(double dt) osg::NodePath path = visitor.mFoundPath; path.erase(path.begin()); - transform = osg::computeLocalToWorld(path); + emitterToPs = osg::computeLocalToWorld(path) * emitterToPs; } + emitterToPs.orthoNormalize(emitterToPs); + + int n = mCounter->numParticlesToCreate(dt); + for (int i=0; icreateParticle(0); @@ -282,8 +282,6 @@ void Emitter::emitParticles(double dt) mShooter->shoot(P); - P->transformPositionVelocity(transform); - P->transformPositionVelocity(emitterToPs); } } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index e626a9f082..ead6a9669f 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -51,6 +51,7 @@ namespace void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { osg::Matrix worldMat = node->getWorldMatrices()[0]; + worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { partsys->getParticle(i)->transformPositionVelocity(worldMat); From df9ea917dd3849d615f1a5a2eb268872a4a14041 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 8 Apr 2015 16:14:52 +0200 Subject: [PATCH 0101/1812] Delete some unused crap --- libs/openengine/misc/list.hpp | 178 ---------------------------------- 1 file changed, 178 deletions(-) delete mode 100644 libs/openengine/misc/list.hpp diff --git a/libs/openengine/misc/list.hpp b/libs/openengine/misc/list.hpp deleted file mode 100644 index bda9cb8de7..0000000000 --- a/libs/openengine/misc/list.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef MISC_LIST_H -#define MISC_LIST_H - -#include - -namespace Misc{ - -/* - A simple and completely allocation-less doubly linked list. The - class only manages pointers to and between elements. It leaving all - memory management to the user. -*/ -template -struct List -{ - List() : head(0), tail(0), totalNum(0) {} - - // Empty the list. - void reset() - { - head = 0; - tail = 0; - totalNum = 0; - } - - // Insert an element at the end of the list. The element cannot be - // part of any other list when this is called. - void insert(Elem *p) - { - if(tail) - { - // There are existing elements. Insert the node at the end of - // the list. - assert(head && totalNum > 0); - tail->next = p; - } - else - { - // This is the first element - assert(head == 0 && totalNum == 0); - head = p; - } - - // These have to be done in either case - p->prev = tail; - p->next = 0; - tail = p; - - totalNum++; - } - - // Remove element from the list. The element MUST be part of the - // list when this is called. - void remove(Elem *p) - { - assert(totalNum > 0); - - if(p->next) - { - // There's an element following us. Set it up correctly. - p->next->prev = p->prev; - assert(tail && tail != p); - } - else - { - // We're the tail - assert(tail == p); - tail = p->prev; - } - - // Now do exactly the same for the previous element - if(p->prev) - { - p->prev->next = p->next; - assert(head && head != p); - } - else - { - assert(head == p); - head = p->next; - } - - totalNum--; - } - - // Pop the first element off the list - Elem *pop() - { - Elem *res = getHead(); - if(res) remove(res); - return res; - } - - // Swap the contents of this list with another of the same type - void swap(List &other) - { - Elem *tmp; - - tmp = head; - head = other.head; - other.head = tmp; - - tmp = tail; - tail = other.tail; - other.tail = tmp; - - unsigned int tmp2 = totalNum; - totalNum = other.totalNum; - other.totalNum = tmp2; - } - - /* Absorb the contents of another list. All the elements from the - list are moved to the end of this list, and the other list is - cleared. - */ - void absorb(List &other) - { - assert(&other != this); - if(other.totalNum) - { - absorb(other.head, other.tail, other.totalNum); - other.reset(); - } - assert(other.totalNum == 0); - } - - /* Absorb a range of elements, endpoints included. The elements are - assumed NOT to belong to any list, but they ARE assumed to be - connected with a chain between them. - - The connection MUST run all the way from 'first' to 'last' - through the ->next pointers, and vice versa through ->prev - pointers. - - The parameter 'num' must give the exact number of elements in the - chain. - - Passing first == last, num == 1 is allowed and is equivalent to - calling insert(). - */ - void absorb(Elem* first, Elem *last, int num) - { - assert(first && last && num>=1); - if(tail) - { - // There are existing elements. Insert the first node at the - // end of the list. - assert(head && totalNum > 0); - tail->next = first; - } - else - { - // This is the first element - assert(head == 0 && totalNum == 0); - head = first; - } - - // These have to be done in either case - first->prev = tail; - last->next = 0; - tail = last; - - totalNum += num; - } - - Elem* getHead() const { return head; } - Elem* getTail() const { return tail; } - unsigned int getNum() const { return totalNum; } - -private: - - Elem *head; - Elem *tail; - unsigned int totalNum; -}; - -} -#endif From 0b77ae43a4ca39e42f8244374e47b11554c4a185 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Apr 2015 16:51:57 +0200 Subject: [PATCH 0102/1812] Minor optimization for particle emitters --- components/nifosg/particle.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c4bf69579f..59a4a981b3 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -238,7 +238,12 @@ void Emitter::setCounter(osgParticle::Counter *counter) void Emitter::emitParticles(double dt) { + int n = mCounter->numParticlesToCreate(dt); + if (n == 0) + return; + osg::Matrix worldToPs; + // maybe this could be optimized by halting at the lowest common ancestor of the particle and emitter nodes osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) @@ -271,8 +276,6 @@ void Emitter::emitParticles(double dt) emitterToPs.orthoNormalize(emitterToPs); - int n = mCounter->numParticlesToCreate(dt); - for (int i=0; icreateParticle(0); From 8b206e0aeda6feee2470a61aa363a79dbe3ba25f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Apr 2015 16:52:38 +0200 Subject: [PATCH 0103/1812] Enable culling for particle emitters & programs Big speedup, though might cause timing inconsistencies that we should fix at some point. --- components/nifosg/nifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2a3d0322d3..b077c32ff8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -954,6 +954,7 @@ namespace NifOsg attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); + program->setCullingActive(true); for (; !affectors.empty(); affectors = affectors->extra) { if (affectors->recType == Nif::RC_NiParticleGrowFade) @@ -1100,6 +1101,7 @@ namespace NifOsg osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + emitter->setCullingActive(true); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -1140,6 +1142,7 @@ namespace NifOsg // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; + updater->setCullingActive(true); updater->addParticleSystem(partsys); parentNode->addChild(updater); From 433e29f297adf6c34ccf3e1883583b6297789f23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 14:34:57 +0200 Subject: [PATCH 0104/1812] MorphGeometry optimizations: static bounding box and vertices updated during cull traversal --- components/nifosg/nifloader.cpp | 101 ++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b077c32ff8..9df27df329 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -379,6 +379,17 @@ namespace // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. struct UpdateRigGeometry : public osg::Drawable::CullCallback { + UpdateRigGeometry() + { + } + + UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateRigGeometry) + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const { osgAnimation::RigGeometry* geom = static_cast(drw); @@ -412,6 +423,59 @@ namespace } }; + // Same for MorphGeometry + struct UpdateMorphGeometry : public osg::Drawable::CullCallback + { + UpdateMorphGeometry() + { + } + + UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateMorphGeometry) + + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + { + osgAnimation::MorphGeometry* geom = static_cast(drw); + if (!geom) + return false; + geom->transformSoftwareMethod(); + return false; + } + }; + + // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box + // every time the morph weights change. To do so we return a maximum containing box that is big enough for all possible combinations of morph targets. + class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + StaticBoundingBoxCallback() + { + } + + StaticBoundingBoxCallback(const osg::BoundingBox& bounds) + : mBoundingBox(bounds) + { + } + + StaticBoundingBoxCallback(const StaticBoundingBoxCallback& copy, const osg::CopyOp& copyop) + : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) + , mBoundingBox(copy.mBoundingBox) + { + } + + virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const + { + return mBoundingBox; + } + + private: + osg::BoundingBox mBoundingBox; + }; + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: @@ -1279,7 +1343,12 @@ namespace NifOsg // No normals available in the MorphData morphGeom->setMorphNormals(false); + morphGeom->setUpdateCallback(NULL); + morphGeom->setCullCallback(new UpdateMorphGeometry); + const std::vector& morphs = morpher->data.getPtr()->mMorphs; + if (!morphs.size()) + return morphGeom; // Note we are not interested in morph 0, which just contains the original vertices for (unsigned int i = 1; i < morphs.size(); ++i) { @@ -1287,6 +1356,38 @@ namespace NifOsg morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); morphGeom->addMorphTarget(morphTarget, 0.f); } + + // build the bounding box containing all possible morph combinations + + std::vector vertBounds(morphs[0].mVertices.size()); + + // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. + // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. + + // Start with zero offsets which will happen when no morphs are applied. + for (unsigned int i=0; isetComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); + return morphGeom; } From 642c1d2d3627ab7d29f959d6e09f4b7448254987 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 15:31:19 +0200 Subject: [PATCH 0105/1812] Build fix --- apps/openmw/mwclass/static.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index dbbe7e43a7..834ce129e3 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -19,11 +19,8 @@ namespace MWClass void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - if (!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent); + renderingInterface.getObjects().insertModel(ptr, model); } } From 591a35b8d717161bd1974ecc57eb63146efaee05 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Apr 2015 23:16:17 +0200 Subject: [PATCH 0106/1812] *very* early version of the LightManager --- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 43 +--- components/sceneutil/attach.cpp | 59 ++--- components/sceneutil/lightmanager.cpp | 309 ++++++++++++++++++++++++++ components/sceneutil/lightmanager.hpp | 105 +++++++++ components/sceneutil/util.cpp | 36 +++ components/sceneutil/util.hpp | 17 ++ components/sceneutil/visitor.hpp | 37 +++ 8 files changed, 542 insertions(+), 66 deletions(-) create mode 100644 components/sceneutil/lightmanager.cpp create mode 100644 components/sceneutil/lightmanager.hpp create mode 100644 components/sceneutil/util.cpp create mode 100644 components/sceneutil/util.hpp create mode 100644 components/sceneutil/visitor.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1debf3495d..abce7020cf 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach + clone attach lightmanager visitor util ) add_component_dir (nif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9df27df329..a5c9b6e2aa 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -41,6 +41,7 @@ #include #include +#include #include "particle.hpp" #include "userdata.hpp" @@ -467,7 +468,9 @@ namespace { } - virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const + META_Object(NifOsg, StaticBoundingBoxCallback) + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return mBoundingBox; } @@ -497,37 +500,6 @@ namespace mBoundSpheres[bonename] = sphere; } - // based off code in osg::Transform - void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) const - { - osg::BoundingSphere::vec_type xdash = bsphere._center; - xdash.x() += bsphere._radius; - xdash = xdash*matrix; - - osg::BoundingSphere::vec_type ydash = bsphere._center; - ydash.y() += bsphere._radius; - ydash = ydash*matrix; - - osg::BoundingSphere::vec_type zdash = bsphere._center; - zdash.z() += bsphere._radius; - zdash = zdash*matrix; - - bsphere._center = bsphere._center*matrix; - - xdash -= bsphere._center; - osg::BoundingSphere::value_type len_xdash = xdash.length(); - - ydash -= bsphere._center; - osg::BoundingSphere::value_type len_ydash = ydash.length(); - - zdash -= bsphere._center; - osg::BoundingSphere::value_type len_zdash = zdash.length(); - - bsphere._radius = len_xdash; - if (bsphere._radiusfirst; osg::BoundingSphere bs = it->second; - transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); + SceneUtil::transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); box.expandBy(bs); } @@ -776,7 +748,6 @@ namespace NifOsg osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setName(nifNode->name); bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } else @@ -788,14 +759,14 @@ namespace NifOsg transformNode->addCullCallback(new BillboardCallback); } + transformNode->setName(nifNode->name); + if (parentNode) parentNode->addChild(transformNode); if (!rootNode) rootNode = transformNode; - // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. - // UserData used for a variety of features: // - finding the correct emitter node for a particle system // - establishing connections to the animated collision shapes, which are handled in a separate loader diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 6208d01528..47efe986c3 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,40 +12,39 @@ #include #include +#include "visitor.hpp" + namespace SceneUtil { - class FindByNameVisitor : public osg::NodeVisitor + class NodeMapVisitor : public osg::NodeVisitor { public: - FindByNameVisitor(const std::string& nameToFind) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mNameToFind(nameToFind) - , mFoundNode(NULL) + NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::MatrixTransform& trans) { + mMap[trans.getName()] = &trans; + traverse(trans); } - virtual void apply(osg::Node &node) + typedef std::map > NodeMap; + + const NodeMap& getNodeMap() const { - osg::Group* group = node.asGroup(); - if (group && node.getName() == mNameToFind) - { - mFoundNode = group; - return; - } - traverse(node); + return mMap; } - const std::string& mNameToFind; - osg::Group* mFoundNode; + private: + NodeMap mMap; }; - /// Copy the skeleton-space matrix of a "source" bone to a "dest" bone (the bone that the callback is attached to). - /// Must be set on a Bone. + /// Copy the matrix of a "source" node to a "dest" node (the node that the callback is attached to). + /// Must be set on a MatrixTransform. class CopyController : public osg::NodeCallback { public: - CopyController(osgAnimation::Bone* copyFrom) + CopyController(osg::MatrixTransform* copyFrom) : mCopyFrom(copyFrom) { } @@ -66,22 +65,21 @@ namespace SceneUtil if (mCopyFrom) { bone->setMatrix(mCopyFrom->getMatrix()); - bone->setMatrixInSkeletonSpace(mCopyFrom->getMatrixInSkeletonSpace()); } traverse(node, nv); } private: - const osgAnimation::Bone* mCopyFrom; + const osg::MatrixTransform* mCopyFrom; }; class AddCopyControllerVisitor : public osg::NodeVisitor { public: - AddCopyControllerVisitor(const osgAnimation::BoneMap& boneMap) + AddCopyControllerVisitor(const NodeMapVisitor::NodeMap& boneMap) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mBoneMap(boneMap) + , mNodeMap(boneMap) { } @@ -89,19 +87,23 @@ namespace SceneUtil { if (osgAnimation::Bone* bone = dynamic_cast(&node)) { - osgAnimation::BoneMap::const_iterator found = mBoneMap.find(bone->getName()); - if (found != mBoneMap.end()) + NodeMapVisitor::NodeMap::const_iterator found = mNodeMap.find(bone->getName()); + if (found != mNodeMap.end()) { + // add the CopyController at position 0 so it's executed before UpdateBone + osg::ref_ptr old = bone->getUpdateCallback(); bone->setUpdateCallback(new CopyController(found->second.get())); + bone->addUpdateCallback(old); } } } private: - const osgAnimation::BoneMap& mBoneMap; + const NodeMapVisitor::NodeMap& mNodeMap; }; // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later + // copying is kinda cheap though, so don't bother for now class FilterVisitor : public osg::NodeVisitor { public: @@ -137,13 +139,12 @@ namespace SceneUtil { if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) { - osgAnimation::Skeleton* masterSkel = dynamic_cast(master); - osgAnimation::BoneMapVisitor boneMapVisitor; - masterSkel->accept(boneMapVisitor); + NodeMapVisitor nodeMapVisitor; + master->accept(nodeMapVisitor); // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible // due to a difference in binding pose of the two skeletons - AddCopyControllerVisitor visitor(boneMapVisitor.getBoneMap()); + AddCopyControllerVisitor visitor(nodeMapVisitor.getNodeMap()); toAttach->accept(visitor); FilterVisitor filterVisitor(filter); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp new file mode 100644 index 0000000000..c49cf77b8d --- /dev/null +++ b/components/sceneutil/lightmanager.cpp @@ -0,0 +1,309 @@ +#include "lightmanager.hpp" + +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace SceneUtil +{ + + class LightStateAttribute : public osg::Light + { + public: + LightStateAttribute() {} + + LightStateAttribute(const LightStateAttribute& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::Light(light,copyop) {} + + LightStateAttribute(const osg::Light& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::Light(light,copyop) {} + + + META_StateAttribute(NifOsg, LightStateAttribute, osg::StateAttribute::LIGHT) + + virtual void apply(osg::State& state) const + { + osg::Matrix modelViewMatrix = state.getModelViewMatrix(); + + // FIXME: we shouldn't have to apply the modelview matrix after every light + // this could be solvable by having the LightStateAttribute contain all lights instead of just one. + state.applyModelViewMatrix(state.getInitialViewMatrix()); + + osg::Light::apply(state); + + state.setGlobalDefaultAttribute(this); + + state.applyModelViewMatrix(modelViewMatrix); + } + }; + + class CullCallback : public osg::NodeCallback + { + public: + CullCallback() + : mLightManager(NULL) + {} + CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + CullCallback(LightManager* lightManager) + : mLightManager(lightManager) + {} + + META_Object(NifOsg, CullCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i 8) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > 8) + lightList.pop_back(); + } + + osg::ref_ptr stateset = mLightManager->getLightListStateSet(lightList); + + cv->pushStateSet(stateset); + + traverse(node, nv); + + cv->popStateSet(); + } + else + traverse(node, nv); + } + + private: + LightManager* mLightManager; + }; + + class AttachCullCallbackVisitor : public osg::NodeVisitor + { + public: + AttachCullCallbackVisitor(LightManager* lightManager) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mLightManager(lightManager) + { + } + + virtual void apply(osg::Geode &geode) + { + if (!geode.getNumParents()) + return; + + // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call + // does not traverse the drawables, so the push/pop in the CullCallback has no effect + // Should be no longer an issue with osg trunk + osg::Node* parent = geode.getParent(0); + parent->addCullCallback(new CullCallback(mLightManager)); + } + + private: + LightManager* mLightManager; + }; + + // Set on a LightSource. Adds the light source to its light manager for the current frame. + // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. + class CollectLightCallback : public osg::NodeCallback + { + public: + CollectLightCallback() + : mLightManager(0) { } + + CollectLightCallback(const CollectLightCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + , mLightManager(0) { } + + META_Object(SceneUtil, SceneUtil::CollectLightCallback) + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + throw std::runtime_error("can't find parent LightManager"); + } + + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + + traverse(node, nv); + } + + private: + LightManager* mLightManager; + }; + + // Set on a LightManager. Clears the data from the previous frame. + class LightManagerUpdateCallback : public osg::NodeCallback + { + public: + LightManagerUpdateCallback() + { } + + LightManagerUpdateCallback(const LightManagerUpdateCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { } + + META_Object(SceneUtil, SceneUtil::LightManagerUpdateCallback) + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + LightManager* lightManager = static_cast(node); + lightManager->update(); + + traverse(node, nv); + } + }; + + LightManager::LightManager() + : mLightsInViewSpace(false) + , mDecorated(false) + { + setUpdateCallback(new LightManagerUpdateCallback); + } + + LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) + : osg::Group(copy, copyop) + , mLightsInViewSpace(false) + , mDecorated(copy.mDecorated) + { + + } + + void LightManager::decorateGeodes() + { + AttachCullCallbackVisitor visitor(this); + accept(visitor); + } + + void LightManager::update() + { + mLightsInViewSpace = false; + mLights.clear(); + mStateSetCache.clear(); + + if (!mDecorated) + { + decorateGeodes(); + mDecorated = true; + } + } + + void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) + { + LightSourceTransform l; + l.mLightSource = lightSource; + l.mWorldMatrix = worldMat; + mLights.push_back(l); + } + + void LightManager::prepareForCamera(osg::Camera *cam) + { + // later on we need to store this per camera + if (!mLightsInViewSpace) + { + for (std::vector::iterator it = mLights.begin(); it != mLights.end(); ++it) + { + LightSourceTransform& l = *it; + osg::Matrix worldViewMat = l.mWorldMatrix * cam->getViewMatrix(); + l.mViewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), l.mLightSource->getRadius()); + transformBoundingSphere(worldViewMat, l.mViewBound); + } + mLightsInViewSpace = true; + } + } + + osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) + { + // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) + size_t hash = 0; + for (unsigned int i=0; isecond; + else + { + osg::ref_ptr stateset (new osg::StateSet); + for (unsigned int i=0; igetLight(); + + osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); + clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); + + clonedLight->setLightNum(i); + + // don't use setAttributeAndModes, that does not support light indices! + stateset->setAttribute(clonedLight, osg::StateAttribute::ON); + stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + } + mStateSetCache.insert(std::make_pair(hash, stateset)); + return stateset; + } + } + + const std::vector& LightManager::getLights() const + { + return mLights; + } + + LightSource::LightSource() + : mRadius(0.f) + { + setUpdateCallback(new CollectLightCallback); + } + +} diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp new file mode 100644 index 0000000000..ccb6603a6e --- /dev/null +++ b/components/sceneutil/lightmanager.hpp @@ -0,0 +1,105 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H +#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H + +#include + +#include +#include + +namespace SceneUtil +{ + + /// LightSource managed by a LightManager. + class LightSource : public osg::Node + { + osg::ref_ptr mLight; + + // The activation radius + float mRadius; + + public: + + META_Node(SceneUtil, SceneUtil::LightSource) + + LightSource(); + + LightSource(const LightSource& copy, const osg::CopyOp& copyop) + : osg::Node(copy, copyop) + , mLight(copy.mLight) + , mRadius(copy.mRadius) + { + } + + float getRadius() const + { + return mRadius; + } + + void setRadius(float radius) + { + mRadius = radius; + } + + osg::Light* getLight() + { + return mLight; + } + + void setLight(osg::Light* light) + { + mLight = light; + } + }; + + /// All light sources must be a child of the LightManager node. The LightManager can be anywhere in the scene graph, + /// but would be typically somewhere near the top. + class LightManager : public osg::Group + { + public: + + META_Node(SceneUtil, SceneUtil::LightManager) + + LightManager(); + + LightManager(const LightManager& copy, const osg::CopyOp& copyop); + + // Called automatically by the UpdateCallback + void update(); + + // Called automatically by the LightSource's UpdateCallback + void addLight(LightSource* lightSource, osg::Matrix worldMat); + + void prepareForCamera(osg::Camera* cam); + + void decorateGeodes(); + + struct LightSourceTransform + { + LightSource* mLightSource; + osg::Matrix mWorldMatrix; + osg::BoundingSphere mViewBound; + }; + + const std::vector& getLights() const; + + // Stores indices into the mLights vector + typedef std::vector LightList; + + osg::ref_ptr getLightListStateSet(const LightList& lightList); + + private: + // Lights collected from the scene graph. Only valid during the cull traversal. + std::vector mLights; + + bool mLightsInViewSpace; + + // < Light list hash , StateSet > + typedef std::map > LightStateSetMap; + LightStateSetMap mStateSetCache; + + bool mDecorated; + }; + +} + +#endif diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp new file mode 100644 index 0000000000..0d99e762d8 --- /dev/null +++ b/components/sceneutil/util.cpp @@ -0,0 +1,36 @@ +#include "util.hpp" + +namespace SceneUtil +{ + +void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) +{ + osg::BoundingSphere::vec_type xdash = bsphere._center; + xdash.x() += bsphere._radius; + xdash = xdash*matrix; + + osg::BoundingSphere::vec_type ydash = bsphere._center; + ydash.y() += bsphere._radius; + ydash = ydash*matrix; + + osg::BoundingSphere::vec_type zdash = bsphere._center; + zdash.z() += bsphere._radius; + zdash = zdash*matrix; + + bsphere._center = bsphere._center*matrix; + + xdash -= bsphere._center; + osg::BoundingSphere::value_type len_xdash = xdash.length(); + + ydash -= bsphere._center; + osg::BoundingSphere::value_type len_ydash = ydash.length(); + + zdash -= bsphere._center; + osg::BoundingSphere::value_type len_zdash = zdash.length(); + + bsphere._radius = len_xdash; + if (bsphere._radius +#include + +namespace SceneUtil +{ + + // Transform a bounding sphere by a matrix + // based off private code in osg::Transform + // TODO: patch osg to make public + void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + +} + +#endif diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp new file mode 100644 index 0000000000..59c706f110 --- /dev/null +++ b/components/sceneutil/visitor.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H +#define OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H + +#include + +// Commonly used scene graph visitors +namespace SceneUtil +{ + + class FindByNameVisitor : public osg::NodeVisitor + { + public: + FindByNameVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node) + { + osg::Group* group = node.asGroup(); + if (group && node.getName() == mNameToFind) + { + mFoundNode = group; + return; + } + traverse(node); + } + + const std::string& mNameToFind; + osg::Group* mFoundNode; + }; + +} + +#endif From e6cf959134d34dcc0cb727dc849848c391d91c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 14:46:52 +0200 Subject: [PATCH 0107/1812] Revert "Delete nifosgtest" This reverts commit ba3075dc110b5da47ab5e1b3aa069d54fecd444b. --- CMakeLists.txt | 2 + apps/nifosgtest/CMakeLists.txt | 7 ++ apps/nifosgtest/test.cpp | 162 +++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 apps/nifosgtest/CMakeLists.txt create mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e510b29d3..77bea373fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -559,6 +559,8 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools +add_subdirectory( apps/nifosgtest ) + if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt new file mode 100644 index 0000000000..265577d989 --- /dev/null +++ b/apps/nifosgtest/CMakeLists.txt @@ -0,0 +1,7 @@ +set (FILES + test.cpp +) + +add_executable (test ${FILES}) + +target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp new file mode 100644 index 0000000000..332867be5d --- /dev/null +++ b/apps/nifosgtest/test.cpp @@ -0,0 +1,162 @@ +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include + +// EventHandler to toggle wireframe when 'w' key is pressed +class WireframeKeyHandler : public osgGA::GUIEventHandler +{ +public: + WireframeKeyHandler(osg::Node* node) + : mWireframe(false) + , mNode(node) + { + + } + + virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) + { + switch (adapter.getEventType()) + { + case osgGA::GUIEventAdapter::KEYDOWN: + if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) + { + mWireframe = !mWireframe; + osg::PolygonMode* mode = new osg::PolygonMode; + mode->setMode(osg::PolygonMode::FRONT_AND_BACK, + mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); + + // Create a new stateset instead of changing the old one, this alleviates the need to set + // the StateSet to DYNAMIC DataVariance, which would have a performance impact. + + osg::StateSet* stateset = new osg::StateSet; + stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF + : osg::StateAttribute::ON); + + mNode->setStateSet(stateset); + + return true; + } + default: + break; + } + return false; + } + +private: + bool mWireframe; + osg::Node* mNode; +}; + +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + Files::ConfigurationManager cfgMgr; + boost::program_options::options_description desc(""); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("fallback-archive", boost::program_options::value >()-> + default_value(std::vector(), "fallback-archive")->multitoken()); + + boost::program_options::variables_map variables; + cfgMgr.readConfiguration(variables, desc); + + std::vector archives = variables["fallback-archive"].as >(); + bool fsStrict = variables["fs-strict"].as(); + Files::PathContainer dataDirs; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + cfgMgr.processPaths(dataDirs); + + VFS::Manager resourceMgr (fsStrict); + Files::Collections collections (dataDirs, !fsStrict); + + for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) + { + std::string filepath = collections.getPath(*it).string(); + resourceMgr.addArchive(new VFS::BsaArchive(filepath)); + } + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); + } + + resourceMgr.buildIndex(); + + Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); + + // For NiStencilProperty + osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); + + osgViewer::Viewer viewer; + + osg::ref_ptr root(new osg::Group()); + root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + // To prevent lighting issues with scaled meshes + root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + + //osgDB::writeNodeFile(*newNode, "out.osg"); + osg::Group* newNode = new osg::Group; + NifOsg::Loader loader; + Resource::TextureManager texMgr(&resourceMgr); + loader.mTextureManager = &texMgr; + newNode->addChild(loader.load(nif)); + + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; + root->addChild(trans); + + for (int x=0; x<1;++x) + { + //root->addChild(newNode); + trans->addChild(newNode); + } + + viewer.setSceneData(root); + + viewer.setUpViewInWindow(0, 0, 800, 600); + viewer.realize(); + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); + viewer.addEventHandler(new WireframeKeyHandler(root)); + + // Mask to separate cull visitors from update visitors + viewer.getCamera()->setCullMask(~(0x1)); + + viewer.addEventHandler(new osgViewer::StatsHandler); + + while (!viewer.done()) + { + //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); + + viewer.frame(); + } + + return 0; +} From b0ea51a5c8ffb8922e71c124d09719025fb3eb40 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 20:09:40 +0200 Subject: [PATCH 0108/1812] Colour conversion utility --- .../view/render/unpagedworldspacewidget.cpp | 7 +++---- components/sceneutil/util.cpp | 17 +++++++++++++++++ components/sceneutil/util.hpp | 5 +++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a6d18a0f2d..dec7d493ee 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -7,6 +7,8 @@ #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/data.hpp" @@ -23,10 +25,7 @@ void CSVRender::UnpagedWorldspaceWidget::update() const CSMWorld::Record& record = dynamic_cast&> (mCellsModel->getRecord (mCellId)); - ESM::Color clr = record.get().mAmbi.mAmbient; - osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f, 1.f); + osg::Vec4f colour = SceneUtil::colourFromRGB(record.get().mAmbi.mAmbient); setDefaultAmbient (colour); diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 0d99e762d8..a41c6b74b3 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -33,4 +33,21 @@ void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bs if (bsphere._radius> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, 1.f); + return colour; +} + +osg::Vec4f colourFromRGBA(unsigned int clr) +{ + osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, + ((clr >> 8) & 0xFF) / 255.0f, + ((clr >> 16) & 0xFF) / 255.0f, + ((clr >> 24) & 0xFF) / 255.0f); + return colour; +} + } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index a8d970df17..c99771c5ea 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace SceneUtil { @@ -12,6 +13,10 @@ namespace SceneUtil // TODO: patch osg to make public void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + osg::Vec4f colourFromRGB (unsigned int clr); + + osg::Vec4f colourFromRGBA (unsigned int clr); + } #endif From a0b43f426e2861bd4c4f554c0e53dadc8d62c3ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 23:01:37 +0200 Subject: [PATCH 0109/1812] Avoid setting DYNAMIC DataVariance on StateSets --- components/nifosg/controller.cpp | 16 ++++++++++++---- components/nifosg/controller.hpp | 19 +++++++++++++++---- components/nifosg/nifloader.cpp | 4 ---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5916359c8b..59ba9ad4ff 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -291,7 +291,7 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = getInputValue(nv); float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); @@ -372,7 +372,7 @@ void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -404,7 +404,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -441,7 +441,7 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput() && mDelta != 0) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } @@ -507,4 +507,12 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n traverse(node, nv); } +osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node) +{ + osg::StateSet* orig = node->getOrCreateStateSet(); + osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY); + node->setStateSet(cloned); + return cloned; +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 80e6090e49..1a90b8759e 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,8 +189,19 @@ namespace NifOsg bool mEnabled; }; + class StateSetController + { + protected: + // Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame + // queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would + // undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates. + // If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames, + // kind of like a double buffering scheme. + osg::StateSet* getWritableStateSet(osg::Node* node); + }; + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting - struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator + class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { public: UVController(); @@ -226,7 +237,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -241,7 +252,7 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -256,7 +267,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class FlipController : public osg::NodeCallback, public Controller + class FlipController : public osg::NodeCallback, public Controller, public StateSetController { private: int mTexSlot; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a5c9b6e2aa..a858473514 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -881,7 +881,6 @@ namespace NifOsg osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); - transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); transformNode->addUpdateCallback(ctrl); } @@ -927,7 +926,6 @@ namespace NifOsg const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) @@ -935,7 +933,6 @@ namespace NifOsg const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); setupController(matctrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else @@ -975,7 +972,6 @@ namespace NifOsg } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(callback); } else From c92592493ed8cf454a83034eb100181f0d7865a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 15:34:50 +0200 Subject: [PATCH 0110/1812] OpenMW: create a window and render the starting cell(s) --- apps/nifosgtest/test.cpp | 3 +- apps/openmw/CMakeLists.txt | 5 +- apps/openmw/engine.cpp | 69 +- apps/openmw/engine.hpp | 32 +- apps/openmw/mwclass/activator.cpp | 5 +- apps/openmw/mwclass/container.cpp | 5 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/door.cpp | 5 +- apps/openmw/mwclass/light.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwmechanics/levelledlist.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 13 +- apps/openmw/mwrender/actors.hpp | 2 - apps/openmw/mwrender/animation.cpp | 1580 +---------------- apps/openmw/mwrender/animation.hpp | 196 +- apps/openmw/mwrender/objects.cpp | 249 ++- apps/openmw/mwrender/objects.hpp | 57 +- apps/openmw/mwrender/renderingmanager.cpp | 1078 +---------- apps/openmw/mwrender/renderingmanager.hpp | 267 +-- .../mwscript/transformationextensions.cpp | 4 +- apps/openmw/mwworld/cellfunctors.hpp | 4 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 12 +- apps/openmw/mwworld/refdata.cpp | 15 +- apps/openmw/mwworld/refdata.hpp | 19 +- apps/openmw/mwworld/scene.cpp | 83 +- apps/openmw/mwworld/scene.hpp | 9 +- apps/openmw/mwworld/worldimp.cpp | 49 +- apps/openmw/mwworld/worldimp.hpp | 21 +- components/sceneutil/lightmanager.cpp | 42 +- components/sceneutil/lightmanager.hpp | 7 + files/settings-default.cfg | 9 - 36 files changed, 665 insertions(+), 3202 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 332867be5d..487a91890e 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -127,8 +127,7 @@ int main(int argc, char** argv) osg::Group* newNode = new osg::Group; NifOsg::Loader loader; Resource::TextureManager texMgr(&resourceMgr); - loader.mTextureManager = &texMgr; - newNode->addChild(loader.load(nif)); + newNode->addChild(loader.load(nif, &texMgr)); osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 50aeafc2aa..e10688149f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender -actors objects -# renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation +# debugging sky camera npcanimation creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation @@ -129,6 +129,7 @@ target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c7a92e52e3..0d0294fa7d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -3,15 +3,23 @@ #include #include -#include -#include +#include +#include + +#include #include #include +// TODO: move to component #include +#include +#include + +#include + #include #include @@ -172,8 +180,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mOgre (0) - , mVerboseScripts (false) + : mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) @@ -220,10 +227,6 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) { } -void OMW::Engine::addZipResource (const boost::filesystem::path& path) -{ -} - void OMW::Engine::enableFSStrict(bool fsStrict) { mFSStrict = fsStrict; @@ -318,21 +321,27 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "shadows"); addResourcesDirectory(mResDir / "materials"); - OEngine::Render::WindowSettings windowSettings; - windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); - windowSettings.window_border = settings.getBool("window border", "Video"); - windowSettings.window_x = settings.getInt("resolution x", "Video"); - windowSettings.window_y = settings.getInt("resolution y", "Video"); - windowSettings.screen = settings.getInt("screen", "Video"); - windowSettings.vsync = settings.getBool("vsync", "Video"); - windowSettings.icon = "openmw.png"; - std::string aa = settings.getString("antialiasing", "Video"); - windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + //OEngine::Render::WindowSettings windowSettings; + //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); + //windowSettings.window_border = settings.getBool("window border", "Video"); + //windowSettings.vsync = settings.getBool("vsync", "Video"); + //windowSettings.icon = "openmw.png"; + //std::string aa = settings.getString("antialiasing", "Video"); + //windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - //Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); + // not handling fullscreen yet, we should figure this out when adding SDL to the mix + mViewer.setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); + osg::ref_ptr rootNode (new osg::Group); + mViewer.setSceneData(rootNode); + + mVFS.reset(new VFS::Manager(mFSStrict)); + + VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); + + mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -378,8 +387,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (mFileCollections, mContentFiles, - mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, + mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), + mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); @@ -460,7 +469,7 @@ void OMW::Engine::go() { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); } - else if (!mSkipMenu) + else if (0)// !mSkipMenu) { // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); @@ -481,6 +490,22 @@ void OMW::Engine::go() } // Start the main rendering loop + mViewer.setCameraManipulator(new osgGA::TrackballManipulator); + mViewer.addEventHandler(new osgViewer::StatsHandler); + + osg::Timer timer; + //osgUtil::IncrementalCompileOperation* ico = new osgUtil::IncrementalCompileOperation; + //ico->compileAllForNextFrame(1); + //mViewer.setRealizeOperation(ico); + mViewer.realize(); + std::cout << "realize took " << timer.time_m() << std::endl; + while (!mViewer.done()) + { + MWBase::Environment::get().getWorld()->update(0.f, false); + + mViewer.frame(/*simulationTime*/); + } + /* Ogre::Timer timer; while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index ef26ceb3a8..de09082d88 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -9,11 +9,23 @@ #include #include +#include + #include "mwbase/environment.hpp" #include "mwworld/ptr.hpp" +namespace Resource +{ + class ResourceSystem; +} + +namespace VFS +{ + class Manager; +} + namespace Compiler { class Context; @@ -39,19 +51,6 @@ namespace MWGui class WindowManager; } -namespace OEngine -{ - namespace GUI - { - class MyGUIManager; - } - - namespace Render - { - class OgreRenderer; - } -} - namespace Files { struct ConfigurationManager; @@ -62,13 +61,15 @@ namespace OMW /// \brief Main engine class, that brings together all the components of OpenMW class Engine : private Ogre::FrameListener { + std::auto_ptr mVFS; + std::auto_ptr mResourceSystem; MWBase::Environment mEnvironment; ToUTF8::FromType mEncoding; ToUTF8::Utf8Encoder* mEncoder; Files::PathContainer mDataDirs; std::vector mArchives; boost::filesystem::path mResDir; - OEngine::Render::OgreRenderer *mOgre; + osgViewer::Viewer mViewer; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; @@ -108,9 +109,6 @@ namespace OMW /// \note This function works recursively. void addResourcesDirectory (const boost::filesystem::path& path); - /// add a .zip resource - void addZipResource (const boost::filesystem::path& path); - void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 457b0cec10..2621f5e522 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -16,7 +16,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -34,8 +34,7 @@ namespace MWClass void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 5f49a74b6c..ac23744e8f 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -23,7 +23,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwmechanics/npcstats.hpp" @@ -93,8 +93,7 @@ namespace MWClass void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ac99fa4b48..c1b8177f78 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -29,7 +29,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwrender/renderinginterface.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwgui/tooltips.hpp" @@ -163,10 +163,10 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - //MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); - //MWRender::Actors& actors = renderingInterface.getActors(); - //actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + MWRender::Objects& objects = renderingInterface.getObjects(); + objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 2d39881b1f..f46ede730d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -24,7 +24,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" namespace @@ -52,8 +52,7 @@ namespace MWClass void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, true); } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 90c708f970..2cf31d996d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -23,7 +23,6 @@ #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" -#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" namespace MWClass @@ -39,8 +38,7 @@ namespace MWClass ptr.get(); // Insert even if model is empty, so that the light is added - MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, model, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); + renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3dcb57fbba..506852a908 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -35,7 +35,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwrender/actors.hpp" +#include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -409,7 +409,7 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - renderingInterface.getActors().insertNPC(ptr); + renderingInterface.getObjects().insertNPC(ptr); } void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bc7bb0bb58..319e1d7ec9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1702,6 +1702,7 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { + return; mVideoWidget->playVideo("video\\" + name); mVideoWidget->eventKeyButtonPressed.clear(); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d277b1249d..6850518600 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -474,7 +474,7 @@ namespace MWMechanics Ogre::Vector3 dir = playerPos - actorPos; Ogre::Radian faceAngle = Ogre::Math::ATan2(dir.x,dir.y); - Ogre::Radian actorAngle = actor.getRefData().getBaseNode()->getOrientation().getRoll(); + Ogre::Radian actorAngle = actor.getRefData().getBaseNodeOld()->getOrientation().getRoll(); // an attempt at reducing the turning animation glitch if( Ogre::Math::Abs( faceAngle - actorAngle ) >= Ogre::Degree(5) ) // TODO: is there a better way? { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index c5fc34507b..64456dd11d 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -75,7 +75,7 @@ namespace MWMechanics return false; Ogre::Degree angle = signedAngle (Ogre::Vector3(attacker.getRefData().getPosition().pos) - Ogre::Vector3(blocker.getRefData().getPosition().pos), - blocker.getRefData().getBaseNode()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); + blocker.getRefData().getBaseNodeOld()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); if (angle.valueDegrees() < gmst.find("fCombatBlockLeftAngle")->getFloat()) diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 20b87a3a96..76c472001e 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index abfc793de5..0b33902719 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1385,7 +1385,7 @@ namespace MWMechanics static float fSneakViewMult = store.find("fSneakViewMult")->getFloat(); float y = 0; Ogre::Vector3 vec = pos1 - pos2; - Ogre::Radian angle = observer.getRefData().getBaseNode()->getOrientation().yAxis().angleBetween(vec); + Ogre::Radian angle = observer.getRefData().getBaseNodeOld()->getOrientation().yAxis().angleBetween(vec); if (angle < Ogre::Degree(90)) y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a7d3545b3a..5f4d986b4c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -418,7 +418,7 @@ namespace MWMechanics absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { - const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell @@ -466,7 +466,7 @@ namespace MWMechanics bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { - const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); + //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); @@ -565,7 +565,7 @@ namespace MWMechanics } // Add VFX - const ESM::Static* castStatic; + /*const ESM::Static* castStatic; if (!magicEffect->mHit.empty()) castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); else @@ -574,9 +574,10 @@ namespace MWMechanics // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well - //MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); - //if (anim) - // anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); + if (anim) + anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + */ } } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 887ea68d1c..931c5bbd59 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,8 +1,6 @@ #ifndef GAME_RENDER_ACTORS_H #define GAME_RENDER_ACTORS_H -//#include - #include namespace OEngine diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 871561bdcf..85d9546aa4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,1551 +1,73 @@ #include "animation.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" -#include "../mwbase/world.hpp" - -#include "../mwmechanics/character.hpp" -#include "../mwmechanics/creaturestats.hpp" - -#include "../mwworld/class.hpp" -#include "../mwworld/fallback.hpp" -#include "../mwworld/cellstore.hpp" -#include "../mwworld/esmstore.hpp" - -#include "renderconst.hpp" +#include +#include +#include namespace MWRender { -Ogre::Real Animation::AnimationTime::getValue() const -{ - AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); - if(iter != mAnimation->mStates.end()) - return iter->second.mTime; - return 0.0f; -} - -void Animation::AnimationTime::setValue(Ogre::Real) -{ -} - -Ogre::Real Animation::EffectAnimationTime::getValue() const -{ - return mTime; -} - -void Animation::EffectAnimationTime::setValue(Ogre::Real) -{ -} - -Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) - : mPtr(ptr) - , mInsert(node) - , mSkelBase(NULL) - , mAccumRoot(NULL) - , mNonAccumRoot(NULL) - , mNonAccumCtrl(NULL) - , mAccumulate(0.0f) - , mNullAnimationTimePtr(OGRE_NEW NullAnimationTime) - , mGlowLight(NULL) -{ - for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this)); -} - -Animation::~Animation() -{ - setLightEffect(0); - - mEffects.clear(); - - mAnimSources.clear(); -} - -std::string Animation::getObjectRootName() const -{ - if (mSkelBase) - return mSkelBase->getMesh()->getName(); - return std::string(); -} - -void Animation::setObjectRoot(const std::string &model, bool baseonly) -{ - OgreAssert(mAnimSources.empty(), "Setting object root while animation sources are set!"); - - mSkelBase = NULL; - mObjectRoot.setNull(); - - if(model.empty()) - return; - - mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - - if(mObjectRoot->mSkelBase) + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem) + : mPtr(ptr) + , mInsert(node) + , mResourceSystem(resourceSystem) { - mSkelBase = mObjectRoot->mSkelBase; - Ogre::AnimationStateSet *aset = mObjectRoot->mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) + } + + Animation::~Animation() + { + if (mObjectRoot) + mInsert->removeChild(mObjectRoot); + } + + osg::Vec3f Animation::runAnimation(float duration) + { + return osg::Vec3f(); + } + + void Animation::setObjectRoot(const std::string &model) + { + if (mObjectRoot) { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); + mObjectRoot->getParent(0)->removeChild(mObjectRoot); } - // Set the bones as manually controlled since we're applying the - // transformations manually - Ogre::SkeletonInstance *skelinst = mObjectRoot->mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + } - // Reattach any objects that have been attached to this one - ObjectAttachMap::iterator iter = mAttachedObjects.begin(); - while(iter != mAttachedObjects.end()) + osg::Group* Animation::getObjectRoot() + { + return static_cast(mObjectRoot.get()); + } + + osg::Group* Animation::getOrCreateObjectRoot() + { + if (mObjectRoot) + return static_cast(mObjectRoot.get()); + + mObjectRoot = new osg::Group; + mInsert->addChild(mObjectRoot); + return static_cast(mObjectRoot.get()); + } + + // -------------------------------------------------------------------------------- + + ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) + { + if (!model.empty()) { - if(!skelinst->hasBone(iter->second)) - mAttachedObjects.erase(iter++); - else - { - mSkelBase->attachObjectToBone(iter->second, iter->first); - ++iter; - } - } - } - else - mAttachedObjects.clear(); -} - -struct AddGlow -{ - Ogre::Vector3* mColor; - NifOgre::MaterialControllerManager* mMaterialControllerMgr; - AddGlow(Ogre::Vector3* col, NifOgre::MaterialControllerManager* materialControllerMgr) - : mColor(col) - , mMaterialControllerMgr(materialControllerMgr) - {} - - void operator()(Ogre::Entity* entity) const - { - if (!entity->getNumSubEntities()) - return; - Ogre::MaterialPtr writableMaterial = mMaterialControllerMgr->getWritableMaterial(entity); - sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(writableMaterial->getName()); - - instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z))); - // Workaround for crash in Ogre (https://bitbucket.org/sinbad/ogre/pull-request/447/fix-shadows-crash-for-textureunitstates/diff) - // Remove when the fix is merged - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - } -}; - -class VisQueueSet -{ - Ogre::uint32 mVisFlags; - Ogre::uint8 mSolidQueue, mTransQueue; - Ogre::Real mDist; - -public: - VisQueueSet(Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist) - : mVisFlags(visflags), mSolidQueue(solidqueue), mTransQueue(transqueue), mDist(dist) - { } - - void operator()(Ogre::Entity *entity) const - { - if(mVisFlags != 0) - entity->setVisibilityFlags(mVisFlags); - entity->setRenderingDistance(mDist); - - unsigned int numsubs = entity->getNumSubEntities(); - for(unsigned int i = 0;i < numsubs;++i) - { - Ogre::SubEntity* subEnt = entity->getSubEntity(i); - sh::Factory::getInstance()._ensureMaterial(subEnt->getMaterial()->getName(), "Default"); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? mTransQueue : mSolidQueue); - } - } - - void operator()(Ogre::ParticleSystem *psys) const - { - if(mVisFlags != 0) - psys->setVisibilityFlags(mVisFlags); - psys->setRenderingDistance(mDist); - // TODO: Check particle material for actual transparency - psys->setRenderQueueGroup(mTransQueue); - } -}; - -void Animation::setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist, bool enchantedGlow, Ogre::Vector3* glowColor) -{ - std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(), - VisQueueSet(visflags, solidqueue, transqueue, dist)); - std::for_each(objlist->mParticles.begin(), objlist->mParticles.end(), - VisQueueSet(visflags, solidqueue, transqueue, dist)); - - if (enchantedGlow) - std::for_each(objlist->mEntities.begin(), objlist->mEntities.end(), - AddGlow(glowColor, &objlist->mMaterialControllerMgr)); -} - - -size_t Animation::detectAnimGroup(const Ogre::Node *node) -{ - static const char sGroupRoots[sNumGroups][32] = { - "", /* Lower body / character root */ - "Bip01 Spine1", /* Torso */ - "Bip01 L Clavicle", /* Left arm */ - "Bip01 R Clavicle", /* Right arm */ - }; - - while(node) - { - const Ogre::String &name = node->getName(); - for(size_t i = 1;i < sNumGroups;i++) - { - if(name == sGroupRoots[i]) - return i; - } - - node = node->getParent(); - } - - return 0; -} - - -void Animation::addAnimSource(const std::string &model) -{ - OgreAssert(mInsert, "Object is missing a root!"); - if(!mSkelBase) - return; - - std::string kfname = model; - Misc::StringUtils::toLower(kfname); - - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - return; - - std::vector > ctrls; - Ogre::SharedPtr animsrc(OGRE_NEW AnimSource); - NifOgre::Loader::createKfControllers(mSkelBase, kfname, animsrc->mTextKeys, ctrls); - if(animsrc->mTextKeys.empty() || ctrls.empty()) - return; - - mAnimSources.push_back(animsrc); - - std::vector > *grpctrls = animsrc->mControllers; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - - size_t grp = detectAnimGroup(dstval->getNode()); - - if(!mAccumRoot && grp == 0) - { - mNonAccumRoot = dstval->getNode(); - mAccumRoot = mNonAccumRoot->getParent(); - if(!mAccumRoot) - { - std::cerr<< "Non-Accum root for "<getNode()->getName() == "Bip01" || dstval->getNode()->getName() == "Root Bone")) - { - mNonAccumRoot = dstval->getNode(); - mAccumRoot = mNonAccumRoot->getParent(); - if(!mAccumRoot) - { - std::cerr<< "Non-Accum root for "<mControllers.size(); ++i) - { - if (mObjectRoot->mControllers[i].getSource().isNull()) - mObjectRoot->mControllers[i].setSource(mAnimationTimePtr[0]); - } -} - -void Animation::clearAnimSources() -{ - mStates.clear(); - - for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i]->setAnimName(std::string()); - - mNonAccumCtrl = NULL; - - mAccumRoot = NULL; - mNonAccumRoot = NULL; - - mAnimSources.clear(); -} - - -void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light) -{ - const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); - - const unsigned int clr = light->mData.mColor; - Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f); - const float radius = float(light->mData.mRadius); - - if((light->mData.mFlags&ESM::Light::Negative)) - color *= -1; - - objlist->mLights.push_back(sceneMgr->createLight()); - Ogre::Light *olight = objlist->mLights.back(); - olight->setDiffuseColour(color); - - Ogre::ControllerValueRealPtr src(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); - Ogre::ControllerValueRealPtr dest(OGRE_NEW OEngine::Render::LightValue(olight, color)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW OEngine::Render::LightFunction( - (light->mData.mFlags&ESM::Light::Flicker) ? OEngine::Render::LT_Flicker : - (light->mData.mFlags&ESM::Light::FlickerSlow) ? OEngine::Render::LT_FlickerSlow : - (light->mData.mFlags&ESM::Light::Pulse) ? OEngine::Render::LT_Pulse : - (light->mData.mFlags&ESM::Light::PulseSlow) ? OEngine::Render::LT_PulseSlow : - OEngine::Render::LT_Normal - )); - objlist->mControllers.push_back(Ogre::Controller(src, dest, func)); - - bool interior = !(mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior()); - - static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); - static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); - static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); - static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); - static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); - static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); - static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); - - bool quadratic = useQuadratic && (!outQuadInLin || !interior); - - - // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, - // so we ignore lights if their attenuation falls below this factor. - const float threshold = 0.03f; - - float quadraticAttenuation = 0; - float linearAttenuation = 0; - float activationRange = 0; - if (quadratic) - { - float r = radius * quadraticRadiusMult; - quadraticAttenuation = quadraticValue / std::pow(r, 2); - activationRange = std::sqrt(1.0f / (threshold * quadraticAttenuation)); - } - if (useLinear) - { - float r = radius * linearRadiusMult; - linearAttenuation = linearValue / r; - activationRange = std::max(activationRange, 1.0f / (threshold * linearAttenuation)); - } - - olight->setAttenuation(activationRange, 0, linearAttenuation, quadraticAttenuation); - - // If there's an AttachLight bone, attach the light to that, otherwise put it in the center, - if(objlist->mSkelBase && objlist->mSkelBase->getSkeleton()->hasBone("AttachLight")) - objlist->mSkelBase->attachObjectToBone("AttachLight", olight); - else - { - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - for(size_t i = 0;i < objlist->mEntities.size();i++) - { - Ogre::Entity *ent = objlist->mEntities[i]; - bounds.merge(ent->getBoundingBox()); - } - - Ogre::SceneNode *node = bounds.isFinite() ? mInsert->createChildSceneNode(bounds.getCenter()) - : mInsert->createChildSceneNode(); - node->attachObject(olight); - } -} - - -Ogre::Node* Animation::getNode(const std::string &name) -{ - if(mSkelBase) - { - Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); - if(skel->hasBone(name)) - return skel->getBone(name); - } - return NULL; -} - -Ogre::Node* Animation::getNode(int handle) -{ - if (mSkelBase) - { - Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); - return skel->getBone(handle); - } - return NULL; -} - -NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) -{ - NifOgre::TextKeyMap::const_iterator iter(keys.begin()); - for(;iter != keys.end();++iter) - { - if(iter->second.compare(0, groupname.size(), groupname) == 0 && - iter->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - return iter; -} - - -bool Animation::hasAnimation(const std::string &anim) -{ - AnimSourceList::const_iterator iter(mAnimSources.begin()); - for(;iter != mAnimSources.end();++iter) - { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - if(findGroupStart(keys, anim) != keys.end()) - return true; - } - - return false; -} - - -void Animation::setAccumulation(const Ogre::Vector3 &accum) -{ - mAccumulate = accum; -} - - -void Animation::updatePtr(const MWWorld::Ptr &ptr) -{ - mPtr = ptr; -} - - -float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname) -{ - const std::string start = groupname+": start"; - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - const std::string stop = groupname+": stop"; - float starttime = std::numeric_limits::max(); - float stoptime = 0.0f; - - // Pick the last Loop Stop key and the last Loop Start key. - // This is required because of broken text keys in AshVampire.nif. - // It has *two* WalkForward: Loop Stop keys at different times, the first one is used for stopping playback - // but the animation velocity calculation uses the second one. - // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, - // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. - NifOgre::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); - while(keyiter != keys.rend()) - { - if(keyiter->second == start || keyiter->second == loopstart) - { - starttime = keyiter->first; - break; - } - ++keyiter; - } - keyiter = keys.rbegin(); - while(keyiter != keys.rend()) - { - if (keyiter->second == stop) - stoptime = keyiter->first; - else if (keyiter->second == loopstop) - { - stoptime = keyiter->first; - break; - } - ++keyiter; - } - - if(stoptime > starttime) - { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum; - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum; - - return startpos.distance(endpos) / (stoptime - starttime); - } - - return 0.0f; -} - -float Animation::getVelocity(const std::string &groupname) const -{ - /* Look in reverse; last-inserted source has priority. */ - AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); - for(;animsrc != mAnimSources.rend();++animsrc) - { - const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; - if(findGroupStart(keys, groupname) != keys.end()) - break; - } - if(animsrc == mAnimSources.rend()) - return 0.0f; - - float velocity = 0.0f; - const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; - const std::vector >&ctrls = (*animsrc)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) - { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); - break; - } - } - - // If there's no velocity, keep looking - if(!(velocity > 1.0f)) - { - AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); - while(*animiter != *animsrc) - ++animiter; - - while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) - { - const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; - const std::vector >&ctrls = (*animiter)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) - { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); - break; - } - } - } - } - - return velocity; -} - - -static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) -{ - if(bone->getName() != " " // really should be != "", but see workaround in skeleton.cpp for empty node names - && skelsrc->hasBone(bone->getName())) - { - Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); - if(!srcbone->getParent() || !bone->getParent()) - { - bone->setOrientation(srcbone->getOrientation()); - bone->setPosition(srcbone->getPosition()); - bone->setScale(srcbone->getScale()); + setObjectRoot(model); } else { - bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); - bone->_setDerivedPosition(srcbone->_getDerivedPosition()); - bone->setScale(Ogre::Vector3::UNIT_SCALE); + // No model given. Create an object root anyway, so that lights can be added to it if needed. + //mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); } } - Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator(); - while(boneiter.hasMoreElements()) - updateBoneTree(skelsrc, static_cast(boneiter.getNext())); -} - -void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) -{ - Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator(); - while(boneiter.hasMoreElements()) - updateBoneTree(skelsrc, boneiter.getNext()); -} - - -void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &position) -{ - /* Get the non-accumulation root's difference from the last update, and move the position - * accordingly. - */ - Ogre::Vector3 off = mNonAccumCtrl->getTranslation(newtime)*mAccumulate; - position += off - mNonAccumCtrl->getTranslation(oldtime)*mAccumulate; - - /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->setPosition(-off); -} - -bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) -{ - // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two - // separate walkforward keys, and the last one is supposed to be used. - NifOgre::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); - for(;groupend != keys.rend();++groupend) - { - if(groupend->second.compare(0, groupname.size(), groupname) == 0 && - groupend->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - - std::string starttag = groupname+": "+start; - NifOgre::TextKeyMap::const_reverse_iterator startkey(groupend); - while(startkey != keys.rend() && startkey->second != starttag) - ++startkey; - if(startkey == keys.rend() && start == "loop start") - { - starttag = groupname+": start"; - startkey = groupend; - while(startkey != keys.rend() && startkey->second != starttag) - ++startkey; - } - if(startkey == keys.rend()) - return false; - - const std::string stoptag = groupname+": "+stop; - NifOgre::TextKeyMap::const_reverse_iterator stopkey(groupend); - while(stopkey != keys.rend() - // We have to ignore extra garbage at the end. - // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". - // Why, just why? :( - && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) - ++stopkey; - if(stopkey == keys.rend()) - return false; - - if(startkey->first > stopkey->first) - return false; - - state.mStartTime = startkey->first; - if (loopfallback) - { - state.mLoopStartTime = startkey->first; - state.mLoopStopTime = stopkey->first; - } - else - { - state.mLoopStartTime = startkey->first; - state.mLoopStopTime = std::numeric_limits::max(); - } - state.mStopTime = stopkey->first; - - state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); - - // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation - // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.mTime > state.mStartTime) - { - const std::string loopstarttag = groupname+": loop start"; - const std::string loopstoptag = groupname+": loop stop"; - - NifOgre::TextKeyMap::const_reverse_iterator key(groupend); - for (; key != startkey && key != keys.rend(); ++key) - { - if (key->first > state.mTime) - continue; - - if (key->second == loopstarttag) - state.mLoopStartTime = key->first; - else if (key->second == loopstoptag) - state.mLoopStopTime = key->first; - } - } - - return true; -} - -void split(const std::string &s, char delim, std::vector &elems) { - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) { - elems.push_back(item); - } -} - -void Animation::handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - const NifOgre::TextKeyMap& textkeys) -{ - //float time = key->first; - const std::string &evt = key->second; - - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - return; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - std::string soundgen = evt.substr(10); - - // The event can optionally contain volume and pitch modifiers - float volume=1.f, pitch=1.f; - if (soundgen.find(" ") != std::string::npos) - { - std::vector tokens; - split(soundgen, ' ', tokens); - soundgen = tokens[0]; - if (tokens.size() >= 2) - volume = Ogre::StringConverter::parseReal(tokens[1]); - if (tokens.size() >= 3) - pitch = Ogre::StringConverter::parseReal(tokens[2]); - } - - std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); - if(!sound.empty()) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; - if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) - type = MWBase::SoundManager::Play_TypeFoot; - sndMgr->playSound3D(mPtr, sound, volume, pitch, type); - } - return; - } - - if(evt.compare(0, groupname.size(), groupname) != 0 || - evt.compare(groupname.size(), 2, ": ") != 0) - { - // Not ours, skip it - return; - } - size_t off = groupname.size()+2; - size_t len = evt.size() - off; - - if(evt.compare(off, len, "loop start") == 0) - state.mLoopStartTime = key->first; - else if(evt.compare(off, len, "loop stop") == 0) - state.mLoopStopTime = key->first; - else if(evt.compare(off, len, "equip attach") == 0) - showWeapons(true); - else if(evt.compare(off, len, "unequip detach") == 0) - showWeapons(false); - else if(evt.compare(off, len, "chop hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if(evt.compare(off, len, "slash hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if(evt.compare(off, len, "thrust hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - else if(evt.compare(off, len, "hit") == 0) - { - if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - else - mPtr.getClass().hit(mPtr); - } - else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 - && evt.compare(off, len, "start") == 0) - { - NifOgre::TextKeyMap::const_iterator hitKey = key; - - // Not all animations have a hit key defined. If there is none, the hit happens with the start key. - bool hasHitKey = false; - while (hitKey != textkeys.end()) - { - if (hitKey->second == groupname + ": hit") - { - hasHitKey = true; - break; - } - if (hitKey->second == groupname + ": stop") - break; - ++hitKey; - } - if (!hasHitKey) - { - if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); - } - } - else if (evt.compare(off, len, "shoot attach") == 0) - attachArrow(); - else if (evt.compare(off, len, "shoot release") == 0) - releaseArrow(); - else if (evt.compare(off, len, "shoot follow attach") == 0) - attachArrow(); - - else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") - { - // Make sure this key is actually for the RangeType we are casting. The flame atronach has - // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. - // FIXME: This logic should really be in the CharacterController - const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - int range = 0; - if (evt.compare(off, len, "self release") == 0) - range = 0; - else if (evt.compare(off, len, "touch release") == 0) - range = 1; - else if (evt.compare(off, len, "target release") == 0) - range = 2; - if (effectentry.mRange == range) - { - MWBase::Environment::get().getWorld()->castSpell(mPtr); - } - } - - else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) - mPtr.getClass().block(mPtr); -} - -void Animation::changeGroups(const std::string &groupname, int groups) -{ - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - if(stateiter->second.mGroups != groups) - { - stateiter->second.mGroups = groups; - resetActiveGroups(); - } - return; - } -} - -void Animation::stopLooping(const std::string& groupname) -{ - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - stateiter->second.mLoopCount = 0; - return; - } -} - -void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) -{ - if(!mSkelBase || mAnimSources.empty()) - return; - - if(groupname.empty()) - { - resetActiveGroups(); - return; - } - - priority = std::max(0, priority); - - AnimStateMap::iterator stateiter = mStates.begin(); - while(stateiter != mStates.end()) - { - if(stateiter->second.mPriority == priority) - mStates.erase(stateiter++); - else - ++stateiter; - } - - stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - stateiter->second.mPriority = priority; - resetActiveGroups(); - return; - } - - /* Look in reverse; last-inserted source has priority. */ - AnimState state; - AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); - for(;iter != mAnimSources.rend();++iter) - { - const NifOgre::TextKeyMap &textkeys = (*iter)->mTextKeys; - if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) - { - state.mSource = *iter; - state.mSpeedMult = speedmult; - state.mLoopCount = loops; - state.mPlaying = (state.mTime < state.mStopTime); - state.mPriority = priority; - state.mGroups = groups; - state.mAutoDisable = autodisable; - mStates[groupname] = state; - - NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - if (state.mPlaying) - { - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, groupname, textkey, textkeys); - ++textkey; - } - } - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - { - state.mLoopCount--; - state.mTime = state.mLoopStartTime; - state.mPlaying = true; - if(state.mTime >= state.mLoopStopTime) - break; - - NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, groupname, textkey, textkeys); - ++textkey; - } - } - - break; - } - } - if(iter == mAnimSources.rend()) - std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); - } -} - -void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) -{ - AnimStateMap::iterator state(mStates.find(groupname)); - if(state != mStates.end()) - state->second.mSpeedMult = speedmult; -} - -bool Animation::isPlaying(const std::string &groupname) const -{ - AnimStateMap::const_iterator state(mStates.find(groupname)); - if(state != mStates.end()) - return state->second.mPlaying; - return false; -} - -void Animation::resetActiveGroups() -{ - for(size_t grp = 0;grp < sNumGroups;grp++) - { - AnimStateMap::const_iterator active = mStates.end(); - - AnimStateMap::const_iterator state = mStates.begin(); - for(;state != mStates.end();++state) - { - if(!(state->second.mGroups&(1<second.mPriority < state->second.mPriority) - active = state; - } - - mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? - std::string() : active->first); - } - mNonAccumCtrl = NULL; - - if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) - return; - - AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); - if(state == mStates.end()) - { - if (mAccumRoot && mNonAccumRoot) - mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); - return; - } - - const Ogre::SharedPtr &animsrc = state->second.mSource; - const std::vector >&ctrls = animsrc->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) - { - mNonAccumCtrl = dstval; - break; - } - } - - if (mAccumRoot && mNonAccumCtrl) - mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); -} - - -bool Animation::getInfo(const std::string &groupname, float *complete, float *speedmult) const -{ - AnimStateMap::const_iterator iter = mStates.find(groupname); - if(iter == mStates.end()) - { - if(complete) *complete = 0.0f; - if(speedmult) *speedmult = 0.0f; - return false; - } - - if(complete) - { - if(iter->second.mStopTime > iter->second.mStartTime) - *complete = (iter->second.mTime - iter->second.mStartTime) / - (iter->second.mStopTime - iter->second.mStartTime); - else - *complete = (iter->second.mPlaying ? 0.0f : 1.0f); - } - if(speedmult) *speedmult = iter->second.mSpeedMult; - return true; -} - -float Animation::getStartTime(const std::string &groupname) const -{ - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) - { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - - NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); - if(found != keys.end()) - return found->first; - } - return -1.f; -} - -float Animation::getTextKeyTime(const std::string &textKey) const -{ - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) - { - const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - - for(NifOgre::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) - { - if(iterKey->second.compare(0, textKey.size(), textKey) == 0) - return iterKey->first; - } - } - - return -1.f; -} - -float Animation::getCurrentTime(const std::string &groupname) const -{ - AnimStateMap::const_iterator iter = mStates.find(groupname); - if(iter == mStates.end()) - return -1.f; - - return iter->second.mTime; -} - -void Animation::disable(const std::string &groupname) -{ - AnimStateMap::iterator iter = mStates.find(groupname); - if(iter != mStates.end()) - mStates.erase(iter); - resetActiveGroups(); -} - - -Ogre::Vector3 Animation::runAnimation(float duration) -{ - Ogre::Vector3 movement(0.0f); - AnimStateMap::iterator stateiter = mStates.begin(); - while(stateiter != mStates.end()) - { - AnimState &state = stateiter->second; - const NifOgre::TextKeyMap &textkeys = state.mSource->mTextKeys; - NifOgre::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); - - float timepassed = duration * state.mSpeedMult; - while(state.mPlaying) - { - float targetTime; - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - goto handle_loop; - - targetTime = state.mTime + timepassed; - if(textkey == textkeys.end() || textkey->first > targetTime) - { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, targetTime, movement); - state.mTime = std::min(targetTime, state.mStopTime); - } - else - { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, textkey->first, movement); - state.mTime = textkey->first; - } - - state.mPlaying = (state.mTime < state.mStopTime); - timepassed = targetTime - state.mTime; - - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, stateiter->first, textkey, textkeys); - ++textkey; - } - - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) - { - handle_loop: - state.mLoopCount--; - state.mTime = state.mLoopStartTime; - state.mPlaying = true; - - textkey = textkeys.lower_bound(state.mTime); - while(textkey != textkeys.end() && textkey->first <= state.mTime) - { - handleTextKey(state, stateiter->first, textkey, textkeys); - ++textkey; - } - - if(state.mTime >= state.mLoopStopTime) - break; - } - - if(timepassed <= 0.0f) - break; - } - - if(!state.mPlaying && state.mAutoDisable) - { - mStates.erase(stateiter++); - - resetActiveGroups(); - } - else - ++stateiter; - } - - for(size_t i = 0;i < mObjectRoot->mControllers.size();i++) - { - if(!mObjectRoot->mControllers[i].getSource().isNull()) - mObjectRoot->mControllers[i].update(); - } - - // Apply group controllers - for(size_t grp = 0;grp < sNumGroups;grp++) - { - const std::string &name = mAnimationTimePtr[grp]->getAnimName(); - if(!name.empty() && (stateiter=mStates.find(name)) != mStates.end()) - { - const Ogre::SharedPtr &src = stateiter->second.mSource; - for(size_t i = 0;i < src->mControllers[grp].size();i++) - src->mControllers[grp][i].update(); - } - } - - if(mSkelBase) - { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); - } - - updateEffects(duration); - - return movement; -} - -void Animation::showWeapons(bool showWeapon) -{ -} - - -class ToggleLight { - bool mEnable; - -public: - ToggleLight(bool enable) : mEnable(enable) { } - - void operator()(Ogre::Light *light) const - { light->setVisible(mEnable); } -}; - -void Animation::enableLights(bool enable) -{ - std::for_each(mObjectRoot->mLights.begin(), mObjectRoot->mLights.end(), ToggleLight(enable)); -} - - -class MergeBounds { - Ogre::AxisAlignedBox *mBounds; - -public: - MergeBounds(Ogre::AxisAlignedBox *bounds) : mBounds(bounds) { } - - void operator()(Ogre::MovableObject *obj) - { - mBounds->merge(obj->getWorldBoundingBox(true)); - } -}; - -Ogre::AxisAlignedBox Animation::getWorldBounds() -{ - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - std::for_each(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(), MergeBounds(&bounds)); - return bounds; -} - - -Ogre::TagPoint *Animation::attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj) -{ - Ogre::TagPoint *tag = NULL; - Ogre::SkeletonInstance *skel = (mSkelBase ? mSkelBase->getSkeleton() : NULL); - if(skel && skel->hasBone(bonename)) - { - tag = mSkelBase->attachObjectToBone(bonename, obj); - mAttachedObjects[obj] = bonename; - } - return tag; -} - -void Animation::detachObjectFromBone(Ogre::MovableObject *obj) -{ - ObjectAttachMap::iterator iter = mAttachedObjects.find(obj); - if(iter != mAttachedObjects.end()) - mAttachedObjects.erase(iter); - mSkelBase->detachObjectFromBone(obj); -} - -bool Animation::upperBodyReady() const -{ - for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) - { - if((stateiter->second.mPriority > MWMechanics::Priority_Movement - && stateiter->second.mPriority < MWMechanics::Priority_Torch) - || stateiter->second.mPriority == MWMechanics::Priority_Death) - return false; - } - return true; -} - -void Animation::addEffect(const std::string &model, int effectId, bool loop, const std::string &bonename, std::string texture) -{ - // Early out if we already have this effect - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) - return; - - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture); - - EffectParams params; - params.mModelName = model; - if (bonename.empty()) - params.mObjects = NifOgre::Loader::createObjects(mInsert, model); - else - { - if (!mSkelBase) - return; - params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); - } - - setRenderProperties(params.mObjects, RV_Effects, - RQG_Main, RQG_Alpha, 0.f, false, NULL); - - params.mLoop = loop; - params.mEffectId = effectId; - params.mBoneName = bonename; - - for(size_t i = 0;i < params.mObjects->mControllers.size();i++) - { - if(params.mObjects->mControllers[i].getSource().isNull()) - params.mObjects->mControllers[i].setSource(Ogre::SharedPtr (new EffectAnimationTime())); - } - - - // Do some manual adjustments on the created entities/particle systems - - // It looks like vanilla MW totally ignores lighting settings for effects attached to characters. - // If we don't do this, some effects will look way too dark depending on the environment - // (e.g. magic_cast_dst.nif). They were clearly meant to use emissive lighting. - // We used to have this hack in the NIF material loader, but for effects not attached to characters - // (e.g. ash storms) the lighting settings do seem to be in use. Is there maybe a flag we have missed? - Ogre::ColourValue ambient = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue diffuse = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue specular = Ogre::ColourValue(0.f, 0.f, 0.f); - Ogre::ColourValue emissive = Ogre::ColourValue(1.f, 1.f, 1.f); - for(size_t i = 0;i < params.mObjects->mParticles.size(); ++i) - { - Ogre::ParticleSystem* partSys = params.mObjects->mParticles[i]; - - Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(partSys); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - - pass->setAmbient(ambient); - pass->setDiffuse(diffuse); - pass->setSpecular(specular); - pass->setEmissive(emissive); - - if (!texture.empty()) - { - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } - for(size_t i = 0;i < params.mObjects->mEntities.size(); ++i) - { - Ogre::Entity* ent = params.mObjects->mEntities[i]; - if (ent == params.mObjects->mSkelBase) - continue; - Ogre::MaterialPtr mat = params.mObjects->mMaterialControllerMgr.getWritableMaterial(ent); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - - pass->setAmbient(ambient); - pass->setDiffuse(diffuse); - pass->setSpecular(specular); - pass->setEmissive(emissive); - - if (!texture.empty()) - { - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } - - mEffects.push_back(params); -} - -void Animation::removeEffect(int effectId) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - if (it->mEffectId == effectId) - { - mEffects.erase(it); - return; - } - } -} - -void Animation::getLoopingEffects(std::vector &out) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - if (it->mLoop) - out.push_back(it->mEffectId); - } -} - -void Animation::updateEffects(float duration) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ) - { - NifOgre::ObjectScenePtr objects = it->mObjects; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->addTime(duration); - - objects->mControllers[i].update(); - } - - if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength) - { - if (it->mLoop) - { - // Start from the beginning again; carry over the remainder - float remainder = objects->mControllers[0].getSource()->getValue() - objects->mMaxControllerLength; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->resetTime(remainder); - } - } - else - { - it = mEffects.erase(it); - continue; - } - } - ++it; - } -} - -void Animation::preRender(Ogre::Camera *camera) -{ - for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) - { - NifOgre::ObjectScenePtr objects = it->mObjects; - objects->rotateBillboardNodes(camera); - } - mObjectRoot->rotateBillboardNodes(camera); -} - -// TODO: Should not be here -Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item) -{ - Ogre::Vector3 result(1,1,1); - std::string enchantmentName = item.getClass().getEnchantment(item); - if (enchantmentName.empty()) - return result; - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); - assert (enchantment->mEffects.mList.size()); - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - enchantment->mEffects.mList.front().mEffectID); - result.x = magicEffect->mData.mRed / 255.f; - result.y = magicEffect->mData.mGreen / 255.f; - result.z = magicEffect->mData.mBlue / 255.f; - return result; -} - -void Animation::setLightEffect(float effect) -{ - if (effect == 0) - { - if (mGlowLight) - { - mInsert->getCreator()->destroySceneNode(mGlowLight->getParentSceneNode()); - mInsert->getCreator()->destroyLight(mGlowLight); - mGlowLight = NULL; - } - } - else - { - if (!mGlowLight) - { - mGlowLight = mInsert->getCreator()->createLight(); - - Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - for(size_t i = 0;i < mObjectRoot->mEntities.size();i++) - { - Ogre::Entity *ent = mObjectRoot->mEntities[i]; - bounds.merge(ent->getBoundingBox()); - } - mInsert->createChildSceneNode(bounds.getCenter())->attachObject(mGlowLight); - } - mGlowLight->setType(Ogre::Light::LT_POINT); - effect += 3; - mGlowLight->setAttenuation(1.0f / (0.03f * (0.5f/effect)), 0, 0.5f/effect, 0); - } -} - - -ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model) - : Animation(ptr, ptr.getRefData().getBaseNode()) -{ - if (!model.empty()) - { - setObjectRoot(model, false); - - Ogre::Vector3 extents = getWorldBounds().getSize(); - float size = std::max(std::max(extents.x, extents.y), extents.z); - - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; - - float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f; - Ogre::Vector3 col = getEnchantmentColor(ptr); - setRenderProperties(mObjectRoot, (mPtr.getTypeName() == typeid(ESM::Static).name()) ? - (small ? RV_StaticsSmall : RV_Statics) : RV_Misc, - RQG_Main, RQG_Alpha, dist, !ptr.getClass().getEnchantment(ptr).empty(), &col); - } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } -} - - -class FindEntityTransparency { -public: - bool operator()(Ogre::Entity *ent) const - { - unsigned int numsubs = ent->getNumSubEntities(); - for(unsigned int i = 0;i < numsubs;++i) - { - sh::Factory::getInstance()._ensureMaterial(ent->getSubEntity(i)->getMaterial()->getName(), "Default"); - if(ent->getSubEntity(i)->getMaterial()->isTransparent()) - return true; - } - return false; - } -}; - -bool ObjectAnimation::canBatch() const -{ - if(!mObjectRoot->mParticles.empty() || !mObjectRoot->mLights.empty() || !mObjectRoot->mControllers.empty()) - return false; - if (!mObjectRoot->mBillboardNodes.empty()) - return false; - return std::find_if(mObjectRoot->mEntities.begin(), mObjectRoot->mEntities.end(), - FindEntityTransparency()) == mObjectRoot->mEntities.end(); -} - -void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg) -{ - std::vector::reverse_iterator iter = mObjectRoot->mEntities.rbegin(); - for(;iter != mObjectRoot->mEntities.rend();++iter) - { - Ogre::Node *node = (*iter)->getParentNode(); - if ((*iter)->isVisible()) - sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); - } -} - } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dab8cfebb7..cbded364a6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -4,15 +4,20 @@ #include #include -#include - #include "../mwworld/ptr.hpp" +#include + namespace ESM { struct Light; } +namespace Resource +{ + class ResourceSystem; +} + namespace MWRender { class Camera; @@ -69,20 +74,18 @@ protected: virtual void setValue(Ogre::Real value); }; - - - class NullAnimationTime : public Ogre::ControllerValue + class NullAnimationTime : public NifOsg::ControllerSource { public: - virtual Ogre::Real getValue() const - { return 0.0f; } - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor *nv) + { + return 0.f; + } }; struct AnimSource : public Ogre::AnimationAlloc { - NifOgre::TextKeyMap mTextKeys; + //NifOgre::TextKeyMap mTextKeys; std::vector > mControllers[sNumGroups]; }; typedef std::vector< Ogre::SharedPtr > AnimSourceList; @@ -113,106 +116,71 @@ protected: typedef std::map ObjectAttachMap; - struct EffectParams - { - std::string mModelName; // Just here so we don't add the same effect twice - NifOgre::ObjectScenePtr mObjects; - int mEffectId; - bool mLoop; - std::string mBoneName; - }; + osg::ref_ptr mInsert; - std::vector mEffects; + osg::ref_ptr mObjectRoot; MWWorld::Ptr mPtr; - Ogre::Light* mGlowLight; - - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - NifOgre::ObjectScenePtr mObjectRoot; - AnimSourceList mAnimSources; - Ogre::Node *mAccumRoot; - Ogre::Node *mNonAccumRoot; - NifOgre::NodeTargetValue *mNonAccumCtrl; - Ogre::Vector3 mAccumulate; - - AnimStateMap mStates; - - Ogre::SharedPtr mAnimationTimePtr[sNumGroups]; - Ogre::SharedPtr mNullAnimationTimePtr; - - ObjectAttachMap mAttachedObjects; - + Resource::ResourceSystem* mResourceSystem; /* Sets the appropriate animations on the bone groups based on priority. */ - void resetActiveGroups(); + //void resetActiveGroups(); - static size_t detectAnimGroup(const Ogre::Node *node); + //static size_t detectAnimGroup(const Ogre::Node *node); + /* static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname); - - /* Updates a skeleton instance so that all bones matching the source skeleton (based on - * bone names) are positioned identically. */ - void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + */ /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ - void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); + //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); - static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + //static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, - const std::string &groupname, const std::string &start, const std::string &stop, - float startpoint, bool loopfallback); + //bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, + // const std::string &groupname, const std::string &start, const std::string &stop, + // float startpoint, bool loopfallback); - void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - const NifOgre::TextKeyMap& map); + //void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, + // const NifOgre::TextKeyMap& map); - /* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle - * systems in the model are ignored (useful for NPCs, where only the skeleton is needed for - * the root). + /* Sets the root model of the object. * * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. */ - void setObjectRoot(const std::string &model, bool baseonly); + void setObjectRoot(const std::string &model); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif * extension will be replaced with .kf. */ - void addAnimSource(const std::string &model); + //void addAnimSource(const std::string &model); /** Adds an additional light to the given object list using the specified ESM record. */ - void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); + //void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); - void clearAnimSources(); - - // TODO: Should not be here - Ogre::Vector3 getEnchantmentColor(MWWorld::Ptr item); + //void clearAnimSources(); public: - // FIXME: Move outside of this class - static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, - Ogre::uint8 transqueue, Ogre::Real dist=0.0f, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); - /// Returns the name of the .nif file that makes up this animation's base skeleton. - /// If there is no skeleton, returns "". - std::string getObjectRootName() const; - - Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node); + Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + osg::Group* getOrCreateObjectRoot(); + + osg::Group* getObjectRoot(); + /** * @brief Add an effect mesh attached to a bone or the insert scene node * @param model @@ -223,25 +191,18 @@ public: * @param texture override the texture specified in the model's materials * @note Will not add an effect twice. */ - void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); - void removeEffect (int effectId); - void getLoopingEffects (std::vector& out); + //void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); + //void removeEffect (int effectId); + //void getLoopingEffects (std::vector& out); - /// Prepare this animation for being rendered with \a camera (rotates billboard nodes) - virtual void preRender (Ogre::Camera* camera); + //void updatePtr(const MWWorld::Ptr &ptr); - virtual void setAlpha(float alpha) {} - virtual void setVampire(bool vampire) {} - -public: - void updatePtr(const MWWorld::Ptr &ptr); - - bool hasAnimation(const std::string &anim); + //bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value // should be on the scale of 0 to 1. - void setAccumulation(const Ogre::Vector3 &accum); + //void setAccumulation(const Ogre::Vector3 &accum); /** Plays an animation. * \param groupname Name of the animation group to play. @@ -263,23 +224,23 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int groups, bool autodisable, - float speedmult, const std::string &start, const std::string &stop, - float startpoint, size_t loops, bool loopfallback=false); + //void play(const std::string &groupname, int priority, int groups, bool autodisable, + // float speedmult, const std::string &start, const std::string &stop, + // float startpoint, size_t loops, bool loopfallback=false); /** If the given animation group is currently playing, set its remaining loop count to '0'. */ - void stopLooping(const std::string& groupName); + //void stopLooping(const std::string& groupName); /** Adjust the speed multiplier of an already playing animation. */ - void adjustSpeedMult (const std::string& groupname, float speedmult); + //void adjustSpeedMult (const std::string& groupname, float speedmult); /** Returns true if the named animation group is playing. */ - bool isPlaying(const std::string &groupname) const; + //bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. - bool upperBodyReady() const; + //bool upperBodyReady() const; /** Gets info about the given animation group. * \param groupname Animation group to check. @@ -287,71 +248,32 @@ public: * \param speedmult Stores the animation speed multiplier * \return True if the animation is active, false otherwise. */ - bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; + //bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - float getStartTime(const std::string &groupname) const; + //float getStartTime(const std::string &groupname) const; /// Get the absolute position in the animation track of the text key - float getTextKeyTime(const std::string &textKey) const; + //float getTextKeyTime(const std::string &textKey) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. - float getCurrentTime(const std::string& groupname) const; + //float getCurrentTime(const std::string& groupname) const; /** Disables the specified animation group; * \param groupname Animation group to disable. */ - void disable(const std::string &groupname); - void changeGroups(const std::string &groupname, int group); - - virtual void setWeaponGroup(const std::string& group) {} + //void disable(const std::string &groupname); + //void changeGroups(const std::string &groupname, int group); /** Retrieves the velocity (in units per second) that the animation will move. */ - float getVelocity(const std::string &groupname) const; + //float getVelocity(const std::string &groupname) const; - /// A relative factor (0-1) that decides if and how much the skeleton should be pitched - /// to indicate the facing orientation of the character. - virtual void setPitchFactor(float factor) {} - virtual void setHeadPitch(Ogre::Radian factor) {} - virtual void setHeadYaw(Ogre::Radian factor) {} - virtual Ogre::Radian getHeadPitch() const { return Ogre::Radian(0.f); } - virtual Ogre::Radian getHeadYaw() const { return Ogre::Radian(0.f); } - - virtual Ogre::Vector3 runAnimation(float duration); - - /// This is typically called as part of runAnimation, but may be called manually if needed. - void updateEffects(float duration); - - // TODO: move outside of this class - /// Makes this object glow, by placing a Light in its center. - /// @param effect Controls the radius and intensity of the light. - void setLightEffect(float effect); - - virtual void showWeapons(bool showWeapon); - virtual void showCarriedLeft(bool show) {} - virtual void attachArrow() {} - virtual void releaseArrow() {} - void enableLights(bool enable); - virtual void enableHeadAnimation(bool enable) {} - - Ogre::AxisAlignedBox getWorldBounds(); - - Ogre::Node *getNode(const std::string &name); - Ogre::Node *getNode(int handle); - - // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't - // exist, the object isn't attached and NULL is returned. The returned TagPoint is only - // valid until the next setObjectRoot call. - Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj); - void detachObjectFromBone(Ogre::MovableObject *obj); + virtual osg::Vec3f runAnimation(float duration); }; class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model); - - bool canBatch() const; - void fillBatch(Ogre::StaticGeometry *sg); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3c6a507e7d..6d37fa1e8a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -2,110 +2,204 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#include -#include +#include +#include -//#include -#include +// light +#include + +#include + +#include +#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "renderconst.hpp" -//#include "animation.hpp" +#include "animation.hpp" -using namespace MWRender; - -int Objects::uniqueID = 0; - -void Objects::setRootNode(Ogre::SceneNode* root) +namespace { - mRootNode = root; + + /// Removes all particle systems and related nodes in a subgraph. + class RemoveParticlesVisitor : public osg::NodeVisitor + { + public: + RemoveParticlesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { } + + virtual void apply(osg::Node &node) + { + if (dynamic_cast(&node) || dynamic_cast(&node)) + mToRemove.push_back(&node); + + traverse(node); + } + + void remove() + { + for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + mToRemove.clear(); + } + + private: + std::vector > mToRemove; + }; + +} + + +namespace MWRender +{ + +Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) + : mResourceSystem(resourceSystem) + , mRootNode(rootNode) +{ +} + +Objects::~Objects() +{ + for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();++iter) + delete iter->second; + mObjects.clear(); + + for (CellMap::iterator iter = mCellSceneNodes.begin(); iter != mCellSceneNodes.end(); ++iter) + iter->second->getParent(0)->removeChild(iter->second); + mCellSceneNodes.clear(); } void Objects::insertBegin(const MWWorld::Ptr& ptr) { - Ogre::SceneNode* root = mRootNode; - Ogre::SceneNode* cellnode; - if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) + osg::ref_ptr cellnode; + + CellMap::iterator found = mCellSceneNodes.find(ptr.getCell()); + if (found == mCellSceneNodes.end()) { - //Create the scenenode and put it in the map - cellnode = root->createChildSceneNode(); + cellnode = new osg::Group; + mRootNode->addChild(cellnode); mCellSceneNodes[ptr.getCell()] = cellnode; } else - { - cellnode = mCellSceneNodes[ptr.getCell()]; - } + cellnode = found->second; + + osg::ref_ptr insert (new osg::PositionAttitudeTransform); + cellnode->addChild(insert); - Ogre::SceneNode* insert = cellnode->createChildSceneNode(); const float *f = ptr.getRefData().getPosition().pos; - insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); - + insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + insert->setScale(osg::Vec3(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale())); // Convert MW rotation to a quaternion: f = ptr.getCellRef().getPosition().rot; // Rotate around X axis - Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); + osg::Quat xr(-f[0], osg::Vec3(1,0,0)); // Rotate around Y axis - Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y); + osg::Quat yr(-f[1], osg::Vec3(0,1,0)); // Rotate around Z axis - Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); + osg::Quat zr(-f[2], osg::Vec3(0,0,1)); // Rotates first around z, then y, then x - insert->setOrientation(xr*yr*zr); + insert->setAttitude(zr*yr*xr); + + // TODO: actors rotate around z only ptr.getRefData().setBaseNode(insert); } -void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) +void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight) { insertBegin(ptr); -/* - std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); - if (!mesh.empty()) + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { - Ogre::AxisAlignedBox bounds = anim->getWorldBounds(); - Ogre::Vector3 extents = bounds.getSize(); - extents *= ptr.getRefData().getBaseNode()->getScale(); - float size = std::max(std::max(extents.x, extents.y), extents.z); + SceneUtil::FindByNameVisitor visitor("AttachLight"); + ptr.getRefData().getBaseNode()->accept(visitor); - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; + osg::Vec3f lightOffset (0.f, 0.f, 0.f); - if (mBounds.find(ptr.getCell()) == mBounds.end()) - mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - mBounds[ptr.getCell()].merge(bounds); + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + osg::Group* objectRoot = anim->getOrCreateObjectRoot(); + objectRoot->accept(computeBound); + lightOffset = computeBound.getBoundingBox().center(); + + attachTo = objectRoot; + } + + const ESM::Light* esmLight = ptr.get()->mBase; + + osg::ref_ptr lightSource = new SceneUtil::LightSource; + osg::Light* light = new osg::Light; + lightSource->setLight(light); + light->setPosition(osg::Vec4f(lightOffset.x(), lightOffset.y(), lightOffset.z(), 1.f)); + + float realRadius = esmLight->mData.mRadius * 2; + + lightSource->setRadius(realRadius); + light->setLinearAttenuation(10.f/realRadius); + //light->setLinearAttenuation(0.05); + light->setConstantAttenuation(0.f); + + light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + + attachTo->addChild(lightSource); + } + if (!allowLight) + { + RemoveParticlesVisitor visitor; + anim->getObjectRoot()->accept(visitor); + visitor.remove(); } - if(anim.get() != NULL) - mObjects.insert(std::make_pair(ptr, anim.release())); - */ + mObjects.insert(std::make_pair(ptr, anim.release())); +} + +void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields) +{ + insertBegin(ptr); + + // CreatureAnimation + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + mObjects.insert(std::make_pair(ptr, anim.release())); +} + +void Objects::insertNPC(const MWWorld::Ptr &ptr) +{ + } bool Objects::deleteObject (const MWWorld::Ptr& ptr) { - /* if(!ptr.getRefData().getBaseNode()) return true; @@ -115,18 +209,16 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr) delete iter->second; mObjects.erase(iter); - mRenderer.getScene()->destroySceneNode(ptr.getRefData().getBaseNode()); - ptr.getRefData().setBaseNode(0); + ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); + ptr.getRefData().setBaseNode(NULL); return true; } -*/ return false; } -void Objects::removeCell(MWWorld::CellStore* store) +void Objects::removeCell(const MWWorld::CellStore* store) { - /* for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();) { if(iter->first.getCell() == store) @@ -138,46 +230,19 @@ void Objects::removeCell(MWWorld::CellStore* store) ++iter; } - std::map::iterator geom = mStaticGeometry.find(store); - if(geom != mStaticGeometry.end()) - { - Ogre::StaticGeometry *sg = geom->second; - mStaticGeometry.erase(geom); - mRenderer.getScene()->destroyStaticGeometry(sg); - } - - geom = mStaticGeometrySmall.find(store); - if(geom != mStaticGeometrySmall.end()) - { - Ogre::StaticGeometry *sg = geom->second; - mStaticGeometrySmall.erase(store); - mRenderer.getScene()->destroyStaticGeometry(sg); - } - - mBounds.erase(store); - - std::map::iterator cell = mCellSceneNodes.find(store); + CellMap::iterator cell = mCellSceneNodes.find(store); if(cell != mCellSceneNodes.end()) { - cell->second->removeAndDestroyAllChildren(); - mRenderer.getScene()->destroySceneNode(cell->second); + cell->second->getParent(0)->removeChild(cell->second); mCellSceneNodes.erase(cell); } - */ -} - -Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) -{ - return mBounds[cell]; } void Objects::update(float dt, Ogre::Camera* camera) { - /* PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) it->second->runAnimation(dt); - */ } void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) @@ -206,13 +271,13 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) */ } -ObjectAnimation* Objects::getAnimation(const MWWorld::Ptr &ptr) +Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) { - /* PtrAnimationMap::const_iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) return iter->second; - */ + return NULL; } +} diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b2f07ab0fc..44334e4447 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -1,10 +1,16 @@ #ifndef GAME_RENDER_OBJECTS_H #define GAME_RENDER_OBJECTS_H -#include #include -#include +#include + +#include + +namespace osg +{ + class Group; +} namespace MWWorld { @@ -14,53 +20,52 @@ namespace MWWorld namespace MWRender{ -class ObjectAnimation; +class Animation; + class Objects{ - typedef std::map PtrAnimationMap; + typedef std::map PtrAnimationMap; - OEngine::Render::OgreRenderer &mRenderer; - - std::map mCellSceneNodes; - std::map mStaticGeometry; - std::map mStaticGeometrySmall; - std::map mBounds; + typedef std::map > CellMap; + CellMap mCellSceneNodes; PtrAnimationMap mObjects; - Ogre::SceneNode* mRootNode; - - static int uniqueID; + osg::ref_ptr mRootNode; void insertBegin(const MWWorld::Ptr& ptr); - + Resource::ResourceSystem* mResourceSystem; public: - Objects(OEngine::Render::OgreRenderer &renderer) - : mRenderer(renderer) - , mRootNode(NULL) - {} - ~Objects(){} - void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool batch=false); + Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); + ~Objects(); - ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); + /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? + /// @param allowLight If false, no lights will be created, and particles systems will be cleared then frozen. + void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); + + void insertNPC(const MWWorld::Ptr& ptr); + void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); + + Animation* getAnimation(const MWWorld::Ptr &ptr); void update (float dt, Ogre::Camera* camera); ///< per-frame update - Ogre::AxisAlignedBox getDimensions(MWWorld::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::CellStore* store); - void setRootNode(Ogre::SceneNode* root); - - void rebuildStaticGeometry(); + void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); + +private: + void operator = (const Objects&); + Objects(const Objects&); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c64a265acf..4e5b33c647 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,1046 +1,92 @@ #include "renderingmanager.hpp" -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include -#include +#include -#include -#include +#include -#include +#include -#include -#include -#include +#include -#include "../mwworld/esmstore.hpp" -#include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" - -#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone -#include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" // FIXME -#include "../mwbase/statemanager.hpp" - -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" - -#include "../mwworld/ptr.hpp" - -#include "localmap.hpp" -#include "water.hpp" -#include "npcanimation.hpp" -#include "globalmap.hpp" -#include "terrainstorage.hpp" -#include "effectmanager.hpp" - -using namespace MWRender; -using namespace Ogre; - -namespace MWRender { - -RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, - MWWorld::Fallback* fallback) - : mRendering(_rend) - , mFallback(fallback) - , mPlayerAnimation(NULL) - , mSunEnabled(0) - , mPhysicsEngine(engine) - , mTerrain(NULL) - , mEffectManager(NULL) - , mRenderWorld(true) +namespace MWRender { - mActors = new MWRender::Actors(mRendering, this); - mObjects = new MWRender::Objects(mRendering); - mEffectManager = new EffectManager(mRendering.getScene()); - // select best shader mode - bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); - bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos); - // glsl is only supported in opengl mode and hlsl only in direct3d mode. - std::string currentMode = Settings::Manager::getString("shader mode", "General"); - if (currentMode == "" - || (openGL && currentMode == "hlsl") - || (!openGL && currentMode == "glsl") - || (glES && currentMode != "glsles")) + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mRootNode(rootNode) + , mResourceSystem(resourceSystem) { - Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); + osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setStartLight(1); + + mRootNode->addChild(lightRoot); + + mObjects.reset(new Objects(mResourceSystem, lightRoot)); + + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); + + osg::ref_ptr source = new osg::LightSource; + mSunLight = new osg::Light; + source->setLight(mSunLight); + mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); + mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); + mSunLight->setConstantAttenuation(1.f); + source->setStateSetModes(*rootNode->getOrCreateStateSet(), osg::StateAttribute::ON); + lightRoot->addChild(source); + + rootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + rootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + // for consistent benchmarks against the ogre branch. remove later + osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); + cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + viewer.getCamera()->setCullingMode( cullingMode ); } - mRendering.adjustCamera(Settings::Manager::getFloat("field of view", "General"), 5); - - mRendering.getWindow()->addListener(this); - mRendering.setWindowListener(this); - - mWater = 0; - - // material system - sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string()); - if (!boost::filesystem::exists (cacheDir)) - boost::filesystem::create_directories (cacheDir); - platform->setCacheFolder (cacheDir.string()); - 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 == "glsles") - lang = sh::Language_GLSLES; - else if (l == "hlsl") - lang = sh::Language_HLSL; - else - lang = sh::Language_CG; - mFactory->setCurrentLanguage (lang); - mFactory->setWriteSourceCache (true); - mFactory->setReadSourceCache (true); - mFactory->setReadMicrocodeCache (true); - mFactory->setWriteMicrocodeCache (true); - - mFactory->loadAllFiles(); - - TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); - - // Set default texture filtering options - TextureFilterOptions tfo; - std::string filter = Settings::Manager::getString("texture filtering", "General"); - - if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; - else if (filter == "trilinear") tfo = TFO_TRILINEAR; - else if (filter == "bilinear") tfo = TFO_BILINEAR; - else /*if (filter == "none")*/ tfo = TFO_NONE; - - MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); - MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - - Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024); - Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024); - - Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - - // disable unsupported effects - 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 ("fog", "true"); - sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); - sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); - - 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.5f, -0.8f, 0.2f))); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6f))); - sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); - sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); - - mRootNode = mRendering.getScene()->getRootSceneNode(); - mRootNode->createChildSceneNode("player"); - - mObjects->setRootNode(mRootNode); - mActors->setRootNode(mRootNode); - - mCamera = new MWRender::Camera(mRendering.getCamera()); - - mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); - - mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - - mSun = 0; - - mLocalMap = new MWRender::LocalMap(&mRendering, this); - - mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); - - setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); -} - -RenderingManager::~RenderingManager () -{ - mRendering.getWindow()->removeListener(this); - - delete mPlayerAnimation; - delete mCamera; - delete mSkyManager; - delete mTerrain; - delete mLocalMap; - delete mOcclusionQuery; - delete mWater; - delete mActors; - delete mObjects; - delete mEffectManager; - delete mFactory; -} - -MWRender::SkyManager* RenderingManager::getSkyManager() -{ - return mSkyManager; -} - -MWRender::Objects& RenderingManager::getObjects(){ - return *mObjects; -} -MWRender::Actors& RenderingManager::getActors(){ - return *mActors; -} - -MWRender::Camera* RenderingManager::getCamera() const -{ - return mCamera; -} - -void RenderingManager::removeCell (MWWorld::CellStore *store) -{ - if (store->isExterior()) - mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - - mLocalMap->saveFogOfWar(store); - mObjects->removeCell(store); - mActors->removeCell(store); -} - -void RenderingManager::removeWater () -{ - mWater->setActive(false); -} - -bool RenderingManager::toggleWater() -{ - return mWater->toggle(); -} - -bool RenderingManager::toggleWorld() -{ - mRenderWorld = !mRenderWorld; - - int visibilityMask = mRenderWorld ? ~int(0) : 0; - mRendering.getViewport()->setVisibilityMask(visibilityMask); - return mRenderWorld; -} - -void RenderingManager::cellAdded (MWWorld::CellStore *store) -{ - if (store->isExterior()) - mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - - mObjects->buildStaticGeometry (*store); - sh::Factory::getInstance().unloadUnreferencedMaterials(); -} - -void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ - const MWWorld::Class& class_ = - ptr.getClass(); - class_.insertObjectRendering(ptr, model, *this); -} - -void RenderingManager::removeObject (const MWWorld::Ptr& ptr) -{ - if (!mObjects->deleteObject (ptr)) - mActors->deleteObject (ptr); -} - -void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) -{ - /// \todo move this to the rendering-subsystems - ptr.getRefData().getBaseNode()->setPosition(position); -} - -void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) -{ - ptr.getRefData().getBaseNode()->setScale(scale); -} - -void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) -{ - Ogre::Vector3 rot(ptr.getRefData().getPosition().rot); - - if(ptr.getRefData().getHandle() == mCamera->getHandle() && - !mCamera->isVanityOrPreviewModeEnabled()) - mCamera->rotateCamera(-rot, false); - - Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z); - if(!ptr.getClass().isActor()) - newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) * - Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo; - ptr.getRefData().getBaseNode()->setOrientation(newo); -} - -void -RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) -{ - if (!old.getRefData().getBaseNode()) - return; - Ogre::SceneNode *child = - mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); - - Ogre::SceneNode *parent = child->getParentSceneNode(); - parent->removeChild(child); - - if (old.getClass().isActor()) { - mActors->updateObjectCell(old, cur); - } else { - mObjects->updateObjectCell(old, cur); - } -} - -void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) -{ - if(mPlayerAnimation) - mPlayerAnimation->updatePtr(ptr); - if(mCamera->getHandle() == ptr.getRefData().getHandle()) - attachCameraTo(ptr); -} - -void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) -{ - NpcAnimation *anim = NULL; - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - anim = mPlayerAnimation; - else if(ptr.getClass().isActor()) - anim = dynamic_cast(mActors->getAnimation(ptr)); - if(anim) + MWRender::Objects& RenderingManager::getObjects() { - anim->rebuild(); - if(mCamera->getHandle() == ptr.getRefData().getHandle()) - { - attachCameraTo(ptr); - mCamera->setAnimation(anim); - } + return *mObjects.get(); } -} -void RenderingManager::update (float duration, bool paused) -{ - if (MWBase::Environment::get().getStateManager()->getState()== - MWBase::StateManager::State_NoGame) - return; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - MWWorld::Ptr player = world->getPlayerPtr(); - - int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); - MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); - setAmbientMode(); - - if (player.getClass().getNpcStats(player).isWerewolf()) - MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mCamera->isFirstPerson()); - - // player position - MWWorld::RefData &data = player.getRefData(); - Ogre::Vector3 playerPos(data.getPosition().pos); - - mCamera->setCameraDistance(); - if(!mCamera->isFirstPerson()) + MWRender::Actors& RenderingManager::getActors() { - Ogre::Vector3 orig, dest; - mCamera->getPosition(orig, dest); - - btVector3 btOrig(orig.x, orig.y, orig.z); - btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5f, btOrig, btDest); - if(test.first) - mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); + throw std::runtime_error("unimplemented"); } - // Sink the camera while sneaking - bool isSneaking = player.getClass().getCreatureStats(player).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool isInAir = !world->isOnGround(player); - bool isSwimming = world->isSwimming(player); - - static const float i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() - .find("i1stPersonSneakDelta")->getFloat(); - if(!paused && isSneaking && !(isSwimming || isInAir)) - mCamera->setSneakOffset(i1stPersonSneakDelta); - - mOcclusionQuery->update(duration); - - mRendering.update(duration); - - Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); - - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - - applyFog(world->isUnderwater(player.getCell(), cam)); - - mCamera->update(duration, paused); - - Ogre::SceneNode *node = data.getBaseNode(); - Ogre::Quaternion orient = node->_getDerivedOrientation(); - mLocalMap->updatePlayer(playerPos, orient); - - if(paused) - return; - - mEffectManager->update(duration, mRendering.getCamera()); - - mActors->update (mRendering.getCamera()); - mPlayerAnimation->preRender(mRendering.getCamera()); - mObjects->update (duration, mRendering.getCamera()); - - mSkyManager->update(duration); - - mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - - mWater->changeCell(player.getCell()->getCell()); - - mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); - - mWater->update(duration, playerPos); -} - -void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) -{ - mOcclusionQuery->setActive(true); -} - -void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt) -{ - // deactivate queries to make sure we aren't getting false results from several misc render targets - // (will be reactivated at the bottom of this method) - mOcclusionQuery->setActive(false); -} - -void RenderingManager::setWaterEnabled(bool enable) -{ - mWater->setActive(enable); -} - -void RenderingManager::setWaterHeight(float height) -{ - mWater->setHeight(height); -} - -void RenderingManager::skyEnable () -{ - mSkyManager->enable(); - mOcclusionQuery->setSunNode(mSkyManager->getSunNode()); -} - -void RenderingManager::skyDisable () -{ - mSkyManager->disable(); -} - -void RenderingManager::skySetHour (double hour) -{ - mSkyManager->setHour(hour); -} - - -void RenderingManager::skySetDate (int day, int month) -{ - mSkyManager->setDate(day, month); -} - -int RenderingManager::skyGetMasserPhase() const -{ - - return mSkyManager->getMasserPhase(); -} - -int RenderingManager::skyGetSecundaPhase() const -{ - return mSkyManager->getSecundaPhase(); -} - -void RenderingManager::skySetMoonColour (bool red){ - mSkyManager->setMoonColour(red); -} - -bool RenderingManager::toggleRenderMode(int mode) -{ -#if 0 - if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid) - return mDebugging->toggleRenderMode(mode); - if (mode == MWBase::World::Render_Wireframe) + Resource::ResourceSystem* RenderingManager::getResourceSystem() { - if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) - { - mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); - return true; - } - else - { - mRendering.getCamera()->setPolygonMode(PM_SOLID); - return false; - } + return mResourceSystem; } - else //if (mode == MWBase::World::Render_BoundingBoxes) + + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - bool show = !mRendering.getScene()->getShowBoundingBoxes(); - mRendering.getScene()->showBoundingBoxes(show); - return show; + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + + mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); + mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } -#endif - return 0; -} -void RenderingManager::configureFog(const MWWorld::CellStore &mCell) -{ - Ogre::ColourValue color; - color.setAsABGR (mCell.getCell()->mAmbi.mFog); - - configureFog (mCell.getCell()->mAmbi.mFogDensity, color); -} - -void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) -{ - mFogColour = colour; - float max = Settings::Manager::getFloat("viewing distance", "Viewing distance"); - - if (density == 0) + osg::Vec3f RenderingManager::getEyePos() { - mFogStart = 0; - mFogEnd = std::numeric_limits::max(); - mRendering.getCamera()->setFarClipDistance (max); + osg::Vec3d eye; + //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); + eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + return eye; } - else + + void RenderingManager::removeCell(const MWWorld::CellStore *store) { - mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - mRendering.getCamera()->setFarClipDistance (max / density); + mObjects->removeCell(store); } } - -void RenderingManager::applyFog (bool underwater) -{ - if (!underwater) - { - mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); - mRendering.getViewport()->setBackgroundColour (mFogColour); - mWater->setViewportBackground (mFogColour); - } - else - { - Ogre::ColourValue clv(0.090195f, 0.115685f, 0.12745f); - mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(clv), 0, 0, 1000); - mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(clv)); - mWater->setViewportBackground (Ogre::ColourValue(clv)); - } -} - -void RenderingManager::setAmbientMode() -{ - setAmbientColour(mAmbientColor); -} - -void RenderingManager::configureAmbient(MWWorld::CellStore &mCell) -{ - if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior) - mAmbientColor.setAsABGR (mCell.getCell()->mAmbi.mAmbient); - setAmbientMode(); - - // Create a "sun" that shines light downwards. It doesn't look - // completely right, but leave it for now. - if(!mSun) - { - mSun = mRendering.getScene()->createLight(); - mSun->setType(Ogre::Light::LT_DIRECTIONAL); - } - if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior) - { - Ogre::ColourValue colour; - colour.setAsABGR (mCell.getCell()->mAmbi.mSunlight); - mSun->setDiffuseColour (colour); - mSun->setDirection(1,-1,-1); - sunEnable(false); - } -} - -void RenderingManager::setSunColour(const Ogre::ColourValue& colour) -{ - if (!mSunEnabled) return; - mSun->setDiffuseColour(colour); - mSun->setSpecularColour(colour); -} - -void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) -{ - mAmbientColor = colour; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); - Ogre::ColourValue final = colour; - final += Ogre::ColourValue(0.7f,0.7f,0.7f,0) * std::min(1.f, (nightEye/100.f)); - - mRendering.getScene()->setAmbientLight(final); -} - -void RenderingManager::sunEnable(bool real) -{ - if (real && mSun) mSun->setVisible(true); - else - { - // Don't disable the light, as the shaders assume the first light to be directional. - mSunEnabled = true; - } -} - -void RenderingManager::sunDisable(bool real) -{ - if (real && mSun) mSun->setVisible(false); - else - { - // Don't disable the light, as the shaders assume the first light to be directional. - mSunEnabled = false; - if (mSun) - { - mSun->setDiffuseColour(ColourValue(0,0,0)); - mSun->setSpecularColour(ColourValue(0,0,0)); - } - } -} - -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) -{ - // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), - if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - - mSkyManager->setSunDirection(direction, is_night); -} - -void RenderingManager::setGlare(bool glare) -{ - mSkyManager->setGlare(glare); -} - -void RenderingManager::updateTerrain() -{ - if (mTerrain) - { - // Avoid updating with dims.getCenter for each cell. Player position should be good enough - mTerrain->update(mRendering.getCamera()->getRealPosition()); - mTerrain->syncLoad(); - // need to update again so the chunks that were just loaded can be made visible - mTerrain->update(mRendering.getCamera()->getRealPosition()); - } -} - -void RenderingManager::requestMap(MWWorld::CellStore* cell) -{ - if (cell->getCell()->isExterior()) - { - assert(mTerrain); - - Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell); - Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5f, cell->getCell()->getGridY() + 0.5f); - dims.merge(mTerrain->getWorldBoundingBox(center)); - - mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); - } - else - mLocalMap->requestMap(cell, mObjects->getDimensions(cell)); -} - -void RenderingManager::writeFog(MWWorld::CellStore* cell) -{ - mLocalMap->saveFogOfWar(cell); -} - -void RenderingManager::disableLights(bool sun) -{ - mActors->disableLights(); - sunDisable(sun); -} - -void RenderingManager::enableLights(bool sun) -{ - mActors->enableLights(); - sunEnable(sun); -} - -void RenderingManager::notifyWorldSpaceChanged() -{ - mEffectManager->clear(); - mWater->clearRipples(); -} - -Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) -{ - Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix(); - - const Ogre::Vector3* corners = bounds.getAllCorners(); - - float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; - - // expand the screen-space bounding-box so that it completely encloses - // the object's AABB - for (int i=0; i<8; i++) - { - Ogre::Vector3 corner = corners[i]; - - // multiply the AABB corner vertex by the view matrix to - // get a camera-space vertex - corner = mat * corner; - - // make 2D relative/normalized coords from the view-space vertex - // by dividing out the Z (depth) factor -- this is an approximation - float x = corner.x / corner.z + 0.5f; - float y = corner.y / corner.z + 0.5f; - - if (x < min_x) - min_x = x; - - if (x > max_x) - max_x = x; - - if (y < min_y) - min_y = y; - - if (y > max_y) - max_y = y; - } - - return Vector4(min_x, min_y, max_x, max_y); -} - -void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) -{ - bool changeRes = false; - bool rebuild = false; // rebuild static geometry (necessary after any material changes) - for (Settings::CategorySettingVector::const_iterator it=settings.begin(); - it != settings.end(); ++it) - { - if (it->second == "menu transparency" && it->first == "GUI") - { - setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); - } - else if (it->second == "viewing distance" && it->first == "Viewing distance") - { - if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior() - && MWBase::Environment::get().getWorld()->getPlayerPtr().mCell) - configureFog(*MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()); - } - else if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y" - || it->second == "fullscreen")) - changeRes = true; - else if (it->first == "Video" && it->second == "window border") - changeRes = true; - else if (it->second == "field of view" && it->first == "General") - mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); - else if (it->second == "gamma" && it->first == "General") - { - mRendering.setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General")); - } - else if ((it->second == "texture filtering" && it->first == "General") - || (it->second == "anisotropy" && it->first == "General")) - { - TextureFilterOptions tfo; - std::string filter = Settings::Manager::getString("texture filtering", "General"); - if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; - else if (filter == "trilinear") tfo = TFO_TRILINEAR; - else if (filter == "bilinear") tfo = TFO_BILINEAR; - else /*if (filter == "none")*/ tfo = TFO_NONE; - - MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); - MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - } - else if (it->second == "shader" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - rebuild = true; - mRendering.getViewport ()->setClearEveryFrame (true); - } - else if (it->second == "refraction" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); - rebuild = true; - } - else if (it->second == "shaders" && it->first == "Objects") - { - sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - rebuild = true; - } - 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); - rebuild = true; - } - } - - if (changeRes) - { - unsigned int x = Settings::Manager::getInt("resolution x", "Video"); - unsigned int y = Settings::Manager::getInt("resolution y", "Video"); - bool fullscreen = Settings::Manager::getBool("fullscreen", "Video"); - bool windowBorder = Settings::Manager::getBool("window border", "Video"); - - SDL_Window* window = mRendering.getSDLWindow(); - - SDL_SetWindowFullscreen(window, 0); - - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED) - SDL_RestoreWindow(window); - - if (fullscreen) - { - SDL_DisplayMode mode; - SDL_GetWindowDisplayMode(window, &mode); - mode.w = x; - mode.h = y; - SDL_SetWindowDisplayMode(window, &mode); - SDL_SetWindowFullscreen(window, fullscreen); - } - else - { - SDL_SetWindowSize(window, x, y); - SDL_SetWindowBordered(window, windowBorder ? SDL_TRUE : SDL_FALSE); - } - } - - mWater->processChangedSettings(settings); - - if (rebuild) - { - mObjects->rebuildStaticGeometry(); - if (mTerrain) - mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), - Settings::Manager::getBool("split", "Shadows")); - } -} - -void RenderingManager::setMenuTransparency(float val) -{ - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName("transparent.png"); std::vector buffer; - buffer.resize(1); - buffer[0] = (int(255*val) << 24) | (255 << 16) | (255 << 8) | 255; - memcpy(tex->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], 1*4); - tex->getBuffer()->unlock(); -} - -void RenderingManager::windowResized(int x, int y) -{ - Settings::Manager::setInt("resolution x", "Video", x); - Settings::Manager::setInt("resolution y", "Video", y); - mRendering.adjustViewport(); - - MWBase::Environment::get().getWindowManager()->windowResized(x,y); -} - -void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) -{ - batches = mRendering.getWindow()->getBatchCount(); - triangles = mRendering.getWindow()->getTriangleCount(); -} - -void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) -{ - ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); - attachCameraTo(ptr); -} - -void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) -{ - Ogre::SceneNode* cameraNode = mCamera->attachTo(ptr); - mSkyManager->attachToNode(cameraNode); -} - -void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) -{ - if(!mPlayerAnimation) - { - mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - } - else - { - // Reconstruct the NpcAnimation in-place - mPlayerAnimation->~NpcAnimation(); - new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - } - - mCamera->setAnimation(mPlayerAnimation); - mWater->removeEmitter(ptr); - mWater->addEmitter(ptr); - // apply race height - MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); -} - -bool RenderingManager::vanityRotateCamera(const float *rot) -{ - if(!mCamera->isVanityOrPreviewModeEnabled()) - return false; - - Ogre::Vector3 vRot(rot); - mCamera->rotateCamera(vRot, true); - return true; -} - -void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) -{ - if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) - { - if(mCamera->isNearest() && dist > 0.f) - mCamera->toggleViewMode(); - else - mCamera->setCameraDistance(-dist / 120.f * 10, adjust, override); - } - else if(mCamera->isFirstPerson() && dist < 0.f) - { - mCamera->toggleViewMode(); - mCamera->setCameraDistance(0.f, false, override); - } -} - -void RenderingManager::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) -{ - return mLocalMap->worldToInteriorMapPosition (position, nX, nY, x, y); -} - -Ogre::Vector2 RenderingManager::interiorMapToWorldPosition(float nX, float nY, int x, int y) -{ - return mLocalMap->interiorMapToWorldPosition(nX, nY, x, y); -} - -bool RenderingManager::isPositionExplored (float nX, float nY, int x, int y, bool interior) -{ - return mLocalMap->isPositionExplored(nX, nY, x, y, interior); -} - -Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) -{ - Animation *anim = mActors->getAnimation(ptr); - - if(!anim && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - anim = mPlayerAnimation; - - if (!anim) - anim = mObjects->getAnimation(ptr); - - return anim; -} - -void RenderingManager::screenshot(Image &image, int w, int h) -{ - // Create a temporary render target. We do not use the RenderWindow since we want a specific size. - // Also, the GUI should not be visible (and it is only rendered on the RenderWindow's primary viewport) - const std::string tempName = "@temp"; - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(tempName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, w, h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - float oldAspect = mRendering.getCamera()->getAspectRatio(); - - mRendering.getCamera()->setAspectRatio(w / static_cast(h)); - - Ogre::RenderTarget* rt = texture->getBuffer()->getRenderTarget(); - Ogre::Viewport* vp = rt->addViewport(mRendering.getCamera()); - vp->setBackgroundColour(mRendering.getViewport()->getBackgroundColour()); - vp->setOverlaysEnabled(false); - vp->setVisibilityMask(mRendering.getViewport()->getVisibilityMask()); - rt->update(); - - Ogre::PixelFormat pf = rt->suggestPixelFormat(); - - image.loadDynamicImage( - OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL), - w, h, 1, pf, true // autoDelete=true, frees memory we allocate - ); - rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image - - Ogre::TextureManager::getSingleton().remove(tempName); - mRendering.getCamera()->setAspectRatio(oldAspect); -} - -void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) -{ - mWater->addEmitter (ptr, scale, force); -} - -void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr) -{ - mWater->removeEmitter (ptr); -} - -void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) -{ - mWater->updateEmitterPtr(old, ptr); -} - -void RenderingManager::frameStarted(float dt, bool paused) -{ - if (mTerrain) - mTerrain->update(mRendering.getCamera()->getRealPosition()); - - if (!paused) - mWater->frameStarted(dt); -} - -void RenderingManager::resetCamera() -{ - mCamera->reset(); -} - -float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) -{ - if (!mTerrain || !mTerrain->getVisible()) - return -std::numeric_limits::max(); - return mTerrain->getHeightAt(worldPos); -} - -void RenderingManager::enableTerrain(bool enable) -{ - if (enable) - { - if (!mTerrain) - { - if (Settings::Manager::getBool("distant land", "Terrain")) - mTerrain = new Terrain::DefaultWorld(mRendering.getScene(), new MWRender::TerrainStorage(true), RV_Terrain, - Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64); - else - mTerrain = new Terrain::TerrainGrid(mRendering.getScene(), new MWRender::TerrainStorage(false), RV_Terrain, - Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY); - mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), - Settings::Manager::getBool("split", "Shadows")); - mTerrain->update(mRendering.getCamera()->getRealPosition()); - } - mTerrain->setVisible(true); - } - else if (mTerrain) - mTerrain->setVisible(false); -} - -float RenderingManager::getCameraDistance() const -{ - return mCamera->getCameraDistance(); -} - -void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale) -{ - mEffectManager->addEffect(model, texture, worldPosition, scale); -} - -void RenderingManager::clear() -{ - mLocalMap->clear(); - notifyWorldSpaceChanged(); -} - -} // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5bfd8ae775..f0c5040f27 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -1,270 +1,61 @@ -#ifndef GAME_RENDERING_MANAGER_H -#define GAME_RENDERING_MANAGER_H +#ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H +#define OPENMW_MWRENDER_RENDERINGMANAGER_H -#include "sky.hpp" -#include "debugging.hpp" +#include +#include -#include - -#include - -#include +#include "objects.hpp" #include "renderinginterface.hpp" -#include "objects.hpp" -#include "actors.hpp" -#include "camera.hpp" -#include "occlusionquery.hpp" - -namespace Ogre +namespace osg { - class SceneNode; + class Group; } -namespace MWWorld +namespace Resource { - class Ptr; - class CellStore; + class ResourceSystem; } -namespace sh +namespace osgViewer { - class Factory; + class Viewer; } -namespace Terrain +namespace ESM { - class World; + struct Cell; } namespace MWRender { - class Shadows; - class LocalMap; - class Water; - class GlobalMap; - class Animation; - class EffectManager; -class RenderingManager: private RenderingInterface, public Ogre::RenderTargetListener, public OEngine::Render::WindowSizeListener -{ -private: - virtual MWRender::Objects& getObjects(); - virtual MWRender::Actors& getActors(); - -public: - RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, - MWWorld::Fallback* fallback); - virtual ~RenderingManager(); - - void togglePOV() - { mCamera->toggleViewMode(); } - - void togglePreviewMode(bool enable) - { mCamera->togglePreviewMode(enable); } - - bool toggleVanityMode(bool enable) - { return mCamera->toggleVanityMode(enable); } - - void allowVanityMode(bool allow) - { mCamera->allowVanityMode(allow); } - - void togglePlayerLooking(bool enable) - { mCamera->togglePlayerLooking(enable); } - - void changeVanityModeScale(float factor) + class RenderingManager : public MWRender::RenderingInterface { - if(mCamera->isVanityOrPreviewModeEnabled()) - mCamera->setCameraDistance(-factor/120.f*10, true, true); - } + public: + RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); - void resetCamera(); + MWRender::Objects& getObjects(); + MWRender::Actors& getActors(); - bool vanityRotateCamera(const float *rot); - void setCameraDistance(float dist, bool adjust = false, bool override = true); - float getCameraDistance() const; + Resource::ResourceSystem* getResourceSystem(); - void setupPlayer(const MWWorld::Ptr &ptr); - void renderPlayer(const MWWorld::Ptr &ptr); + void configureAmbient(const ESM::Cell* cell); - SkyManager* getSkyManager(); + void removeCell(const MWWorld::CellStore* store); - MWRender::Camera* getCamera() const; + osg::Vec3f getEyePos(); - bool toggleRenderMode(int mode); + private: + osgViewer::Viewer& mViewer; + osg::ref_ptr mRootNode; + Resource::ResourceSystem* mResourceSystem; - void removeCell (MWWorld::CellStore *store); + osg::ref_ptr mSunLight; - /// \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::CellStore *store); - - /// Clear all savegame-specific data (i.e. fog of war textures) - void clear(); - - void enableTerrain(bool enable); - - void removeWater(); - - /// Write current fog of war for this cell to the CellStore - void writeFog (MWWorld::CellStore* store); - - void addObject (const MWWorld::Ptr& ptr, const std::string& model); - void removeObject (const MWWorld::Ptr& ptr); - - void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); - void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale); - - /// Updates an object's rotation - void rotateObject (const MWWorld::Ptr& ptr); - - void setWaterHeight(float height); - void setWaterEnabled(bool enabled); - bool toggleWater(); - bool toggleWorld(); - - /// Updates object rendering after cell change - /// \param old Object reference in previous cell - /// \param cur Object reference in new cell - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); - - /// Specifies an updated Ptr object for the player (used on cell change). - void updatePlayerPtr(const MWWorld::Ptr &ptr); - - /// Currently for NPCs only. Rebuilds the NPC, updating their root model, animation sources, - /// and equipment. - void rebuildPtr(const MWWorld::Ptr &ptr); - - void update (float duration, bool paused); - - void setAmbientColour(const Ogre::ColourValue& colour); - void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_night); - void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) - void sunDisable(bool real); - - void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) - void enableLights(bool sun); - - - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } - OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } - - float getTerrainHeightAt (Ogre::Vector3 worldPos); - - void notifyWorldSpaceChanged(); - - void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - - void setGlare(bool glare); - void skyEnable (); - void skyDisable (); - void skySetHour (double hour); - void skySetDate (int day, int month); - int skyGetMasserPhase() const; - int skyGetSecundaPhase() const; - void skySetMoonColour (bool red); - void configureAmbient(MWWorld::CellStore &mCell); - - void addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeWaterRippleEmitter (const MWWorld::Ptr& ptr); - void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - - void updateTerrain (); - ///< update the terrain according to the player position. Usually done automatically, but should be done manually - /// before calling requestMap - - void requestMap (MWWorld::CellStore* cell); - ///< request the local map for a cell - - /// configure fog according to cell - void configureFog(const MWWorld::CellStore &mCell); - - /// configure fog manually - void configureFog(const float density, const Ogre::ColourValue& colour); - - Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); - ///< transform the specified bounding box (in world coordinates) into screen coordinates. - /// @return packed vector4 (min_x, min_y, max_x, max_y) - - void processChangedSettings(const Settings::CategorySettingVector& settings); - - Ogre::Viewport* getViewport() { return mRendering.getViewport(); } - - void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - ///< see MWRender::LocalMap::isPositionExplored - - Animation* getAnimation(const MWWorld::Ptr &ptr); - - void frameStarted(float dt, bool paused); - void screenshot(Ogre::Image& image, int w, int h); - - void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition, float scale=1.f); - -protected: - virtual void windowResized(int x, int y); - -private: - sh::Factory* mFactory; - - void setAmbientMode(); - void applyFog(bool underwater); - - void attachCameraTo(const MWWorld::Ptr& ptr); - - void setMenuTransparency(float val); - - bool mSunEnabled; - - MWWorld::Fallback* mFallback; - - SkyManager* mSkyManager; - - OcclusionQuery* mOcclusionQuery; - - Terrain::World* mTerrain; - - MWRender::Water *mWater; - - GlobalMap* mGlobalMap; - - OEngine::Render::OgreRenderer &mRendering; - - MWRender::Objects* mObjects; - MWRender::Actors* mActors; - - MWRender::EffectManager* mEffectManager; - - MWRender::NpcAnimation *mPlayerAnimation; - - Ogre::ColourValue mAmbientColor; - Ogre::Light* mSun; - - Ogre::SceneNode *mRootNode; - - Ogre::ColourValue mFogColour; - float mFogStart; - float mFogEnd; - - OEngine::Physic::PhysicEngine* mPhysicsEngine; - - MWRender::Camera *mCamera; - - MWRender::LocalMap* mLocalMap; - - bool mRenderWorld; -}; + std::auto_ptr mObjects; + }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f87983ce88..e71a4a34b6 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -686,10 +686,10 @@ namespace MWScript else throw std::runtime_error ("invalid movement axis: " + axis); - if (!ptr.getRefData().getBaseNode()) + if (!ptr.getRefData().getBaseNodeOld()) return; - Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 diff = ptr.getRefData().getBaseNodeOld()->getOrientation() * posChange; Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); worldPos += diff; MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 5115fa02db..cf6f7bf567 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -20,11 +20,11 @@ namespace MWWorld bool operator() (MWWorld::Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); if (handle) mHandles.push_back (handle); - ptr.getRefData().setBaseNode(0); + ptr.getRefData().setBaseNodeOld(0); return true; } }; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d4aadc6c7a..371543f2e1 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -242,7 +242,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell + item.getRefData().setBaseNodeOld(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell ESM::Position pos; pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a59efecfee..b8e4a06a8d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -653,7 +653,7 @@ namespace MWWorld std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { - return mEngine->getCollisions(ptr.getRefData().getBaseNode()->getName(), collisionGroup, collisionMask); + return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) @@ -675,7 +675,7 @@ namespace MWWorld void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); @@ -685,7 +685,7 @@ namespace MWWorld void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); } @@ -699,7 +699,7 @@ namespace MWWorld void PhysicsSystem::moveObject (const Ptr& ptr) { - Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode *node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); const Ogre::Vector3 &position = node->getPosition(); @@ -722,7 +722,7 @@ namespace MWWorld void PhysicsSystem::rotateObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); const Ogre::Quaternion &rotation = node->getOrientation(); @@ -751,7 +751,7 @@ namespace MWWorld void PhysicsSystem::scaleObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 14a315a81b..7e83fda5e0 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -134,14 +134,23 @@ namespace MWWorld return mBaseNode->getName(); } - Ogre::SceneNode* RefData::getBaseNode() + Ogre::SceneNode* RefData::getBaseNodeOld() { return mBaseNode; } - void RefData::setBaseNode(Ogre::SceneNode* base) + void RefData::setBaseNodeOld(Ogre::SceneNode* base) { - mBaseNode = base; + } + + void RefData::setBaseNode(osg::PositionAttitudeTransform *base) + { + mBase = base; + } + + osg::PositionAttitudeTransform* RefData::getBaseNode() + { + return mBase; } int RefData::getCount() const diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index e90b44f9c9..2099b859fd 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -10,6 +10,11 @@ namespace Ogre class SceneNode; } +namespace osg +{ + class PositionAttitudeTransform; +} + namespace ESM { class Script; @@ -28,7 +33,7 @@ namespace MWWorld class RefData { Ogre::SceneNode* mBaseNode; - + osg::PositionAttitudeTransform* mBase; MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, @@ -78,10 +83,18 @@ namespace MWWorld const std::string &getHandle(); /// Return OGRE base node (can be a null pointer). - Ogre::SceneNode* getBaseNode(); + /// obsolete + Ogre::SceneNode* getBaseNodeOld(); + + /// Return base node (can be a null pointer). + osg::PositionAttitudeTransform* getBaseNode(); /// Set OGRE base node (can be a null pointer). - void setBaseNode (Ogre::SceneNode* base); + /// obsolete + void setBaseNodeOld (Ogre::SceneNode* base); + + /// Set base node (can be a null pointer). + void setBaseNode (osg::PositionAttitudeTransform* base); int getCount() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6d74086079..1084ae03ac 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -6,12 +6,16 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwrender/renderingmanager.hpp" + //#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" @@ -20,19 +24,20 @@ #include "cellfunctors.hpp" #include "cellstore.hpp" +#include + namespace { -#if 0 - void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, //MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { - std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); std::string id = ptr.getClass().getId(ptr); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player - rendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, physics); + ptr.getClass().insertObjectRendering(ptr, model, rendering); + //ptr.getClass().insertObject (ptr, model, physics); } void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, @@ -40,22 +45,21 @@ namespace { if (ptr.getRefData().getBaseNode() != NULL) { - Ogre::Quaternion worldRotQuat(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z); + osg::Quat worldRotQuat(ptr.getRefData().getPosition().rot[2], osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - worldRotQuat = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* worldRotQuat; + worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * + osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); float x = ptr.getRefData().getLocalRotation().rot[0]; float y = ptr.getRefData().getLocalRotation().rot[1]; float z = ptr.getRefData().getLocalRotation().rot[2]; - Ogre::Quaternion rot(Ogre::Radian(z), Ogre::Vector3::NEGATIVE_UNIT_Z); + osg::Quat rot(z, osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - rot = Ogre::Quaternion(Ogre::Radian(x), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*rot; + rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); - physics.rotateObject(ptr); + ptr.getRefData().getBaseNode()->setAttitude(rot * worldRotQuat); + //physics.rotateObject(ptr); } } @@ -64,20 +68,21 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - MWWorld::PhysicsSystem& mPhysics; + //MWWorld::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); + /*MWWorld::PhysicsSystem& physics, */MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, + Loading::Listener& loadingListener, /*MWWorld::PhysicsSystem& physics,*/ MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), - mPhysics (physics), mRendering (rendering) + //mPhysics (physics), + mRendering (rendering) {} bool InsertFunctor::operator() (const MWWorld::Ptr& ptr) @@ -94,13 +99,13 @@ namespace { try { - addObject(ptr, mPhysics, mRendering); - updateObjectLocalRotation(ptr, mPhysics, mRendering); + addObject(ptr, /*mPhysics, */mRendering); + //updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) { float scale = ptr.getCellRef().getScale(); ptr.getClass().adjustScale(ptr, scale); - mRendering.scaleObject(ptr, Ogre::Vector3(scale)); + //mRendering.scaleObject(ptr, Ogre::Vector3(scale)); } ptr.getClass().adjustPosition (ptr, false); } @@ -115,7 +120,6 @@ namespace return true; } -#endif } @@ -129,7 +133,7 @@ namespace MWWorld void Scene::updateObjectRotation (const Ptr& ptr) { - if(ptr.getRefData().getBaseNode() != 0) + if(ptr.getRefData().getBaseNodeOld() != 0) { //mRendering.rotateObject(ptr); //mPhysics->rotateObject(ptr); @@ -190,23 +194,24 @@ namespace MWWorld for (std::vector::const_iterator iter2 (functor.mHandles.begin()); iter2!=functor.mHandles.end(); ++iter2) { - Ogre::SceneNode* node = *iter2; + //Ogre::SceneNode* node = *iter2; //mPhysics->removeObject (node->getName()); } } if ((*iter)->getCell()->isExterior()) { - ESM::Land* land = + /*ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get().search( (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - //if (land && land->mDataTypes&ESM::Land::DATA_VHGT) - //mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) + mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); + */ } - //mRendering.removeCell(*iter); + mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); @@ -224,8 +229,8 @@ namespace MWWorld { std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; - float verts = ESM::Land::LAND_SIZE; - float worldsize = ESM::Land::REAL_SIZE; + //float verts = ESM::Land::LAND_SIZE; + //float worldsize = ESM::Land::REAL_SIZE; #if 0 // Load terrain physics first... @@ -271,9 +276,9 @@ namespace MWWorld } else mPhysics->disableWater(); - - mRendering.configureAmbient(*cell); #endif + if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) + mRendering.configureAmbient(cell->getCell()); } // register local scripts @@ -290,7 +295,7 @@ namespace MWWorld mCurrentCell = NULL; } - void Scene::playerMoved(const Ogre::Vector3 &pos) + void Scene::playerMoved(const osg::Vec3f &pos) { if (!mCurrentCell || !mCurrentCell->isExterior()) return; @@ -301,12 +306,14 @@ namespace MWWorld float centerX, centerY; MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); const float maxDistance = 8192/2 + 1024; // 1/2 cell size + threshold - float distance = std::max(std::abs(centerX-pos.x), std::abs(centerY-pos.y)); + float distance = std::max(std::abs(centerX-pos.x()), std::abs(centerY-pos.y())); if (distance > maxDistance) { int newX, newY; - MWBase::Environment::get().getWorld()->positionToIndex(pos.x, pos.y, newX, newY); + MWBase::Environment::get().getWorld()->positionToIndex(pos.x(), pos.y(), newX, newY); + osg::Timer timer; changeCellGrid(newX, newY); + std::cout << "changeCellGrid took " << timer.time_m() << std::endl; //mRendering.updateTerrain(); } } @@ -435,7 +442,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics), mRendering(rendering),*/ mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics),*/ mRendering(rendering), mNeedMapUpdate(false) { } @@ -545,15 +552,15 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - //InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - //cell.forEach (functor); + InsertFunctor functor (cell, rescale, *loadingListener, /* *mPhysics, */mRendering); + cell.forEach (functor); } void Scene::addObjectToScene (const Ptr& ptr) { try { - //addObject(ptr, *mPhysics, mRendering); + addObject(ptr, /* *mPhysics, */mRendering); //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 341a89a78e..4e8f6a11b6 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -8,6 +8,11 @@ #include +namespace osg +{ + class Vec3f; +} + namespace Ogre { class Vector3; @@ -59,7 +64,7 @@ namespace MWWorld CellStoreCollection mActiveCells; bool mCellChanged; //PhysicsSystem *mPhysics; - //MWRender::RenderingManager& mRendering; + MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; @@ -80,7 +85,7 @@ namespace MWWorld void loadCell (CellStore *cell, Loading::Listener* loadingListener); - void playerMoved (const Ogre::Vector3& pos); + void playerMoved (const osg::Vec3f& pos); void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8b2035fe96..994a0c9dd1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -11,6 +11,8 @@ #include "../mwscript/globalscripts.hpp" #include +#include + #include #include @@ -37,6 +39,7 @@ #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors //#include "../mwrender/animation.hpp" +#include "../mwrender/renderingmanager.hpp" #include "../mwscript/interpretercontext.hpp" @@ -143,9 +146,11 @@ namespace MWWorld } World::World ( + osgViewer::Viewer& viewer, + osg::ref_ptr rootNode, + Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, const std::vector& contentFiles, - const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) : mPlayer (0), mLocalScripts (mStore), @@ -162,7 +167,7 @@ namespace MWWorld #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); #endif - //mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); //mPhysEngine->setSceneManager(renderer.getScene()); @@ -476,7 +481,7 @@ namespace MWWorld #endif //delete mWeatherManager; delete mWorldScene; - //delete mRendering; + delete mRendering; //delete mPhysics; delete mPlayer; @@ -1184,7 +1189,7 @@ namespace MWWorld MWWorld::Ptr newPtr = ptr.getClass() .copyToCell(ptr, *newCell); - newPtr.getRefData().setBaseNode(0); + newPtr.getRefData().setBaseNodeOld(0); } else if (!currCellActive && !newCellActive) ptr.getClass().copyToCell(ptr, *newCell); @@ -1194,7 +1199,7 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); //mRendering->updateObjectCell(ptr, copy); - ptr.getRefData().setBaseNode(NULL); + ptr.getRefData().setBaseNodeOld(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); @@ -1213,14 +1218,14 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove && ptr.getRefData().getBaseNode()) + if (haveToMove && ptr.getRefData().getBaseNodeOld()) { //mRendering->moveObject(ptr, vec); //mPhysics->moveObject (ptr); } if (isPlayer) { - mWorldScene->playerMoved (vec); + //mWorldScene->playerMoved (vec); } } @@ -1252,7 +1257,7 @@ namespace MWWorld ptr.getCellRef().setScale(scale); ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNode() == 0) + if(ptr.getRefData().getBaseNodeOld() == 0) return; //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); //mPhysics->scaleObject(ptr); @@ -1303,7 +1308,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNode() == 0) + if(ptr.getRefData().getBaseNodeOld() == 0) return; if (ptr.getClass().isActor()) @@ -1325,7 +1330,7 @@ namespace MWWorld ptr.getRefData().setLocalRotation(rot); - if (ptr.getRefData().getBaseNode() != 0) + if (ptr.getRefData().getBaseNodeOld() != 0) { mWorldScene->updateObjectLocalRotation(ptr); } @@ -1335,7 +1340,7 @@ namespace MWWorld { ESM::Position pos (ptr.getRefData().getPosition()); - if(!ptr.getRefData().getBaseNode()) + if(!ptr.getRefData().getBaseNodeOld()) { // will be adjusted when Ptr's cell becomes active return; @@ -1352,9 +1357,9 @@ namespace MWWorld if (force || !isFlying(ptr)) { - Ogre::Vector3 traced;// = mPhysics->traceDown(ptr, 500); - if (traced.z < pos.pos[2]) - pos.pos[2] = traced.z; + //Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); + //if (traced.z < pos.pos[2]) + // pos.pos[2] = traced.z; } moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]); @@ -1599,13 +1604,14 @@ namespace MWWorld void World::update (float duration, bool paused) { + /* if (mGoToJail && !paused) goToJail(); updateWeather(duration, paused); - //if (!paused) - // doPhysics (duration); + if (!paused) + doPhysics (duration); mWorldScene->update (duration, paused); @@ -1620,11 +1626,14 @@ namespace MWWorld ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); } + */ + + //mWorldScene->playerMoved(mRendering->getEyePos()); } void World::updateSoundListener() { - Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); + Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1644,7 +1653,7 @@ namespace MWWorld // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) { - Ogre::SceneNode* node = object.getRefData().getBaseNode(); + Ogre::SceneNode* node = object.getRefData().getBaseNodeOld(); Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { @@ -2341,7 +2350,7 @@ namespace MWWorld bool operator() (Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); if (handle) mHandles.push_back(handle->getName()); return true; @@ -2366,7 +2375,7 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) + if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) return false; // not in active cell OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 07698aae52..f77bb47609 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -5,6 +5,8 @@ #include +#include + #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" @@ -21,6 +23,21 @@ #include +namespace osg +{ + class Group; +} + +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace Ogre { class Vector3; @@ -155,9 +172,11 @@ namespace MWWorld public: World ( + osgViewer::Viewer& viewer, + osg::ref_ptr rootNode, + Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, const std::vector& contentFiles, - const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index c49cf77b8d..60315ba7d8 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -74,6 +74,16 @@ namespace SceneUtil if (lights.size()) { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + // we do the intersections in view space osg::BoundingSphere nodeBound = node->getBound(); osg::Matrixf mat = *cv->getModelViewMatrix(); @@ -89,26 +99,33 @@ namespace SceneUtil if (lightList.empty()) { + statesets[node] = NULL; traverse(node, nv); return; } - if (lightList.size() > 8) + unsigned int maxLights = static_cast (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) { //std::cerr << "More than 8 lights!" << std::endl; // TODO: sort lights by certain criteria - while (lightList.size() > 8) + while (lightList.size() > maxLights) lightList.pop_back(); } - osg::ref_ptr stateset = mLightManager->getLightListStateSet(lightList); + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + if (stateset) cv->pushStateSet(stateset); traverse(node, nv); + if (stateset) cv->popStateSet(); } else @@ -174,7 +191,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -208,6 +225,7 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) , mDecorated(false) + , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); } @@ -216,6 +234,7 @@ namespace SceneUtil : osg::Group(copy, copyop) , mLightsInViewSpace(false) , mDecorated(copy.mDecorated) + , mStartLight(copy.mStartLight) { } @@ -284,11 +303,14 @@ namespace SceneUtil osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); - clonedLight->setLightNum(i); + clonedLight->setLightNum(i+mStartLight); // don't use setAttributeAndModes, that does not support light indices! stateset->setAttribute(clonedLight, osg::StateAttribute::ON); stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); + + //stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + } mStateSetCache.insert(std::make_pair(hash, stateset)); return stateset; @@ -300,6 +322,16 @@ namespace SceneUtil return mLights; } + void LightManager::setStartLight(int start) + { + mStartLight = start; + } + + int LightManager::getStartLight() const + { + return mStartLight; + } + LightSource::LightSource() : mRadius(0.f) { diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ccb6603a6e..fe5dc50822 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -87,6 +87,11 @@ namespace SceneUtil osg::ref_ptr getLightListStateSet(const LightList& lightList); + /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. + void setStartLight(int start); + + int getStartLight() const; + private: // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; @@ -98,6 +103,8 @@ namespace SceneUtil LightStateSetMap mStateSetCache; bool mDecorated; + + int mStartLight; }; } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index de22e1b56b..32c3861c07 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -129,15 +129,6 @@ local map hud widget size = 256 exterior grid size = 3 [Viewing distance] -# Limit the rendering distance of small objects -limit small object distance = false - -# Size below which an object is considered as small -small object size = 250 - -# Rendering distance for small objects -small object distance = 3500 - # Viewing distance at normal weather conditions # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) # viewing distance / minimum weather fog depth (.69) * view frustum factor <= cell size (8192) - loading threshold (1024) From 61aaf0cf70f12411d3da47ad65155d5314079528 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 18:02:29 +0200 Subject: [PATCH 0111/1812] Attach light lists to the object base nodes instead of each renderable Apparently that is how Ogre worked (on the SceneNode) so let's roll with it for now. Have not tested yet what MW does. --- apps/openmw/mwrender/objects.cpp | 3 + components/sceneutil/lightmanager.cpp | 218 ++++++++++---------------- components/sceneutil/lightmanager.hpp | 23 ++- 3 files changed, 109 insertions(+), 135 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6d37fa1e8a..764aa13c67 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -131,6 +131,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { SceneUtil::FindByNameVisitor visitor("AttachLight"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 60315ba7d8..5bccd53b38 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -45,122 +45,6 @@ namespace SceneUtil } }; - class CullCallback : public osg::NodeCallback - { - public: - CullCallback() - : mLightManager(NULL) - {} - CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) - {} - CullCallback(LightManager* lightManager) - : mLightManager(lightManager) - {} - - META_Object(NifOsg, CullCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = static_cast(nv); - - mLightManager->prepareForCamera(cv->getCurrentCamera()); - - // Possible optimizations: - // - cull list of lights by the camera frustum - // - organize lights in a quad tree - - const std::vector& lights = mLightManager->getLights(); - - if (lights.size()) - { - - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) - { - stateset = found->second; - } - else{ - - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; - - // TODO: sort lights by certain criteria - - while (lightList.size() > maxLights) - lightList.pop_back(); - } - - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; - } - - if (stateset) - cv->pushStateSet(stateset); - - traverse(node, nv); - - if (stateset) - cv->popStateSet(); - } - else - traverse(node, nv); - } - - private: - LightManager* mLightManager; - }; - - class AttachCullCallbackVisitor : public osg::NodeVisitor - { - public: - AttachCullCallbackVisitor(LightManager* lightManager) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mLightManager(lightManager) - { - } - - virtual void apply(osg::Geode &geode) - { - if (!geode.getNumParents()) - return; - - // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call - // does not traverse the drawables, so the push/pop in the CullCallback has no effect - // Should be no longer an issue with osg trunk - osg::Node* parent = geode.getParent(0); - parent->addCullCallback(new CullCallback(mLightManager)); - } - - private: - LightManager* mLightManager; - }; - // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -191,7 +75,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -224,7 +108,6 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) - , mDecorated(false) , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); @@ -233,29 +116,16 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mLightsInViewSpace(false) - , mDecorated(copy.mDecorated) , mStartLight(copy.mStartLight) { } - void LightManager::decorateGeodes() - { - AttachCullCallbackVisitor visitor(this); - accept(visitor); - } - void LightManager::update() { mLightsInViewSpace = false; mLights.clear(); mStateSetCache.clear(); - - if (!mDecorated) - { - decorateGeodes(); - mDecorated = true; - } } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -338,4 +208,90 @@ namespace SceneUtil setUpdateCallback(new CollectLightCallback); } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + return; + } + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > maxLights) + lightList.pop_back(); + } + + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + + if (stateset) + cv->pushStateSet(stateset); + + traverse(node, nv); + + if (stateset) + cv->popStateSet(); + } + else + traverse(node, nv); + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index fe5dc50822..1cd73589a4 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -71,8 +71,6 @@ namespace SceneUtil void prepareForCamera(osg::Camera* cam); - void decorateGeodes(); - struct LightSourceTransform { LightSource* mLightSource; @@ -102,11 +100,28 @@ namespace SceneUtil typedef std::map > LightStateSetMap; LightStateSetMap mStateSetCache; - bool mDecorated; - int mStartLight; }; + class LightListCallback : public osg::NodeCallback + { + public: + LightListCallback() + : mLightManager(NULL) + {} + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + + META_Object(NifOsg, LightListCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightManager* mLightManager; + }; + + } #endif From 987e923790f91ef1e62a9464409a5d1c6d351ee1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 19:44:48 +0200 Subject: [PATCH 0112/1812] LightManager optimization --- components/sceneutil/lightmanager.cpp | 73 +++++++++++++++++---------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 5bccd53b38..1aaf7ab408 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -15,17 +15,32 @@ namespace SceneUtil { - class LightStateAttribute : public osg::Light + // Resets the modelview matrix to just the view matrix before applying lights. + class LightStateAttribute : public osg::StateAttribute { public: - LightStateAttribute() {} + LightStateAttribute() : mIndex(0) {} + LightStateAttribute(unsigned int index, const std::vector >& lights) : mIndex(index), mLights(lights) {} - LightStateAttribute(const LightStateAttribute& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) - : osg::Light(light,copyop) {} + LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) + : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {} - LightStateAttribute(const osg::Light& light,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) - : osg::Light(light,copyop) {} + unsigned int getMember() const + { + return mIndex; + } + virtual bool getModeUsage(ModeUsage & usage) const + { + for (unsigned int i=0; isetLightNum(i+mIndex); + mLights[i]->apply(state); + } state.applyModelViewMatrix(modelViewMatrix); } + + private: + unsigned int mIndex; + + std::vector > mLights; }; // Set on a LightSource. Adds the light source to its light manager for the current frame. @@ -133,6 +153,9 @@ namespace SceneUtil LightSourceTransform l; l.mLightSource = lightSource; l.mWorldMatrix = worldMat; + lightSource->getLight()->setPosition(osg::Vec4f(worldMat.getTrans().x(), + worldMat.getTrans().y(), + worldMat.getTrans().z(), 1.f)); mLights.push_back(l); } @@ -164,24 +187,22 @@ namespace SceneUtil return found->second; else { - osg::ref_ptr stateset (new osg::StateSet); + + std::vector > lights; for (unsigned int i=0; igetLight(); - - osg::ref_ptr clonedLight = new LightStateAttribute(*light, osg::CopyOp::DEEP_COPY_ALL); - clonedLight->setPosition(mLights[lightIndex].mWorldMatrix.preMult(light->getPosition())); - - clonedLight->setLightNum(i+mStartLight); - - // don't use setAttributeAndModes, that does not support light indices! - stateset->setAttribute(clonedLight, osg::StateAttribute::ON); - stateset->setAssociatedModes(clonedLight, osg::StateAttribute::ON); - - //stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - + const LightSourceTransform& l = mLights[lightList[i]]; + lights.push_back(l.mLightSource->getLight()); } + + osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); + + osg::ref_ptr stateset = new osg::StateSet; + + // don't use setAttributeAndModes, that does not support light indices! + stateset->setAttribute(attr, osg::StateAttribute::ON); + stateset->setAssociatedModes(attr, osg::StateAttribute::ON); + mStateSetCache.insert(std::make_pair(hash, stateset)); return stateset; } From 246b06ca279c293ef3f914b391b3935cd16b62d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Apr 2015 17:30:32 +0200 Subject: [PATCH 0113/1812] Forgot to add --- apps/openmw/mwrender/objects.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 764aa13c67..25d57aba08 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -139,8 +139,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool SceneUtil::FindByNameVisitor visitor("AttachLight"); ptr.getRefData().getBaseNode()->accept(visitor); - osg::Vec3f lightOffset (0.f, 0.f, 0.f); - osg::Group* attachTo = NULL; if (visitor.mFoundNode) { @@ -152,9 +150,13 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::Group* objectRoot = anim->getOrCreateObjectRoot(); objectRoot->accept(computeBound); - lightOffset = computeBound.getBoundingBox().center(); + // PositionAttitudeTransform seems to be slightly faster than MatrixTransform + osg::ref_ptr trans(new osg::PositionAttitudeTransform); + trans->setPosition(computeBound.getBoundingBox().center()); - attachTo = objectRoot; + objectRoot->addChild(trans); + + attachTo = trans; } const ESM::Light* esmLight = ptr.get()->mBase; @@ -162,7 +164,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::ref_ptr lightSource = new SceneUtil::LightSource; osg::Light* light = new osg::Light; lightSource->setLight(light); - light->setPosition(osg::Vec4f(lightOffset.x(), lightOffset.y(), lightOffset.z(), 1.f)); float realRadius = esmLight->mData.mRadius * 2; From 8c7c89a4aabf8131f4c07a08cc9f03a2e2af819b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Apr 2015 22:48:37 +0200 Subject: [PATCH 0114/1812] Port SoundManager --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 50 ++++++++++++++----------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 8 +++- apps/openmw/mwsound/openal_output.cpp | 2 +- apps/openmw/mwsound/sound_decoder.hpp | 10 +++-- apps/openmw/mwsound/soundmanagerimp.cpp | 28 ++++++++------ apps/openmw/mwsound/soundmanagerimp.hpp | 12 ++++-- 7 files changed, 68 insertions(+), 44 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0d0294fa7d..59f9fa6926 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -377,7 +377,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (window); // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); + mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); if (!mSkipMenu) { diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 0185d3ecc1..55607b5b72 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -4,6 +4,7 @@ #include #include +#include extern "C" { #ifndef HAVE_LIBSWRESAMPLE @@ -15,6 +16,8 @@ AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_ #endif } +#include + namespace MWSound { @@ -27,8 +30,10 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) { try { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->read(buf, buf_size); + std::istream& stream = *static_cast(user_data)->mDataStream; + stream.read((char*)buf, buf_size); + stream.clear(); + return stream.gcount(); } catch (std::exception& ) { @@ -36,36 +41,36 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) } } -int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) +int FFmpeg_Decoder::writePacket(void *, uint8_t *, int) { - try - { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->write(buf, buf_size); - } - catch (std::exception& ) - { - return 0; - } + throw std::runtime_error("can't write to read-only stream"); } int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + std::istream& stream = *static_cast(user_data)->mDataStream; whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) - return stream->size(); + { + size_t prev = stream.tellg(); + stream.seekg(0, std::ios_base::end); + size_t size = stream.tellg(); + stream.seekg(prev, std::ios_base::beg); + return size; + } + if(whence == SEEK_SET) - stream->seek(static_cast(offset)); + stream.seekg(offset, std::ios_base::beg); else if(whence == SEEK_CUR) - stream->seek(static_cast(stream->tell()+offset)); + stream.seekg(offset, std::ios_base::cur); else if(whence == SEEK_END) - stream->seek(static_cast(stream->size()+offset)); + stream.seekg(offset, std::ios_base::end); else return -1; - return stream->tell(); + return stream.tellg(); } @@ -186,7 +191,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) void FFmpeg_Decoder::open(const std::string &fname) { close(); - mDataStream = mResourceMgr.openResource(fname); + mDataStream = mResourceMgr->get(fname); if((mFormatCtx=avformat_alloc_context()) == NULL) fail("Failed to allocate context"); @@ -289,7 +294,7 @@ void FFmpeg_Decoder::close() avformat_close_input(&mFormatCtx); } - mDataStream.setNull(); + mDataStream.reset(); } std::string FFmpeg_Decoder::getName() @@ -409,8 +414,9 @@ size_t FFmpeg_Decoder::getSampleOffset() return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay; } -FFmpeg_Decoder::FFmpeg_Decoder() - : mFormatCtx(NULL) +FFmpeg_Decoder::FFmpeg_Decoder(const VFS::Manager* vfs) + : Sound_Decoder(vfs) + , mFormatCtx(NULL) , mStream(NULL) , mFrame(NULL) , mFrameSize(0) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 2cdbbf363d..3abf7c474d 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -37,7 +37,10 @@ extern "C" #endif } +#include + #include +#include #include "sound_decoder.hpp" @@ -66,7 +69,8 @@ namespace MWSound bool getNextPacket(); - Ogre::DataStreamPtr mDataStream; + Files::IStreamPtr mDataStream; + static int readPacket(void *user_data, uint8_t *buf, int buf_size); static int writePacket(void *user_data, uint8_t *buf, int buf_size); static int64_t seek(void *user_data, int64_t offset, int whence); @@ -90,7 +94,7 @@ namespace MWSound FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); FFmpeg_Decoder(const FFmpeg_Decoder &rhs); - FFmpeg_Decoder(); + FFmpeg_Decoder(const VFS::Manager* vfs); public: virtual ~FFmpeg_Decoder(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1b3dced801..266b97f875 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -786,7 +786,7 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) { decoder->open(fname); } - catch(Ogre::FileNotFoundException&) + catch(std::exception&) { std::string::size_type pos = fname.rfind('.'); if(pos == std::string::npos) diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 151b580360..1be9dd3749 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -2,8 +2,12 @@ #define GAME_SOUND_SOUND_DECODER_H #include +#include -#include +namespace VFS +{ + class Manager; +} namespace MWSound { @@ -28,7 +32,7 @@ namespace MWSound struct Sound_Decoder { - Ogre::ResourceGroupManager &mResourceMgr; + const VFS::Manager* mResourceMgr; virtual void open(const std::string &fname) = 0; virtual void close() = 0; @@ -41,7 +45,7 @@ namespace MWSound virtual void rewind() = 0; virtual size_t getSampleOffset() = 0; - Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + Sound_Decoder(const VFS::Manager* resourceMgr) : mResourceMgr(resourceMgr) { } virtual ~Sound_Decoder() { } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 5fc39f03e8..84f61ddf8d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -6,6 +6,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -27,8 +29,8 @@ namespace MWSound { - SoundManager::SoundManager(bool useSound) - : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) + : mVFS(vfs) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -96,7 +98,7 @@ namespace MWSound // Return a new decoder instance, used as needed by the output implementations DecoderPtr SoundManager::getDecoder() { - return DecoderPtr(new DEFAULT_DECODER); + return DecoderPtr(new DEFAULT_DECODER (mVFS)); } // Convert a soundId to file name, and modify the volume @@ -208,20 +210,24 @@ namespace MWSound void SoundManager::startRandomTitle() { - Ogre::StringVector filelist; + std::vector filelist; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { -#if 0 - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Music/" + mCurrentPlaylist; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) { - Ogre::StringVectorPtr resourcesInThisGroup = mResourceMgr.findResourceNames(*it, - "Music/"+mCurrentPlaylist+"/*"); - filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) + filelist.push_back(found->first); + ++found; } + mMusicFiles[mCurrentPlaylist] = filelist; -#endif } else filelist = mMusicFiles[mCurrentPlaylist]; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 250cb0d51c..8089a7e6f5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -8,12 +8,16 @@ #include #include -#include #include #include "../mwbase/soundmanager.hpp" +namespace VFS +{ + class Manager; +} + namespace MWSound { class Sound_Output; @@ -27,12 +31,12 @@ namespace MWSound class SoundManager : public MWBase::SoundManager { - Ogre::ResourceGroupManager& mResourceMgr; + const VFS::Manager* mVFS; std::auto_ptr mOutput; // Caches available music tracks by - std::map mMusicFiles; + std::map > mMusicFiles; std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; @@ -74,7 +78,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(bool useSound); + SoundManager(const VFS::Manager* vfs, bool useSound); virtual ~SoundManager(); virtual void processChangedSettings(const Settings::CategorySettingVector& settings); From 5dd1ab24fe45afbe43542eeda45a480faf3a4180 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 15:55:56 +0200 Subject: [PATCH 0115/1812] More efficient StateSetController, beginnings of sky rendering --- apps/openmw/CMakeLists.txt | 8 +- apps/openmw/engine.cpp | 10 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 91 ++- apps/openmw/mwrender/renderingmanager.hpp | 22 + apps/openmw/mwrender/sky.cpp | 827 +++++++------------- apps/openmw/mwrender/sky.hpp | 170 +--- apps/openmw/mwworld/fallback.cpp | 10 +- apps/openmw/mwworld/fallback.hpp | 4 +- apps/openmw/mwworld/weather.cpp | 70 +- apps/openmw/mwworld/weather.hpp | 26 +- apps/openmw/mwworld/worldimp.cpp | 44 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/CMakeLists.txt | 2 +- components/resource/scenemanager.cpp | 10 + components/resource/scenemanager.hpp | 4 + components/sceneutil/statesetcontroller.cpp | 31 + components/sceneutil/statesetcontroller.hpp | 39 + 18 files changed, 610 insertions(+), 762 deletions(-) create mode 100644 components/sceneutil/statesetcontroller.cpp create mode 100644 components/sceneutil/statesetcontroller.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e10688149f..e7ed2d921f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation -# debugging sky camera npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation sky +# debugging camera npcanimation creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation @@ -68,8 +68,8 @@ add_openmw_dir (mwworld cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist cellref physicssystem -# weather projectilemanager + contentloader esmloader actiontrap cellreflist cellref physicssystem weather +# projectilemanager ) add_openmw_dir (mwclass diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59f9fa6926..59504048ae 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -499,9 +499,17 @@ void OMW::Engine::go() //mViewer.setRealizeOperation(ico); mViewer.realize(); std::cout << "realize took " << timer.time_m() << std::endl; + osg::Timer frameTimer; while (!mViewer.done()) { - MWBase::Environment::get().getWorld()->update(0.f, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + + // frameRenderingQueued(dt); + MWBase::Environment::get().getWorld()->update(dt, false); + + MWBase::Environment::get().getWorld()->advanceTime( + dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); mViewer.frame(/*simulationTime*/); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 44334e4447..07328b9592 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -41,7 +41,7 @@ public: ~Objects(); /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? - /// @param allowLight If false, no lights will be created, and particles systems will be cleared then frozen. + /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); void insertNPC(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4e5b33c647..e9a5d302c1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,11 +13,39 @@ #include +#include + #include +#include "sky.hpp" + namespace MWRender { + class StateUpdater : public SceneUtil::StateSetController + { + public: + virtual void setDefaults(osg::StateSet *stateset) + { + osg::LightModel* lightModel = new osg::LightModel; + stateset->setAttribute(lightModel, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::LightModel* lightModel = static_cast(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); + lightModel->setAmbientIntensity(mAmbientColor); + } + + void setAmbientColor(osg::Vec4f col) + { + mAmbientColor = col; + } + + private: + osg::Vec4f mAmbientColor; + }; + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) : mViewer(viewer) , mRootNode(rootNode) @@ -30,6 +58,8 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -38,17 +68,30 @@ namespace MWRender mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); mSunLight->setConstantAttenuation(1.f); - source->setStateSetModes(*rootNode->getOrCreateStateSet(), osg::StateAttribute::ON); lightRoot->addChild(source); - rootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); + + mStateUpdater = new StateUpdater; + mRootNode->addUpdateCallback(mStateUpdater); // for consistent benchmarks against the ogre branch. remove later osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); viewer.getCamera()->setCullingMode( cullingMode ); + + double fovy, aspect, zNear, zFar; + mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + fovy = 55.f; + mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + RenderingManager::~RenderingManager() + { } MWRender::Objects& RenderingManager::getObjects() @@ -66,21 +109,34 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::setAmbientColour(const osg::Vec4f &colour) + { + mStateUpdater->setAmbientColor(colour); + } + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - osg::ref_ptr lightmodel = new osg::LightModel; - lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } + void RenderingManager::setSunColour(const osg::Vec4f &colour) + { + mSunLight->setDiffuse(colour); + } + + void RenderingManager::setSunDirection(const osg::Vec3f &direction) + { + mSunLight->setDirection(direction*-1); + + mSky->setSunDirection(direction*-1); + } + osg::Vec3f RenderingManager::getEyePos() { - osg::Vec3d eye; - //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); - eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + osg::Vec3d eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); return eye; } @@ -89,4 +145,19 @@ namespace MWRender mObjects->removeCell(store); } + void RenderingManager::setSkyEnabled(bool enabled) + { + mSky->setEnabled(enabled); + } + + void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &colour) + { + mViewer.getCamera()->setClearColor(colour); + } + + SkyManager* RenderingManager::getSkyManager() + { + return mSky.get(); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0c5040f27..1db0467efc 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -31,20 +31,36 @@ namespace ESM namespace MWRender { + class StateUpdater; + + class SkyManager; + class RenderingManager : public MWRender::RenderingInterface { public: RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + ~RenderingManager(); MWRender::Objects& getObjects(); MWRender::Actors& getActors(); Resource::ResourceSystem* getResourceSystem(); + void setAmbientColour(const osg::Vec4f& colour); + + void setSunDirection(const osg::Vec3f& direction); + void setSunColour(const osg::Vec4f& colour); + void configureAmbient(const ESM::Cell* cell); + void configureFog(float fogDepth, const osg::Vec4f& colour); + void removeCell(const MWWorld::CellStore* store); + void setSkyEnabled(bool enabled); + + SkyManager* getSkyManager(); + osg::Vec3f getEyePos(); private: @@ -55,6 +71,12 @@ namespace MWRender osg::ref_ptr mSunLight; std::auto_ptr mObjects; + std::auto_ptr mSky; + + osg::ref_ptr mStateUpdater; + + void operator = (const RenderingManager&); + RenderingManager(const RenderingManager&); }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d591cca2ea..be702a2212 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,30 +1,30 @@ #include "sky.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include -#include +#include + +#include #include #include -#include #include -#include +#include +#include + +#include + +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -34,239 +34,202 @@ #include "renderconst.hpp" #include "renderingmanager.hpp" -using namespace MWRender; -using namespace Ogre; - namespace { -void setAlpha (NifOgre::ObjectScenePtr scene, Ogre::MovableObject* movable, float alpha) -{ - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(movable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) + osg::StateSet* getWritableStateSet(osg::Node* node) { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) + osg::StateSet* stateset = node->getOrCreateStateSet(); + osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); + node->setStateSet(cloned); + return cloned; + } + + osg::ref_ptr createAlphaTrackingUnlitMaterial() + { + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::DIFFUSE); + return mat; + } + + osg::ref_ptr createUnlitMaterial() + { + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::OFF); + return mat; + } + + osg::ref_ptr createTexturedQuad() + { + osg::ref_ptr geom = new osg::Geometry; + + osg::ref_ptr verts = new osg::Vec3Array; + verts->push_back(osg::Vec3f(-0.5, -0.5, 0)); + verts->push_back(osg::Vec3f(-0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, -0.5, 0)); + + geom->setVertexArray(verts); + + osg::ref_ptr texcoords = new osg::Vec2Array; + texcoords->push_back(osg::Vec2f(0, 0)); + texcoords->push_back(osg::Vec2f(0, 1)); + texcoords->push_back(osg::Vec2f(1, 1)); + texcoords->push_back(osg::Vec2f(1, 0)); + + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); + + return geom; + } + +} + +namespace MWRender +{ + +class AtmosphereUpdater : public SceneUtil::StateSetController +{ +public: + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } + +protected: + virtual void setDefaults(osg::StateSet* stateset) + { + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + } + +private: + osg::Vec4f mEmissionColor; +}; + +/// Transform that removes the eyepoint of the modelview matrix, +/// i.e. its children are positioned relative to the camera. +class CameraRelativeTransform : public osg::Transform +{ +public: + CameraRelativeTransform() + { + } + + CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) + : osg::Transform(copy, copyop) + { + } + + META_Node(MWRender, CameraRelativeTransform) + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); + matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); + return false; + } + else // absolute + { + matrix.makeIdentity(); + return true; } } -} - -void setAlpha (NifOgre::ObjectScenePtr scene, float alpha) -{ - for(size_t i = 0; i < scene->mParticles.size(); ++i) - setAlpha(scene, scene->mParticles[i], alpha); - for(size_t i = 0; i < scene->mEntities.size(); ++i) + osg::BoundingSphere computeBound() const { - if (scene->mEntities[i] != scene->mSkelBase) - setAlpha(scene, scene->mEntities[i], alpha); + return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); } -} +}; -} - -BillboardObject::BillboardObject( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) -: mVisibility(1.0f) +class DisableCullingVisitor : public osg::NodeVisitor { - SceneManager* sceneMgr = rootNode->getCreator(); - - Vector3 finalPosition = position.normalisedCopy() * 1000.f; - - static unsigned int bodyCount=0; - - mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); - mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); - - static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("billboard", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); - plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); - mEntity = sceneMgr->createEntity("billboard"); - mEntity->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); - mEntity->setVisibilityFlags(RV_Sky); - mEntity->setCastShadows(false); - - mNode = rootNode->createChildSceneNode(); - mNode->setPosition(finalPosition); - mNode->attachObject(mEntity); - mNode->setScale(Ogre::Vector3(450.f*initialSize)); - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-position.normalisedCopy())); - - sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); - - bodyCount++; -} - -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) -{ - mEntity->setVisible(visible); -} - -void BillboardObject::setSize(const float size) -{ - mNode->setScale(450.f*size, 450.f*size, 450.f*size); -} - -void BillboardObject::setVisibility(const float visibility) -{ - mVisibility = visibility; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) +public: + DisableCullingVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setDiffuse (0,0,0, visibility); - } -} - -void BillboardObject::setPosition(const Vector3& pPosition) -{ - Vector3 normalised = pPosition.normalisedCopy(); - Vector3 finalPosition = normalised * 1000.f; - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-normalised)); - mNode->setPosition(finalPosition); -} - -Vector3 BillboardObject::getPosition() const -{ - return mNode->getPosition(); -} - -void BillboardObject::setVisibilityFlags(int flags) -{ - mEntity->setVisibilityFlags(flags); -} - -void BillboardObject::setColour(const ColourValue& 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) -{ - mEntity->setRenderQueueGroup(id); -} - -SceneNode* BillboardObject::getNode() -{ - return mNode; -} - -Moon::Moon( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) - : BillboardObject(textureName, initialSize, position, rootNode, material) - , mType(Type_Masser) -{ - setVisibility(1.0); - - mMaterial->setProperty("alphatexture", sh::makeProperty(new sh::StringValue(textureName + "_alpha"))); - - mPhase = Moon::Phase_Full; -} - -void Moon::setType(const Moon::Type& type) -{ - mType = type; -} - -void Moon::setPhase(const Moon::Phase& phase) -{ - // Colour texture - Ogre::String textureName = "textures\\tx_"; - - if (mType == Moon::Type_Secunda) textureName += "secunda_"; - else textureName += "masser_"; - - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; - - textureName += ".dds"; - - if (mType == Moon::Type_Secunda) - { - sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("secunda_texture_alpha", "textures\\tx_mooncircle_full_s.dds"); - } - else - { - sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("masser_texture_alpha", "textures\\tx_mooncircle_full_m.dds"); } - mPhase = phase; -} + void apply(osg::Geode &geode) + { + geode.setCullingActive(false); + } +}; -unsigned int Moon::getPhaseInt() const +class ModVertexAlphaVisitor : public osg::NodeVisitor { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; +public: + ModVertexAlphaVisitor(int meshType) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMeshType(meshType) + { + } - return 0; -} + void apply(osg::Geode &geode) + { + for (unsigned int i=0; iasGeometry(); + if (!geom) + continue; + + // might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha + // (that isn't possible now, with the diffuse tracking the vertex colors) + + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; + } + + (*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha); + } + + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + } + } + +private: + int mMeshType; +}; + +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : mSceneManager(sceneManager) + , mHour(0.0f) , mDay(0) , mMonth(0) - , mSun(NULL) - , mSunGlare(NULL) - , mMasser(NULL) - , mSecunda(NULL) - , mCamera(pCamera) - , mRootNode(NULL) - , mSceneMgr(NULL) - , mAtmosphereDay(NULL) - , mAtmosphereNight(NULL) - , mCloudNode(NULL) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) - , mLightning(NULL) , mRemainingTransitionTime(0.0f) , mGlareFade(0.0f) , mGlare(0.0f) @@ -277,7 +240,6 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mCreated(false) , mCloudAnimationTimer(0.f) , mMoonRed(false) - , mParticleNode(NULL) , mRainEnabled(false) , mRainTimer(0) , mRainSpeed(0) @@ -285,118 +247,63 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mStormDirection(0,-1,0) , mIsStorm(false) { - mSceneMgr = root->getCreator(); - mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setCullingActive(false); + parentNode->addChild(skyroot); + + mRootNode = skyroot; + + // By default render before the world is rendered + mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); } void SkyManager::create() { assert(!mCreated); - 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))); - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + ModVertexAlphaVisitor modAtmosphere(0); + mAtmosphereDay->accept(modAtmosphere); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); + // osg::Node* alphaBlendedRoot = - // Create light used for thunderstorm - mLightning = mSceneMgr->createLight(); - mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - mLightning->setVisible (false); - mLightning->setDiffuseColour (ColourValue(3,3,3)); + mAtmosphereUpdater = new AtmosphereUpdater; + mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mSecunda->setType(Moon::Type_Secunda); - mSecunda->setRenderQueue(RQG_SkiesEarly+4); - - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mMasser->setRenderQueue(RQG_SkiesEarly+3); - mMasser->setType(Moon::Type_Masser); - - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSunGlare->setRenderQueue(RQG_SkiesLate); - mSunGlare->setVisibilityFlags(RV_NoReflection); - - Ogre::AxisAlignedBox aabInf = Ogre::AxisAlignedBox::BOX_INFINITE; - - // Stars - mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::ObjectScenePtr objects; - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("meshes\\sky_night_02.nif")) - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_02.nif"); + if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); else - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode); + mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + ModVertexAlphaVisitor modStars(2); + mAtmosphereNight->accept(modStars); + mAtmosphereNight->setNodeMask(0); - for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) - { - Entity* night1_ent = objects->mEntities[i]; - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - night1_ent->getMesh()->_setBounds (aabInf); + osg::Geode* geode = new osg::Geode; + osg::ref_ptr sun = createTexturedQuad(); + geode->addDrawable(sun); + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; + trans->setScale(osg::Vec3f(450,450,450)); + trans->addChild(geode); + mRootNode->addChild(trans); - 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"); + mSunTransform = trans; - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); + mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); + ModVertexAlphaVisitor modClouds(1); + mCloudNode->accept(modClouds); - m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + osg::ref_ptr sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); - night1_ent->getSubEntity(j)->setMaterialName(matName); - } - } - mObjects.push_back(objects); + mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - // Atmosphere (day) - mAtmosphereDay = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* atmosphere_ent = objects->mEntities[i]; - atmosphere_ent->setCastShadows(false); - atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); - atmosphere_ent->setVisibilityFlags(RV_Sky); - - for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) - atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); - - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - atmosphere_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); - - // Clouds - mCloudNode = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mCloudNode, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* clouds_ent = objects->mEntities[i]; - clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) - clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); - clouds_ent->setCastShadows(false); - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - clouds_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); + osg::ref_ptr depth = new osg::Depth; + depth->setWriteMask(false); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mCreated = true; } @@ -404,158 +311,51 @@ void SkyManager::create() SkyManager::~SkyManager() { clearRain(); - delete mSun; - delete mSunGlare; - delete mMasser; - delete mSecunda; } int SkyManager::getMasserPhase() const { + return 0; if (!mCreated) return 0; - return mMasser->getPhaseInt(); + //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { + return 0; if (!mCreated) return 0; - return mSecunda->getPhaseInt(); + //return mSecunda->getPhaseInt(); } void SkyManager::clearRain() { - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } } void SkyManager::updateRain(float dt) { - // Move existing rain - // Note: if rain gets disabled, we let the existing rain drops finish falling down. - float minHeight = 200; - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - Ogre::Vector3 pos = it->first->getPosition(); - pos.z -= mRainSpeed * dt; - it->first->setPosition(pos); - if (pos.z < -minHeight - // Here we might want to add a "splash" effect later - || MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), it->first->_getDerivedPosition())) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } - else - ++it; - } - - // Spawn new rain - float rainFrequency = mRainFrequency; - if (mRainEnabled) - { - mRainTimer += dt; - if (mRainTimer >= 1.f/rainFrequency) - { - mRainTimer = 0; - - // TODO: handle rain settings from Morrowind.ini - const float rangeRandom = 100; - float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - - // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still - // consider the orientation of the parent node for its position, just not for its orientation - float startHeight = 700; - Ogre::Vector3 worldPos = mParticleNode->_getDerivedPosition(); - worldPos += Ogre::Vector3(xOffs, yOffs, startHeight); - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), worldPos)) - return; - - Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); - - // Spawn a new rain object for each instance. - // TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions - // about the rain meshes being Quads and their dimensions. - // Or we could clone meshes into one vertex buffer manually. - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect); - for (unsigned int i=0; imEntities.size(); ++i) - { - objects->mEntities[i]->setRenderQueueGroup(RQG_Alpha); - objects->mEntities[i]->setVisibilityFlags(RV_Sky); - } - for (unsigned int i=0; imParticles.size(); ++i) - { - objects->mParticles[i]->setRenderQueueGroup(RQG_Alpha); - objects->mParticles[i]->setVisibilityFlags(RV_Sky); - } - mRainModels[offsetNode] = objects; - } - } } void SkyManager::update(float duration) { if (!mEnabled) return; - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - if (!mParticle.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mParticle->mControllers[i].update(); - - for (unsigned int i=0; imParticles.size(); ++i) - { - Ogre::ParticleSystem* psys = mParticle->mParticles[i]; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); - #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3 pos = p->mPosition; - Ogre::Real& timeToLive = p->mTimeToLive; - #else - Ogre::Vector3 pos = p->position; - Ogre::Real& timeToLive = p->timeToLive; - #endif - - if (psys->getKeepParticlesInLocalSpace() && psys->getParentNode()) - pos = psys->getParentNode()->convertLocalToWorldPosition(pos); - - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), pos)) - timeToLive = 0; - } - } - - if (mIsStorm) - mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - } - - if (mIsStorm) - mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - else - mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); + //if (mIsStorm) + // mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); + //else + // mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); updateRain(duration); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed; - 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)) ); + //mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); + //mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); - mMasser->setColour (ColourValue(1,1,1,1)); + //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); + //mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { @@ -573,45 +373,36 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun + /* Vector3 sun = mSunGlare->getPosition(); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*6; mSunGlare->setSize(val * mGlareFade); + */ } - mSunGlare->setVisible(mSunEnabled); - mSun->setVisible(mSunEnabled); - mMasser->setVisible(mMasserEnabled); - mSecunda->setVisible(mSecundaEnabled); + //mSunGlare->setVisible(mSunEnabled); + //mSun->setVisible(mSunEnabled); + //mMasser->setVisible(mMasserEnabled); + //mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days - mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); + //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } -void SkyManager::enable() +void SkyManager::setEnabled(bool enabled) { - if (!mCreated) + if (enabled && !mCreated) create(); - if (mParticleNode) - mParticleNode->setVisible(true); + if (!enabled) + clearRain(); - mRootNode->setVisible(true); - mEnabled = true; -} + mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); -void SkyManager::disable() -{ - if (mParticleNode) - mParticleNode->setVisible(false); - - clearRain(); - - mRootNode->setVisible(false); - - mEnabled = false; + mEnabled = enabled; } void SkyManager::setMoonColour (bool red) @@ -635,59 +426,53 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { - mParticle.setNull(); + if (mParticleEffect) + mRootNode->removeChild(mParticleEffect); + mParticleEffect = NULL; } else { - mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); - for(size_t i = 0; i < mParticle->mParticles.size(); ++i) - { - ParticleSystem* particle = mParticle->mParticles[i]; - particle->setRenderQueueGroup(RQG_Alpha); - particle->setVisibilityFlags(RV_Sky); - } + mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode); + DisableCullingVisitor visitor; + mParticleEffect->accept(visitor); + + /* for (size_t i = 0; i < mParticle->mControllers.size(); ++i) { if (mParticle->mControllers[i].getSource().isNull()) mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); } + */ } } if (mClouds != weather.mCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", Misc::ResourceHelpers::correctTexturePath(weather.mCloudTexture)); mClouds = weather.mCloudTexture; } if (mNextClouds != weather.mNextCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", Misc::ResourceHelpers::correctTexturePath(weather.mNextCloudTexture)); mNextClouds = weather.mNextCloudTexture; } if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", - sh::makeProperty(new sh::FloatValue(weather.mCloudBlendFactor))); } if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(weather.mCloudOpacity))); } if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, - weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, - weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); - - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); + /* + osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, + weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, + weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + */ mCloudColour = weather.mSunColor; } @@ -695,35 +480,32 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mSkyColour != 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))); + + mAtmosphereUpdater->setEmissionColor(mSkyColour); } if (mFogColour != weather.mFogColor) { mFogColour = weather.mFogColor; - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( - weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); } mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) { - if (weather.mNightFade == 0) - mAtmosphereNight->setVisible(false); - else + if (weather.mNightFade != 0) { - mAtmosphereNight->setVisible(true); + //sh::Factory::getInstance().setSharedParameter ("nightFade", + // sh::makeProperty(new sh::FloatValue(weather.mNightFade))); - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(weather.mNightFade))); - - mStarsOpacity = weather.mNightFade; + //mStarsOpacity = weather.mNightFade; } } + mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + + /* float strength; float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); if (timeofday_angle <= 0.44) @@ -735,12 +517,12 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSun->setVisibility(weather.mGlareView * strength); - mAtmosphereNight->setVisible(weather.mNight && mEnabled); if (mParticle.get()) setAlpha(mParticle, weather.mEffectFade); for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) setAlpha(it->second, weather.mEffectFade); + */ } void SkyManager::setGlare(const float glare) @@ -748,12 +530,6 @@ void SkyManager::setGlare(const float glare) mGlare = glare; } -Vector3 SkyManager::getRealSunPos() -{ - if (!mCreated) return Vector3(0,0,0); - return mSun->getNode()->getPosition() + mCamera->getRealPosition(); -} - void SkyManager::sunEnable() { mSunEnabled = true; @@ -764,32 +540,34 @@ void SkyManager::sunDisable() mSunEnabled = false; } -void SkyManager::setStormDirection(const Vector3 &direction) +void SkyManager::setStormDirection(const Ogre::Vector3 &direction) { mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_night) +void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSun->setPosition(direction); - mSunGlare->setPosition(direction); - float height = direction.z; - float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); + mSunTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mSunTransform->setAttitude(quat); + + //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Vector3& direction) +void SkyManager::setMasserDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mMasser->setPosition(direction); + //mMasser->setPosition(direction); } -void SkyManager::setSecundaDirection(const Vector3& direction) +void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mSecunda->setPosition(direction); + //mSecunda->setPosition(direction); } void SkyManager::masserEnable() @@ -815,6 +593,7 @@ void SkyManager::secundaDisable() void SkyManager::setLightningStrength(const float factor) { if (!mCreated) return; + /* if (factor > 0.f) { mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); @@ -822,18 +601,19 @@ void SkyManager::setLightningStrength(const float factor) } else mLightning->setVisible(false); + */ } void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - mMasser->setVisibility(fade); + //mMasser->setVisibility(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - mSecunda->setVisibility(fade); + //mSecunda->setVisibility(fade); } void SkyManager::setHour(double hour) @@ -847,28 +627,11 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -Ogre::SceneNode* SkyManager::getSunNode() -{ - if (!mCreated) return 0; - return mSun->getNode(); -} - void SkyManager::setGlareEnabled (bool enabled) { if (!mCreated || !mEnabled) return; - mSunGlare->setVisible (mSunEnabled && enabled); + //mSunGlare->setVisible (mSunEnabled && enabled); } -void SkyManager::attachToNode(SceneNode *sceneNode) -{ - if (!mParticleNode) - { - mParticleNode = sceneNode->createChildSceneNode(); - mParticleNode->setInheritOrientation(false); - } - else - { - sceneNode->addChild(mParticleNode); - } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 6950dbab34..c8403af71e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,128 +1,35 @@ -#ifndef GAME_RENDER_SKY_H -#define GAME_RENDER_SKY_H - -#include - -#include -#include -#include -#include -#include - -#include - -#include +#ifndef OPENMW_MWRENDER_SKY_H +#define OPENMW_MWRENDER_SKY_H +#include #include "../mwworld/weather.hpp" -namespace Ogre +namespace osg +{ + class Group; + class Node; + class Material; +} + +namespace Resource { - class RenderWindow; - class SceneNode; - class Camera; - class Viewport; class SceneManager; - class Entity; - class BillboardSet; - class TextureUnitState; } namespace MWRender { - class BillboardObject : public sh::MaterialInstanceListener - { - public: - BillboardObject( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - 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); - void setPosition(const Ogre::Vector3& pPosition); - void setVisible(const bool visible); - void setRenderQueue(unsigned int id); - void setVisibilityFlags(int flags); - void setSize(const float size); - Ogre::Vector3 getPosition() const; - - void setVisibility(const float visibility); - - Ogre::SceneNode* getNode(); - - protected: - float mVisibility; - Ogre::ColourValue mColour; - Ogre::SceneNode* mNode; - sh::MaterialInstance* mMaterial; - Ogre::Entity* mEntity; - }; - - - /* - * The moons need a seperate class because of their shader (which allows them to be partially transparent) - */ - class Moon : public BillboardObject - { - public: - Moon( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - virtual ~Moon() {} - - enum Phase - { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent - }; - - enum Type - { - Type_Masser = 0, - Type_Secunda - }; - - void setPhase(const Phase& phase); - void setType(const Type& type); - - unsigned int getPhaseInt() const; - - private: - Type mType; - Phase mPhase; - }; + class AtmosphereUpdater; class SkyManager { public: - SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); ~SkyManager(); - /// Attach weather particle effects to this scene node (should be the Camera's parent node) - void attachToNode(Ogre::SceneNode* sceneNode); - void update(float duration); - void enable(); - - void disable(); + void setEnabled(bool enabled); void setHour (double hour); ///< will be called even when sky is disabled. @@ -143,8 +50,6 @@ namespace MWRender void setWeather(const MWWorld::WeatherResult& weather); - Ogre::SceneNode* getSunNode(); - void sunEnable(); void sunDisable(); @@ -153,7 +58,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_night); + void setSunDirection(const osg::Vec3f& direction); void setMasserDirection(const Ogre::Vector3& direction); @@ -173,7 +78,6 @@ namespace MWRender void setGlare(const float glare); void setGlareEnabled(bool enabled); - Ogre::Vector3 getRealSunPos(); private: void create(); @@ -182,6 +86,22 @@ namespace MWRender void updateRain(float dt); void clearRain(); + Resource::SceneManager* mSceneManager; + + osg::ref_ptr mRootNode; + + osg::ref_ptr mParticleEffect; + + osg::ref_ptr mCloudNode; + + osg::ref_ptr mAtmosphereDay; + + osg::ref_ptr mAtmosphereNight; + + osg::ref_ptr mAtmosphereUpdater; + + osg::ref_ptr mSunTransform; + bool mCreated; bool mMoonRed; @@ -194,26 +114,6 @@ namespace MWRender float mCloudAnimationTimer; - BillboardObject* mSun; - BillboardObject* mSunGlare; - Moon* mMasser; - Moon* mSecunda; - - Ogre::Camera* mCamera; - Ogre::SceneNode* mRootNode; - Ogre::SceneManager* mSceneMgr; - - Ogre::SceneNode* mAtmosphereDay; - Ogre::SceneNode* mAtmosphereNight; - - Ogre::SceneNode* mCloudNode; - - std::vector mObjects; - - Ogre::SceneNode* mParticleNode; - NifOgre::ObjectScenePtr mParticle; - - std::map mRainModels; float mRainTimer; Ogre::Vector3 mStormDirection; @@ -225,14 +125,12 @@ namespace MWRender float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; - Ogre::ColourValue mCloudColour; - Ogre::ColourValue mSkyColour; - Ogre::ColourValue mFogColour; + osg::Vec4f mCloudColour; + osg::Vec4f mSkyColour; + osg::Vec4f mFogColour; std::string mCurrentParticleEffect; - Ogre::Light* mLightning; - float mRemainingTransitionTime; float mGlare; // target diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 3a8154ca7c..fd60224813 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -1,5 +1,7 @@ #include "fallback.hpp" -#include "boost/lexical_cast.hpp" + +#include + namespace MWWorld { Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) @@ -39,11 +41,11 @@ namespace MWWorld else return boost::lexical_cast(fallback); } - Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + osg::Vec4f Fallback::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); if(sum.empty()) - return Ogre::ColourValue(0,0,0); + return osg::Vec4f(0.f,0.f,0.f,1.f); else { std::string ret[3]; @@ -53,7 +55,7 @@ namespace MWWorld else if (sum[i] != ' ') ret[j]+=sum[i]; } - return Ogre::ColourValue(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + return osg::Vec4f(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f, 1.f); } } } diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index f69a5e57bb..af47063ee8 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace MWWorld { @@ -17,7 +17,7 @@ namespace MWWorld float getFallbackFloat(const std::string& fall) const; int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + osg::Vec4f getFallbackColour(const std::string& fall) const; }; } #endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 82814b623e..fe4f62953b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -13,16 +13,15 @@ #include "../mwsound/sound.hpp" -//#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/sky.hpp" #include "player.hpp" #include "esmstore.hpp" #include "fallback.hpp" #include "cellstore.hpp" -using namespace Ogre; using namespace MWWorld; -using namespace MWSound; namespace { @@ -31,7 +30,7 @@ namespace return x * (1-factor) + y * factor; } - Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor) + osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } @@ -196,7 +195,7 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const String& weather, bool instant) +void WeatherManager::setWeather(const std::string& weather, bool instant) { if (weather == mCurrentWeather && mNextWeather == "") { @@ -224,7 +223,7 @@ void WeatherManager::setWeather(const String& weather, bool instant) mFirstUpdate = false; } -void WeatherManager::setResult(const String& weatherType) +void WeatherManager::setResult(const std::string& weatherType) { const Weather& current = mWeatherSettings[weatherType]; @@ -387,8 +386,8 @@ void WeatherManager::update(float duration, bool paused) const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); if (!exterior) { - mRendering->skyDisable(); - mRendering->getSkyManager()->setLightningStrength(0.f); + mRendering->setSkyEnabled(false); + //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } @@ -421,16 +420,16 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z = 0; - mRendering->getSkyManager()->setStormDirection(mStormDirection); + //mRendering->getSkyManager()->setStormDirection(mStormDirection); } mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); - else - mRendering->getSkyManager()->sunEnable(); + //if (mHour >= mNightStart || mHour <= mSunriseTime) + //mRendering->getSkyManager()->sunDisable(); + //else + //mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -455,11 +454,11 @@ void WeatherManager::update(float duration, bool paused) theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } - Vector3 final( + osg::Vec3f final( static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final, is_night ); + mRendering->setSunDirection( final * -1 ); } /* @@ -484,20 +483,20 @@ void WeatherManager::update(float duration, bool paused) if (moonHeight != 0) { int facing = (moonHeight <= 1) ? 1 : -1; - Vector3 masser( + osg::Vec3f masser( (moonHeight - 1) * facing, (1 - moonHeight) * facing, moonHeight); - Vector3 secunda( + osg::Vec3f secunda( (moonHeight - 1) * facing * 1.25f, (1 - moonHeight) * facing * 0.8f, moonHeight); - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); + //mRendering->getSkyManager()->setMasserDirection(masser); + //mRendering->getSkyManager()->setSecundaDirection(secunda); + //mRendering->getSkyManager()->masserEnable(); + //mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -508,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + //mRendering->getSkyManager()->setMasserFade(masserAngleFade); + //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); + //mRendering->getSkyManager()->masserDisable(); + //mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -540,13 +539,13 @@ void WeatherManager::update(float duration, bool paused) } mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - else + //if (mThunderFlash > 0) + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //else { mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; - mRendering->getSkyManager()->setLightningStrength( 0.f ); + //mRendering->getSkyManager()->setLightningStrength( 0.f ); } } else @@ -557,19 +556,19 @@ void WeatherManager::update(float duration, bool paused) { mThunderFlash = mThunderThreshold; - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); mThunderSoundDelay = 0.25; } } } - else - mRendering->getSkyManager()->setLightningStrength(0.f); + //else + //mRendering->getSkyManager()->setLightningStrength(0.f); } mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->sunEnable(false); + //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult); @@ -850,3 +849,8 @@ Ogre::Vector3 WeatherManager::getStormDirection() const { return mStormDirection; } + +void WeatherManager::advanceTime(double hours) +{ + mTimePassed += hours*3600; +} diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a2e6681595..002f4355c8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/soundmanager.hpp" @@ -37,15 +38,15 @@ namespace MWWorld std::string mNextCloudTexture; float mCloudBlendFactor; - Ogre::ColourValue mFogColor; + osg::Vec4f mFogColor; - Ogre::ColourValue mAmbientColor; + osg::Vec4f mAmbientColor; - Ogre::ColourValue mSkyColor; + osg::Vec4f mSkyColor; - Ogre::ColourValue mSunColor; + osg::Vec4f mSunColor; - Ogre::ColourValue mSunDiscColor; + osg::Vec4f mSunDiscColor; float mFogDepth; @@ -80,25 +81,25 @@ namespace MWWorld std::string mCloudTexture; // Sky (atmosphere) colors - Ogre::ColourValue mSkySunriseColor, + osg::Vec4f mSkySunriseColor, mSkyDayColor, mSkySunsetColor, mSkyNightColor; // Fog colors - Ogre::ColourValue mFogSunriseColor, + osg::Vec4f mFogSunriseColor, mFogDayColor, mFogSunsetColor, mFogNightColor; // Ambient lighting colors - Ogre::ColourValue mAmbientSunriseColor, + osg::Vec4f mAmbientSunriseColor, mAmbientDayColor, mAmbientSunsetColor, mAmbientNightColor; // Sun (directional) lighting colors - Ogre::ColourValue mSunSunriseColor, + osg::Vec4f mSunSunriseColor, mSunDayColor, mSunSunsetColor, mSunNightColor; @@ -108,7 +109,7 @@ namespace MWWorld mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) - Ogre::ColourValue mSunDiscSunsetColor; + osg::Vec4f mSunDiscSunsetColor; // Duration of weather transition (in days) float mTransitionDelta; @@ -185,10 +186,7 @@ namespace MWWorld Ogre::Vector3 getStormDirection() const; - void advanceTime(double hours) - { - mTimePassed += hours*3600; - } + void advanceTime(double hours); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 994a0c9dd1..20298bd858 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -131,18 +131,16 @@ namespace MWWorld void World::adjustSky() { -#if 0 if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - mGlobalVariables["month"].getInteger()); + //mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); + //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + // mGlobalVariables["month"].getInteger()); - mRendering->skyEnable(); + mRendering->setSkyEnabled(true); } else - mRendering->skyDisable(); -#endif + mRendering->setSkyEnabled(false); } World::World ( @@ -171,7 +169,7 @@ namespace MWWorld //mPhysEngine->setSceneManager(renderer.getScene()); - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); @@ -267,9 +265,9 @@ namespace MWWorld // mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game - //delete mWeatherManager; - //mWeatherManager = 0; - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + delete mWeatherManager; + mWeatherManager = 0; + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); @@ -277,7 +275,7 @@ namespace MWWorld void World::clear() { - //mWeatherManager->clear(); + mWeatherManager->clear(); //mRendering->clear(); #if 0 mProjectileManager->clear(); @@ -348,7 +346,7 @@ namespace MWWorld mCells.write (writer, progress); mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); - //mWeatherManager->write (writer, progress); + mWeatherManager->write (writer, progress); #if 0 mProjectileManager->write (writer, progress); #endif @@ -378,7 +376,7 @@ namespace MWWorld if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - //!mWeatherManager->readRecord (reader, type) && + !mWeatherManager->readRecord (reader, type) && !mCells.readRecord (reader, type, contentFileMap) #if 0 && !mProjectileManager->readRecord (reader, type) @@ -479,7 +477,7 @@ namespace MWWorld // Must be cleared before mRendering is destroyed mProjectileManager->clear(); #endif - //delete mWeatherManager; + delete mWeatherManager; delete mWorldScene; delete mRendering; //delete mPhysics; @@ -819,7 +817,7 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - //mWeatherManager->advanceTime (hours); + mWeatherManager->advanceTime (hours); hours += mGlobalVariables["gamehour"].getFloat(); @@ -845,7 +843,7 @@ namespace MWWorld //mRendering->skySetHour (hour); - //mWeatherManager->setHour(static_cast(hour)); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1604,11 +1602,11 @@ namespace MWWorld void World::update (float duration, bool paused) { - /* if (mGoToJail && !paused) goToJail(); updateWeather(duration, paused); + /* if (!paused) doPhysics (duration); @@ -1731,17 +1729,17 @@ namespace MWWorld int World::getCurrentWeather() const { - return 0;//mWeatherManager->getWeatherID(); + return mWeatherManager->getWeatherID(); } void World::changeWeather(const std::string& region, const unsigned int id) { - //mWeatherManager->changeWeather(region, id); + mWeatherManager->changeWeather(region, id); } void World::modRegion(const std::string ®ionid, const std::vector &chances) { - //mWeatherManager->modRegion(regionid, chances); + mWeatherManager->modRegion(regionid, chances); } Ogre::Vector2 World::getNorthVector (CellStore* cell) @@ -2975,10 +2973,10 @@ namespace MWWorld if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - //mWeatherManager->switchToNextWeather(true); + mWeatherManager->switchToNextWeather(true); } - //mWeatherManager->update(duration, paused); + mWeatherManager->update(duration, paused); } struct AddDetectedReference diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f77bb47609..9afda480b6 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -81,7 +81,7 @@ namespace MWWorld MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; - //MWWorld::WeatherManager* mWeatherManager; + MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index abce7020cf..6b1c016441 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util + clone attach lightmanager visitor util statesetcontroller ) add_component_dir (nif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ead6a9669f..393f322d7d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -142,4 +142,14 @@ namespace Resource } } + const VFS::Manager* SceneManager::getVFS() const + { + return mVFS; + } + + Resource::TextureManager* SceneManager::getTextureManager() + { + return mTextureManager; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 4d6ad48556..6a52dfb21a 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -55,6 +55,10 @@ namespace Resource /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); + const VFS::Manager* getVFS() const; + + Resource::TextureManager* getTextureManager(); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetcontroller.cpp new file mode 100644 index 0000000000..301e709e40 --- /dev/null +++ b/components/sceneutil/statesetcontroller.cpp @@ -0,0 +1,31 @@ +#include "statesetcontroller.hpp" + +#include + +namespace SceneUtil +{ + + void StateSetController::operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!mStateSets[0]) + { + // first time setup + osg::StateSet* src = node->getOrCreateStateSet(); + for (int i=0; i<2; ++i) // Using SHALLOW_COPY for StateAttributes, if users want to modify it is their responsibility to set a non-shared one first + // This can be done conveniently in user implementations of the setDefaults() method + { + mStateSets[i] = static_cast(osg::clone(src, osg::CopyOp::SHALLOW_COPY)); + setDefaults(mStateSets[i]); + } + } + + // Swap to make the StateSet in [0] writable, [1] is now the StateSet that was queued by the last frame + std::swap(mStateSets[0], mStateSets[1]); + node->setStateSet(mStateSets[0]); + + apply(mStateSets[0], nv); + + traverse(node, nv); + } + +} diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetcontroller.hpp new file mode 100644 index 0000000000..7c6c7e4075 --- /dev/null +++ b/components/sceneutil/statesetcontroller.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H + +#include + +namespace SceneUtil +{ + + /// @brief Implements efficient pre-frame updating of StateSets. + /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame + /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to + /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw + /// traversals run in parallel can yield up to 200% framerates. + /// @par Race conditions are prevented using a "double buffering" scheme - we have two StateSets that take turns, + /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. + /// After a frame is completed the places are swapped. + /// @par Must be set as UpdateCallback on a Node. + class StateSetController : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + protected: + /// Apply state - to override in derived classes + /// @note Due to the double buffering approach you *have* to apply all state + /// even if it has not changed since the last frame. + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0; + + /// Set default state - optionally override in derived classes + /// @par May be used e.g. to allocate StateAttributes. + virtual void setDefaults(osg::StateSet* stateset) {} + + private: + osg::ref_ptr mStateSets[2]; + }; + +} + +#endif From de2c85e0f8b0cb5e6389bae5d0562eba3a54993b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 16:41:06 +0200 Subject: [PATCH 0116/1812] Port nifloader to the more efficient StateSetController --- components/nifosg/controller.cpp | 70 ++++++++------------- components/nifosg/controller.hpp | 31 ++++----- components/nifosg/nifloader.cpp | 37 ++++++----- components/sceneutil/statesetcontroller.cpp | 43 +++++++++++++ components/sceneutil/statesetcontroller.hpp | 31 ++++++++- 5 files changed, 132 insertions(+), 80 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 59ba9ad4ff..344cb2323e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -278,7 +278,7 @@ UVController::UVController(const Nif::NiUVData *data, std::set textureUnits } UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy) + : osg::Object(copy, copyop), StateSetController(copy, copyop), Controller(copy) , mUTrans(copy.mUTrans) , mVTrans(copy.mVTrans) , mUScale(copy.mUScale) @@ -287,11 +287,17 @@ UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) { } -void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +void UVController::setDefaults(osg::StateSet *stateset) +{ + osg::TexMat* texMat = new osg::TexMat; + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); +} + +void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); float value = getInputValue(nv); float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); @@ -301,15 +307,13 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); - osg::TexMat* texMat = new osg::TexMat; - texMat->setMatrix(mat); - - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + // setting once is enough because all other texture units share the same TexMat (see setDefaults). + if (mTextureUnits.size()) { - stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(*mTextureUnits.begin(), osg::StateAttribute::TEXMAT)); + texMat->setMatrix(mat); } } - traverse(node, nv); } VisController::VisController(const Nif::NiVisData *data) @@ -363,26 +367,21 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetController(copy, copyop), ValueInterpolator(), Controller(copy) , mData(copy.mData) { } -void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) +void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); float value = interpKey(mData->mKeys, getInputValue(nv)); - osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - if (mat) - { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.a() = value; - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); - } + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } - traverse(node, nv); } MaterialColorController::MaterialColorController(const Nif::NiPosData *data) @@ -395,26 +394,21 @@ MaterialColorController::MaterialColorController() } MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop), Controller(copy) + : StateSetController(copy, copyop), Controller(copy) , mData(copy.mData) { } -void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) +void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - osg::StateSet* stateset = getWritableStateSet(node); osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); - osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - if (mat) - { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); - } + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } - traverse(node, nv); } FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) @@ -429,7 +423,7 @@ FlipController::FlipController() } FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop) + : StateSetController(copy, copyop) , Controller(copy) , mTexSlot(copy.mTexSlot) , mDelta(copy.mDelta) @@ -437,15 +431,13 @@ FlipController::FlipController(const FlipController ©, const osg::CopyOp &co { } -void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) +void FlipController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { if (hasInput() && mDelta != 0) { - osg::StateSet* stateset = getWritableStateSet(node); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } - traverse(node, nv); } ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl) @@ -507,12 +499,4 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n traverse(node, nv); } -osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node) -{ - osg::StateSet* orig = node->getOrCreateStateSet(); - osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY); - node->setStateSet(cloned); - return cloned; -} - } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 1a90b8759e..103a720460 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -8,6 +8,8 @@ #include +#include + #include #include //UVController @@ -189,19 +191,7 @@ namespace NifOsg bool mEnabled; }; - class StateSetController - { - protected: - // Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame - // queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would - // undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates. - // If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames, - // kind of like a double buffering scheme. - osg::StateSet* getWritableStateSet(osg::Node* node); - }; - - // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting - class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class UVController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { public: UVController(); @@ -210,7 +200,8 @@ namespace NifOsg META_Object(NifOsg,UVController) - virtual void operator() (osg::Node*, osg::NodeVisitor*); + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); private: Nif::FloatKeyMapPtr mUTrans; @@ -237,7 +228,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -247,12 +238,12 @@ namespace NifOsg AlphaController(); AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -264,10 +255,10 @@ namespace NifOsg META_Object(NifOsg, MaterialColorController) - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; - class FlipController : public osg::NodeCallback, public Controller, public StateSetController + class FlipController : public SceneUtil::StateSetController, public Controller { private: int mTexSlot; @@ -281,7 +272,7 @@ namespace NifOsg META_Object(NifOsg, FlipController) - virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); }; class ParticleSystemController : public osg::NodeCallback, public Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a858473514..8dc286a923 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,13 +719,13 @@ namespace NifOsg return skel; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i setNodeMask(0x1); } - applyNodeProperties(nifNode, transformNode, textureManager, boundTextures, animflags); + osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + + applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { @@ -836,9 +838,12 @@ namespace NifOsg handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures, animflags); + handleMeshControllers(nifNode, composite, boundTextures, animflags); } + if (composite->getNumControllers() > 0) + transformNode->addUpdateCallback(composite); + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); @@ -866,7 +871,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetController* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -881,8 +886,7 @@ namespace NifOsg osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); - - transformNode->addUpdateCallback(ctrl); + composite->addController(ctrl); } } } @@ -915,8 +919,9 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) { + osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -926,21 +931,23 @@ namespace NifOsg const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, ctrl, animflags); - node->addUpdateCallback(ctrl); + composite->addController(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); setupController(matctrl, ctrl, animflags); - node->addUpdateCallback(ctrl); + composite->addController(ctrl); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } + if (composite->getNumControllers() > 0) + node->addUpdateCallback(composite); } - static void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -972,7 +979,7 @@ namespace NifOsg } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); - node->addUpdateCallback(callback); + composite->addController(callback); } else std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; @@ -1419,7 +1426,7 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, - osg::Node *node, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1594,7 +1601,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, node, textureManager, stateset, animflags); + handleTextureControllers(texprop, composite, textureManager, stateset, animflags); } break; } @@ -1646,7 +1653,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, stateset, animflags); + handleMaterialControllers(matprop, node, animflags); break; } diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetcontroller.cpp index 301e709e40..079eaf6aa1 100644 --- a/components/sceneutil/statesetcontroller.cpp +++ b/components/sceneutil/statesetcontroller.cpp @@ -28,4 +28,47 @@ namespace SceneUtil traverse(node, nv); } + StateSetController::StateSetController() + { + } + + StateSetController::StateSetController(const StateSetController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + { + } + + // ---------------------------------------------------------------------------------- + + void CompositeStateSetController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + for (unsigned int i=0; iapply(stateset, nv); + } + + void CompositeStateSetController::setDefaults(osg::StateSet *stateset) + { + for (unsigned int i=0; isetDefaults(stateset); + } + + CompositeStateSetController::CompositeStateSetController() + { + } + + CompositeStateSetController::CompositeStateSetController(const CompositeStateSetController ©, const osg::CopyOp ©op) + : StateSetController(copy, copyop) + , mCtrls(copy.mCtrls) + { + } + + unsigned int CompositeStateSetController::getNumControllers() + { + return mCtrls.size(); + } + + void CompositeStateSetController::addController(StateSetController *ctrl) + { + mCtrls.push_back(ctrl); + } + } diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetcontroller.hpp index 7c6c7e4075..e34332e5f3 100644 --- a/components/sceneutil/statesetcontroller.hpp +++ b/components/sceneutil/statesetcontroller.hpp @@ -15,16 +15,21 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. + /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetController. class StateSetController : public osg::NodeCallback { public: + StateSetController(); + StateSetController(const StateSetController& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, StateSetController) + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); - protected: /// Apply state - to override in derived classes /// @note Due to the double buffering approach you *have* to apply all state /// even if it has not changed since the last frame. - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0; + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) {} /// Set default state - optionally override in derived classes /// @par May be used e.g. to allocate StateAttributes. @@ -34,6 +39,28 @@ namespace SceneUtil osg::ref_ptr mStateSets[2]; }; + /// @brief A variant of the StateSetController that can be made up of multiple controllers all controlling the same target. + class CompositeStateSetController : public StateSetController + { + public: + CompositeStateSetController(); + CompositeStateSetController(const CompositeStateSetController& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, CompositeStateSetController) + + unsigned int getNumControllers(); + + void addController(StateSetController* ctrl); + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); + + protected: + + virtual void setDefaults(osg::StateSet *stateset); + + std::vector > mCtrls; + }; + } #endif From c516e897ee7265c59340305e7ae115c79a449e2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 17:29:12 +0200 Subject: [PATCH 0117/1812] Move Controller base classes to SceneUtil, add visitor to assign ControllerSources --- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 12 +-- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 31 +------ components/nifosg/controller.hpp | 51 +++-------- components/nifosg/nifloader.cpp | 21 +++-- components/sceneutil/controller.cpp | 86 +++++++++++++++++++ components/sceneutil/controller.hpp | 64 ++++++++++++++ ...esetcontroller.cpp => statesetupdater.cpp} | 30 ++++--- ...esetcontroller.hpp => statesetupdater.hpp} | 23 ++--- 11 files changed, 211 insertions(+), 115 deletions(-) create mode 100644 components/sceneutil/controller.cpp create mode 100644 components/sceneutil/controller.hpp rename components/sceneutil/{statesetcontroller.cpp => statesetupdater.cpp} (58%) rename components/sceneutil/{statesetcontroller.hpp => statesetupdater.hpp} (77%) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cbded364a6..754adec926 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -74,7 +74,7 @@ protected: virtual void setValue(Ogre::Real value); }; - class NullAnimationTime : public NifOsg::ControllerSource + class NullAnimationTime : public SceneUtil::ControllerSource { public: virtual float getValue(osg::NodeVisitor *nv) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e9a5d302c1..ba34cf303b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include @@ -22,7 +22,7 @@ namespace MWRender { - class StateUpdater : public SceneUtil::StateSetController + class StateUpdater : public SceneUtil::StateSetUpdater { public: virtual void setDefaults(osg::StateSet *stateset) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index be702a2212..a4fd171727 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,14 +37,6 @@ namespace { - osg::StateSet* getWritableStateSet(osg::Node* node) - { - osg::StateSet* stateset = node->getOrCreateStateSet(); - osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); - node->setStateSet(cloned); - return cloned; - } - osg::ref_ptr createAlphaTrackingUnlitMaterial() { osg::ref_ptr mat = new osg::Material; @@ -95,7 +87,7 @@ namespace namespace MWRender { -class AtmosphereUpdater : public SceneUtil::StateSetController +class AtmosphereUpdater : public SceneUtil::StateSetUpdater { public: void setEmissionColor(osg::Vec4f emissionColor) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6b1c016441..f61724eeb2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetcontroller + clone attach lightmanager visitor util statesetupdater controller ) add_component_dir (nif diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 344cb2323e..ce004dc796 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -64,15 +64,6 @@ float ControllerFunction::calculate(float value) } } -FrameTimeSource::FrameTimeSource() -{ -} - -float FrameTimeSource::getValue(osg::NodeVisitor *nv) -{ - return nv->getFrameStamp()->getSimulationTime(); -} - KeyframeController::KeyframeController() { } @@ -207,20 +198,6 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } -Controller::Controller() -{ -} - -bool Controller::hasInput() const -{ - return mSource.get() != NULL; -} - -float Controller::getInputValue(osg::NodeVisitor* nv) -{ - return mFunction->calculate(mSource->getValue(nv)); -} - GeomMorpherController::GeomMorpherController() { } @@ -278,7 +255,7 @@ UVController::UVController(const Nif::NiUVData *data, std::set textureUnits } UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) - : osg::Object(copy, copyop), StateSetController(copy, copyop), Controller(copy) + : osg::Object(copy, copyop), StateSetUpdater(copy, copyop), Controller(copy) , mUTrans(copy.mUTrans) , mVTrans(copy.mVTrans) , mUScale(copy.mUScale) @@ -367,7 +344,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetUpdater(copy, copyop), ValueInterpolator(), Controller(copy) , mData(copy.mData) { } @@ -394,7 +371,7 @@ MaterialColorController::MaterialColorController() } MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop), Controller(copy) + : StateSetUpdater(copy, copyop), Controller(copy) , mData(copy.mData) { } @@ -423,7 +400,7 @@ FlipController::FlipController() } FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop) + : StateSetUpdater(copy, copyop) , Controller(copy) , mTexSlot(copy.mTexSlot) , mDelta(copy.mDelta) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 103a720460..3136b31181 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -8,7 +8,8 @@ #include -#include +#include +#include #include @@ -43,7 +44,6 @@ namespace osgAnimation namespace NifOsg { - // FIXME: Should not be here. We might also want to use this for non-NIF model formats class ValueInterpolator { protected: @@ -76,8 +76,7 @@ namespace NifOsg } }; - // FIXME: Should not be here. We might also want to use this for non-NIF model formats - class ControllerFunction + class ControllerFunction : public SceneUtil::ControllerFunction { private: float mFrequency; @@ -98,35 +97,7 @@ namespace NifOsg float calculate(float value); }; - class ControllerSource - { - public: - virtual float getValue(osg::NodeVisitor* nv) = 0; - }; - - class FrameTimeSource : public ControllerSource - { - public: - FrameTimeSource(); - virtual float getValue(osg::NodeVisitor* nv); - }; - - class Controller - { - public: - Controller(); - - bool hasInput() const; - - float getInputValue(osg::NodeVisitor* nv); - - boost::shared_ptr mSource; - - // The source value gets passed through this function before it's passed on to the DestValue. - boost::shared_ptr mFunction; - }; - - class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator + class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator { public: GeomMorpherController(const Nif::NiMorphData* data); @@ -141,7 +112,7 @@ namespace NifOsg std::vector mKeyFrames; }; - class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller, public ValueInterpolator { public: KeyframeController(const Nif::NiKeyframeData *data); @@ -191,7 +162,7 @@ namespace NifOsg bool mEnabled; }; - class UVController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { public: UVController(); @@ -211,7 +182,7 @@ namespace NifOsg std::set mTextureUnits; }; - class VisController : public osg::NodeCallback, public Controller + class VisController : public osg::NodeCallback, public SceneUtil::Controller { private: std::vector mData; @@ -228,7 +199,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -243,7 +214,7 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public SceneUtil::StateSetController, public Controller, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -258,7 +229,7 @@ namespace NifOsg virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; - class FlipController : public SceneUtil::StateSetController, public Controller + class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: int mTexSlot; @@ -275,7 +246,7 @@ namespace NifOsg virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); }; - class ParticleSystemController : public osg::NodeCallback, public Controller + class ParticleSystemController : public osg::NodeCallback, public SceneUtil::Controller { public: ParticleSystemController(const Nif::NiParticleSystemController* ctrl); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8dc286a923..1d7eaba2c9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -719,7 +719,7 @@ namespace NifOsg return skel; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); + bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; + if (autoPlay) + toSetup->mSource = boost::shared_ptr(new SceneUtil::FrameTimeSource); toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } @@ -825,7 +824,7 @@ namespace NifOsg transformNode->setNodeMask(0x1); } - osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); @@ -871,7 +870,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetController* composite, const std::map &boundTextures, int animflags) + static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -921,7 +920,7 @@ namespace NifOsg static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) { - osg::ref_ptr composite = new SceneUtil::CompositeStateSetController; + osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -947,7 +946,7 @@ namespace NifOsg node->addUpdateCallback(composite); } - static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -1426,7 +1425,7 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetController* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp new file mode 100644 index 0000000000..565d486723 --- /dev/null +++ b/components/sceneutil/controller.cpp @@ -0,0 +1,86 @@ +#include "controller.hpp" + +#include "statesetupdater.hpp" + +#include +#include + +namespace SceneUtil +{ + + + Controller::Controller() + { + } + + bool Controller::hasInput() const + { + return mSource.get() != NULL; + } + + float Controller::getInputValue(osg::NodeVisitor* nv) + { + return mFunction->calculate(mSource->getValue(nv)); + } + + FrameTimeSource::FrameTimeSource() + { + } + + float FrameTimeSource::getValue(osg::NodeVisitor *nv) + { + return nv->getFrameStamp()->getSimulationTime(); + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) + : mToAssign(toAssign) + , osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + void AssignControllerSourcesVisitor::apply(osg::Node &node) + { + osg::NodeCallback* callback = node.getUpdateCallback(); + while (callback) + { + if (Controller* ctrl = dynamic_cast(callback)) + assign(node, *ctrl); + if (CompositeStateSetUpdater* composite = dynamic_cast(callback)) + { + for (unsigned int i=0; igetNumControllers(); ++i) + { + StateSetUpdater* statesetcontroller = composite->getController(i); + if (Controller* ctrl = dynamic_cast(statesetcontroller)) + assign(node, *ctrl); + } + } + + callback = callback->getNestedCallback(); + } + + traverse(node); + } + + void AssignControllerSourcesVisitor::apply(osg::Geode &geode) + { + for (unsigned int i=0; igetUpdateCallback(); + if (Controller* ctrl = dynamic_cast(callback)) + assign(geode, *ctrl); + } + } + + void AssignControllerSourcesVisitor::assign(osg::Node&, Controller &ctrl) + { + if (!ctrl.mSource.get()) + ctrl.mSource = mToAssign; + } + +} diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp new file mode 100644 index 0000000000..de73c7e802 --- /dev/null +++ b/components/sceneutil/controller.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_CONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_CONTROLLER_H + +#include + +#include + +namespace SceneUtil +{ + + class ControllerSource + { + public: + virtual float getValue(osg::NodeVisitor* nv) = 0; + }; + + class FrameTimeSource : public ControllerSource + { + public: + FrameTimeSource(); + virtual float getValue(osg::NodeVisitor* nv); + }; + + class ControllerFunction + { + public: + virtual float calculate(float input) = 0; + }; + + class Controller + { + public: + Controller(); + + bool hasInput() const; + + float getInputValue(osg::NodeVisitor* nv); + + boost::shared_ptr mSource; + + // The source value gets passed through this function before it's passed on to the DestValue. + boost::shared_ptr mFunction; + }; + + class AssignControllerSourcesVisitor : public osg::NodeVisitor + { + public: + AssignControllerSourcesVisitor(); + AssignControllerSourcesVisitor(boost::shared_ptr toAssign); + + virtual void apply(osg::Node& node); + virtual void apply(osg::Geode& geode); + + /// Assign the wanted ControllerSource. May be overriden in derived classes. + /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. + virtual void assign(osg::Node& node, Controller& ctrl); + + private: + boost::shared_ptr mToAssign; + }; + +} + +#endif diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetupdater.cpp similarity index 58% rename from components/sceneutil/statesetcontroller.cpp rename to components/sceneutil/statesetupdater.cpp index 079eaf6aa1..8ed229aa6f 100644 --- a/components/sceneutil/statesetcontroller.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -1,11 +1,11 @@ -#include "statesetcontroller.hpp" +#include "statesetupdater.hpp" #include namespace SceneUtil { - void StateSetController::operator()(osg::Node* node, osg::NodeVisitor* nv) + void StateSetUpdater::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!mStateSets[0]) { @@ -28,45 +28,51 @@ namespace SceneUtil traverse(node, nv); } - StateSetController::StateSetController() + StateSetUpdater::StateSetUpdater() { } - StateSetController::StateSetController(const StateSetController ©, const osg::CopyOp ©op) + StateSetUpdater::StateSetUpdater(const StateSetUpdater ©, const osg::CopyOp ©op) : osg::NodeCallback(copy, copyop) { } // ---------------------------------------------------------------------------------- - void CompositeStateSetController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + void CompositeStateSetUpdater::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { for (unsigned int i=0; iapply(stateset, nv); } - void CompositeStateSetController::setDefaults(osg::StateSet *stateset) + void CompositeStateSetUpdater::setDefaults(osg::StateSet *stateset) { for (unsigned int i=0; isetDefaults(stateset); } - CompositeStateSetController::CompositeStateSetController() + CompositeStateSetUpdater::CompositeStateSetUpdater() { } - CompositeStateSetController::CompositeStateSetController(const CompositeStateSetController ©, const osg::CopyOp ©op) - : StateSetController(copy, copyop) - , mCtrls(copy.mCtrls) + CompositeStateSetUpdater::CompositeStateSetUpdater(const CompositeStateSetUpdater ©, const osg::CopyOp ©op) + : StateSetUpdater(copy, copyop) { + for (unsigned int i=0; i(osg::clone(copy.mCtrls[i].get(), copyop))); } - unsigned int CompositeStateSetController::getNumControllers() + unsigned int CompositeStateSetUpdater::getNumControllers() { return mCtrls.size(); } - void CompositeStateSetController::addController(StateSetController *ctrl) + StateSetUpdater* CompositeStateSetUpdater::getController(int i) + { + return mCtrls[i]; + } + + void CompositeStateSetUpdater::addController(StateSetUpdater *ctrl) { mCtrls.push_back(ctrl); } diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetupdater.hpp similarity index 77% rename from components/sceneutil/statesetcontroller.hpp rename to components/sceneutil/statesetupdater.hpp index e34332e5f3..56f832a086 100644 --- a/components/sceneutil/statesetcontroller.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -15,14 +15,14 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. - /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetController. - class StateSetController : public osg::NodeCallback + /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. + class StateSetUpdater : public osg::NodeCallback { public: - StateSetController(); - StateSetController(const StateSetController& copy, const osg::CopyOp& copyop); + StateSetUpdater(); + StateSetUpdater(const StateSetUpdater& copy, const osg::CopyOp& copyop); - META_Object(SceneUtil, StateSetController) + META_Object(SceneUtil, StateSetUpdater) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); @@ -40,17 +40,18 @@ namespace SceneUtil }; /// @brief A variant of the StateSetController that can be made up of multiple controllers all controlling the same target. - class CompositeStateSetController : public StateSetController + class CompositeStateSetUpdater : public StateSetUpdater { public: - CompositeStateSetController(); - CompositeStateSetController(const CompositeStateSetController& copy, const osg::CopyOp& copyop); + CompositeStateSetUpdater(); + CompositeStateSetUpdater(const CompositeStateSetUpdater& copy, const osg::CopyOp& copyop); - META_Object(SceneUtil, CompositeStateSetController) + META_Object(SceneUtil, CompositeStateSetUpdater) unsigned int getNumControllers(); + StateSetUpdater* getController(int i); - void addController(StateSetController* ctrl); + void addController(StateSetUpdater* ctrl); virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); @@ -58,7 +59,7 @@ namespace SceneUtil virtual void setDefaults(osg::StateSet *stateset); - std::vector > mCtrls; + std::vector > mCtrls; }; } From f7da9796692e14c79632cb85fa75a90b082cd863 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 14 Apr 2015 18:56:11 +0200 Subject: [PATCH 0118/1812] Add FrameSwitch (geometry "double buffering") for efficient updates of RigGeometry & MorphGeometry --- components/nifosg/nifloader.cpp | 56 +++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1d7eaba2c9..b61e3824b8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -176,6 +176,36 @@ namespace collectMaterialProperties(nifNode->parent, out); } + class FrameSwitch : public osg::Group + { + public: + FrameSwitch() + { + } + + FrameSwitch(const FrameSwitch& copy, const osg::CopyOp& copyop) + : osg::Group(copy, copyop) + { + } + + META_Object(NifOsg, FrameSwitch) + + virtual void traverse(osg::NodeVisitor& nv) + { + const osg::FrameStamp* stamp = nv.getFrameStamp(); + if (!stamp || nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + osg::Group::traverse(nv); + else + { + for (unsigned int i=0; igetFrameNumber()%2) + getChild(i)->accept(nv); + } + } + } + }; + // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. // Must be set on a Bone. class UpdateBone : public osg::NodeCallback @@ -1306,7 +1336,19 @@ namespace NifOsg geode->addDrawable(geometry); - parentNode->addChild(geode); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) + { + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch + // This is so we can set the DataVariance as STATIC, giving a huge performance boost + geometry->setDataVariance(osg::Object::STATIC); + osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); + osg::ref_ptr frameswitch = new FrameSwitch; + frameswitch->addChild(geode); + frameswitch->addChild(geode2); + parentNode->addChild(frameswitch); + } + else + parentNode->addChild(geode); } static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -1419,7 +1461,17 @@ namespace NifOsg geode->addDrawable(rig); geode->addUpdateCallback(new DirtyBoundCallback); - trans->addChild(geode); + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch + // This is so we can set the DataVariance as STATIC, giving a huge performance boost + rig->setDataVariance(osg::Object::STATIC); + osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| + osg::CopyOp::DEEP_COPY_DRAWABLES)); + + osg::ref_ptr frameswitch = new FrameSwitch; + frameswitch->addChild(geode); + frameswitch->addChild(geode2); + + trans->addChild(frameswitch); parentNode->addChild(trans); } From 13a1ba0aab499d185b5e275082d6234556bdde4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 18:50:50 +0200 Subject: [PATCH 0119/1812] Moon rendering --- apps/openmw/engine.cpp | 6 - apps/openmw/mwrender/sky.cpp | 363 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 13 +- apps/openmw/mwworld/weather.cpp | 25 ++- 4 files changed, 342 insertions(+), 65 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59504048ae..f6f2ba9bb7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -494,11 +492,7 @@ void OMW::Engine::go() mViewer.addEventHandler(new osgViewer::StatsHandler); osg::Timer timer; - //osgUtil::IncrementalCompileOperation* ico = new osgUtil::IncrementalCompileOperation; - //ico->compileAllForNextFrame(1); - //mViewer.setRealizeOperation(ico); mViewer.realize(); - std::cout << "realize took " << timer.time_m() << std::endl; osg::Timer frameTimer; while (!mViewer.done()) { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4fd171727..1ac7ca10be 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -12,6 +12,9 @@ #include +#include +#include + #include #include @@ -57,7 +60,7 @@ namespace return mat; } - osg::ref_ptr createTexturedQuad() + osg::ref_ptr createTexturedQuad(int numUvSets=1) { osg::ref_ptr geom = new osg::Geometry; @@ -75,7 +78,8 @@ namespace texcoords->push_back(osg::Vec2f(1, 1)); texcoords->push_back(osg::Vec2f(1, 0)); - geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + for (int i=0; isetTexCoordArray(i, texcoords, osg::Array::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); @@ -111,6 +115,52 @@ private: osg::Vec4f mEmissionColor; }; +class CloudUpdater : public SceneUtil::StateSetUpdater +{ +public: + void setAnimationTimer(float timer); + + void setTexture(osg::ref_ptr texture) + { + mTexture = texture; + } + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } + void setOpacity(float opacity) + { + mOpacity = opacity; + } + +protected: + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, new osg::TexMat, osg::StateAttribute::ON); + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + mAnimationTimer = nv->getFrameStamp()->getSimulationTime()*0.05; + osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); + texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(mAnimationTimer, mAnimationTimer, 0.f))); + + stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + + // FIXME: handle opacity, will have to resort to either shaders or multitexturing? diffuse alpha is in use by the vertex colors already + } + +private: + float mAnimationTimer; + osg::ref_ptr mTexture; + osg::Vec4f mEmissionColor; + float mOpacity; +}; + /// Transform that removes the eyepoint of the modelview matrix, /// i.e. its children are positioned relative to the camera. class CameraRelativeTransform : public osg::Transform @@ -118,6 +168,10 @@ class CameraRelativeTransform : public osg::Transform public: CameraRelativeTransform() { + // Culling works in node-local space, not in camera space, so we can't cull this node correctly + // That's not a problem though, children of this node can be culled just fine + // Just make sure you do not place a CameraRelativeTransform deep in the scene graph + setCullingActive(false); } CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) @@ -211,6 +265,219 @@ private: int mMeshType; }; +class CelestialBody +{ +public: + CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) + : mSceneManager(sceneManager) + { + mGeode = new osg::Geode; + osg::ref_ptr geom = createTexturedQuad(numUvSets); + mGeode->addDrawable(geom); + mTransform = new osg::PositionAttitudeTransform; + mTransform->setScale(osg::Vec3f(450,450,450) * scaleFactor); + mTransform->addChild(mGeode); + + parentNode->addChild(mTransform); + } + + void setDirection(const osg::Vec3f& direction) + { + mTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mTransform->setAttitude(quat); + } + + void setVisible(bool visible) + { + mTransform->setNodeMask(visible ? ~0 : 0); + } + +protected: + osg::ref_ptr mTransform; + osg::ref_ptr mGeode; + Resource::SceneManager* mSceneManager; + +}; + +class Sun : public CelestialBody +{ +public: + Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : CelestialBody(parentNode, sceneManager, 1.f, 1) + { + osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + + mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + } +}; + +class Moon : public CelestialBody +{ +public: + enum Type + { + Type_Masser = 0, + Type_Secunda + }; + + Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) + : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + , mPhase(Phase_Unspecified) + , mType(type) + { + mUpdater = new MoonUpdater; + mGeode->addUpdateCallback(mUpdater); + + setPhase(Phase_WaxingCrescent); + } + + enum Phase + { + Phase_New = 0, + Phase_WaxingCrescent, + Phase_WaxingHalf, + Phase_WaxingGibbous, + Phase_Full, + Phase_WaningGibbous, + Phase_WaningHalf, + Phase_WaningCrescent, + Phase_Unspecified + }; + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + osg::ref_ptr stateset = new osg::StateSet; + + osg::ref_ptr moonTex = mSceneManager->getTextureManager()->getTexture2D(circleTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + // stage 0: render the moon circle in atmosphere color + stateset->setTextureAttributeAndModes(0, moonTex, osg::StateAttribute::ON); + + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + // stage 1: render the "lit" side of the moon blended over the circle + osg::ref_ptr moonTex2 = mSceneManager->getTextureManager()->getTexture2D(phaseTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(1, moonTex2, osg::StateAttribute::ON); + + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + texEnv2->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + mTransform->setStateSet(stateset); + } + + void setPhase(const Phase& phase) + { + if (mPhase == phase) + return; + mPhase = phase; + + std::string textureName = "textures/tx_"; + + if (mType == Moon::Type_Secunda) textureName += "secunda_"; + else textureName += "masser_"; + + if (phase == Moon::Phase_New) textureName += "new"; + else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; + else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; + else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == Moon::Phase_Full) textureName += "full"; + + textureName += ".dds"; + + if (mType == Moon::Type_Secunda) + setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + else + setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + } + + void setType(const Type& type) + { + mType = type; + } + + class MoonUpdater : public SceneUtil::StateSetUpdater + { + public: + MoonUpdater() + : mAlpha(1.f) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, mAlpha)); + } + + void setAlpha(float alpha) + { + mAlpha = alpha; + } + + private: + float mAlpha; + }; + + void setAlpha(float alpha) + { + mUpdater->setAlpha(alpha); + } + + void setAtmosphereColor(const osg::Vec4f& color) + { + // TODO + } + + void setColor(const osg::Vec4f& color) + { + // TODO + } + + unsigned int getPhaseInt() const + { + if (mPhase == Moon::Phase_New) return 0; + else if (mPhase == Moon::Phase_WaxingCrescent) return 1; + else if (mPhase == Moon::Phase_WaningCrescent) return 1; + else if (mPhase == Moon::Phase_WaxingHalf) return 2; + else if (mPhase == Moon::Phase_WaningHalf) return 2; + else if (mPhase == Moon::Phase_WaxingGibbous) return 3; + else if (mPhase == Moon::Phase_WaningGibbous) return 3; + else if (mPhase == Moon::Phase_Full) return 4; + return 0; + } + +private: + Type mType; + Phase mPhase; + osg::ref_ptr mUpdater; +}; + SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) , mHour(0.0f) @@ -240,7 +507,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mIsStorm(false) { osg::ref_ptr skyroot (new CameraRelativeTransform); - skyroot->setCullingActive(false); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -257,8 +523,6 @@ void SkyManager::create() ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); - // osg::Node* alphaBlendedRoot = - mAtmosphereUpdater = new AtmosphereUpdater; mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); @@ -271,27 +535,23 @@ void SkyManager::create() mAtmosphereNight->accept(modStars); mAtmosphereNight->setNodeMask(0); - osg::Geode* geode = new osg::Geode; - osg::ref_ptr sun = createTexturedQuad(); - geode->addDrawable(sun); - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - trans->setScale(osg::Vec3f(450,450,450)); - trans->addChild(geode); - mRootNode->addChild(trans); + mSun.reset(new Sun(mRootNode, mSceneManager)); - mSunTransform = trans; + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); ModVertexAlphaVisitor modClouds(1); mCloudNode->accept(modClouds); - osg::ref_ptr sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP); - trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + mCloudUpdater = new CloudUpdater; + //mCloudNode->addUpdateCallback(mCloudUpdater); mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mCloudNode->setNodeMask(0); + osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -307,16 +567,15 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { - return 0; if (!mCreated) return 0; + return 0; //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { - return 0; if (!mCreated) return 0; - //return mSecunda->getPhaseInt(); + return mSecunda->getPhaseInt(); } void SkyManager::clearRain() @@ -376,9 +635,9 @@ void SkyManager::update(float duration) } //mSunGlare->setVisible(mSunEnabled); - //mSun->setVisible(mSunEnabled); - //mMasser->setVisible(mMasserEnabled); - //mSecunda->setVisible(mSecundaEnabled); + mSun->setVisible(mSunEnabled); + mMasser->setVisible(mMasserEnabled); + mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); @@ -441,6 +700,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mClouds != weather.mCloudTexture) { mClouds = weather.mCloudTexture; + + std::string texture = Misc::ResourceHelpers::correctTexturePath(mClouds, mSceneManager->getVFS()); + + mCloudUpdater->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, + osg::Texture::REPEAT, osg::Texture::REPEAT)); } if (mNextClouds != weather.mNextCloudTexture) @@ -456,15 +720,18 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; + + mCloudUpdater->setOpacity(0.3); } if (mCloudColour != weather.mSunColor) { - /* + // FIXME: this doesn't look correct osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); - */ + + mCloudUpdater->setEmissionColor(clr); mCloudColour = weather.mSunColor; } @@ -494,7 +761,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } } - mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + //mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); /* @@ -524,12 +791,16 @@ void SkyManager::setGlare(const float glare) void SkyManager::sunEnable() { - mSunEnabled = true; + if (!mCreated) return; + + mSun->setVisible(true); } void SkyManager::sunDisable() { - mSunEnabled = false; + if (!mCreated) return; + + mSun->setVisible(false); } void SkyManager::setStormDirection(const Ogre::Vector3 &direction) @@ -541,45 +812,51 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSunTransform->setPosition(direction*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), direction); - mSunTransform->setAttitude(quat); + mSun->setDirection(direction); //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Ogre::Vector3& direction) +void SkyManager::setMasserDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mMasser->setPosition(direction); + + mMasser->setDirection(direction); } -void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) +void SkyManager::setSecundaDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mSecunda->setPosition(direction); + + mSecunda->setDirection(direction); } void SkyManager::masserEnable() { - mMasserEnabled = true; + if (!mCreated) return; + + mMasser->setVisible(true); } void SkyManager::secundaEnable() { - mSecundaEnabled = true; + if (!mCreated) return; + + mSecunda->setVisible(true); } void SkyManager::masserDisable() { - mMasserEnabled = false; + if (!mCreated) return; + + mMasser->setVisible(false); } void SkyManager::secundaDisable() { - mSecundaEnabled = false; + if (!mCreated) return; + + mSecunda->setVisible(false); } void SkyManager::setLightningStrength(const float factor) @@ -599,13 +876,13 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - //mMasser->setVisibility(fade); + mMasser->setAlpha(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - //mSecunda->setVisibility(fade); + mSecunda->setAlpha(fade); } void SkyManager::setHour(double hour) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index c8403af71e..ebf3ee87fc 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -20,6 +20,9 @@ namespace Resource namespace MWRender { class AtmosphereUpdater; + class CloudUpdater; + class Sun; + class Moon; class SkyManager { @@ -60,9 +63,9 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const Ogre::Vector3& direction); + void setMasserDirection(const osg::Vec3f& direction); - void setSecundaDirection(const Ogre::Vector3& direction); + void setSecundaDirection(const osg::Vec3f& direction); void setMasserFade(const float fade); @@ -94,13 +97,17 @@ namespace MWRender osg::ref_ptr mCloudNode; + osg::ref_ptr mCloudUpdater; + osg::ref_ptr mAtmosphereDay; osg::ref_ptr mAtmosphereNight; osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSunTransform; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; bool mCreated; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index fe4f62953b..90aedda1cb 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -426,10 +426,10 @@ void WeatherManager::update(float duration, bool paused) mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - //if (mHour >= mNightStart || mHour <= mSunriseTime) - //mRendering->getSkyManager()->sunDisable(); - //else - //mRendering->getSkyManager()->sunEnable(); + if (mHour >= mNightStart || mHour <= mSunriseTime) + mRendering->getSkyManager()->sunDisable(); + else + mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -493,10 +493,10 @@ void WeatherManager::update(float duration, bool paused) (1 - moonHeight) * facing * 0.8f, moonHeight); - //mRendering->getSkyManager()->setMasserDirection(masser); - //mRendering->getSkyManager()->setSecundaDirection(secunda); - //mRendering->getSkyManager()->masserEnable(); - //mRendering->getSkyManager()->secundaEnable(); + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -507,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - //mRendering->getSkyManager()->setMasserFade(masserAngleFade); - //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - //mRendering->getSkyManager()->masserDisable(); - //mRendering->getSkyManager()->secundaDisable(); + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -568,7 +568,6 @@ void WeatherManager::update(float duration, bool paused) mRendering->setAmbientColour(mResult.mAmbientColor); - //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult); From 5b8c28f641973c40392e08125a29d5ff2d785daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:11:38 +0200 Subject: [PATCH 0120/1812] NpcAnimation compiles --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 159 ++++++++--------------- apps/openmw/mwrender/npcanimation.hpp | 49 ++++--- apps/openmw/mwrender/objects.cpp | 4 + apps/openmw/mwrender/weaponanimation.hpp | 18 ++- 7 files changed, 104 insertions(+), 136 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e7ed2d921f..91b1ab1c5d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky -# debugging camera npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation sky npcanimation +# debugging camera creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85d9546aa4..4352520db6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,9 +10,9 @@ namespace MWRender { - Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem) + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mPtr(ptr) - , mInsert(node) + , mInsert(parentNode) , mResourceSystem(resourceSystem) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 754adec926..34173c29cd 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -174,7 +174,7 @@ protected: public: - Animation(const MWWorld::Ptr &ptr, osg::ref_ptr node, Resource::ResourceSystem* resourceSystem); + Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); osg::Group* getOrCreateObjectRoot(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a724644a70..fe16fa06e0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -10,12 +10,14 @@ #include #include -#include - #include #include +#include +#include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -69,27 +71,13 @@ std::string getVampireHead(const std::string& race, bool female) return "meshes\\" + bodyPart->mModel; } -bool isSkinned (NifOgre::ObjectScenePtr scene) -{ - if (scene->mSkelBase == NULL) - return false; - for(size_t j = 0; j < scene->mEntities.size(); j++) - { - Ogre::Entity *ent = scene->mEntities[j]; - if(scene->mSkelBase != ent && ent->hasSkeleton()) - { - return true; - } - } - return false; -} - } namespace MWRender { +/* HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mValue(0), mEnabled(true) { @@ -159,6 +147,7 @@ void HeadAnimationTime::setBlinkStop(float value) { mBlinkStop = value; } +*/ static NpcAnimation::PartBoneMap createPartListMap() { @@ -201,8 +190,8 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) - : Animation(ptr, node), +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) + : Animation(ptr, parentNode, resourceSystem), mVisibilityFlags(visibilityFlags), mListenerDisabled(disableListener), mViewMode(viewMode), @@ -217,8 +206,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v { mNpc = mPtr.get()->mBase; - mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); - mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + //mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); + //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) { @@ -251,7 +240,7 @@ void NpcAnimation::rebuild() void NpcAnimation::updateNpcBase() { - clearAnimSources(); + //clearAnimSources(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); @@ -296,9 +285,10 @@ void NpcAnimation::updateNpcBase() (!isWerewolf ? !isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); - smodel = Misc::ResourceHelpers::correctActorModelPath(smodel); - setObjectRoot(smodel, true); + smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); + setObjectRoot(smodel /*, baseonly = true*/); + /* if(mViewMode != VM_FirstPerson) { addAnimSource(smodel); @@ -318,9 +308,8 @@ void NpcAnimation::updateNpcBase() addAnimSource(smodel); else { - /* A bit counter-intuitive, but unlike third-person anims, it seems - * beast races get both base_anim.1st.nif and base_animkna.1st.nif. - */ + // A bit counter-intuitive, but unlike third-person anims, it seems + // beast races get both base_anim.1st.nif and base_animkna.1st.nif. addAnimSource("meshes\\xbase_anim.1st.nif"); if(isBeast) addAnimSource("meshes\\xbase_animkna.1st.nif"); @@ -328,18 +317,19 @@ void NpcAnimation::updateNpcBase() addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } + */ for(size_t i = 0;i < ESM::PRT_Count;i++) removeIndividualPart((ESM::PartReferenceType)i); updateParts(); - mWeaponAnimationTime->updateStartTime(); + //mWeaponAnimationTime->updateStartTime(); } void NpcAnimation::updateParts() { - if (!mSkelBase) - return; + //if (!mSkelBase) + // return; mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -379,7 +369,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get() != NULL); + bool wasArrowAttached = 0;//(mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) @@ -396,7 +386,8 @@ void NpcAnimation::updateParts() int prio = 1; bool enchantedGlow = !store->getClass().getEnchantment(*store).empty(); - Ogre::Vector3 glowColor = getEnchantmentColor(*store); + //Ogre::Vector3 glowColor = getEnchantmentColor(*store); + Ogre::Vector3 glowColor (1,1,1); if(store->getTypeName() == typeid(ESM::Clothing).name()) { prio = ((slotlist[i].mBasePriority+1)<<1) + 0; @@ -448,7 +439,7 @@ void NpcAnimation::updateParts() const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); + //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); } } @@ -597,6 +588,15 @@ public: } }; +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) +{ + osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); +std::cout << "inserting " << model << std::endl; + osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + return PartHolderPtr(new PartHolder(attached)); +} + +/* NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) { NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, bonefilter, mInsert, model); @@ -624,7 +624,9 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model return objects; } +*/ +/* Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { Ogre::Vector3 ret = Animation::runAnimation(timepassed); @@ -675,13 +677,14 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } +*/ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; mPartslots[type] = -1; - mObjectParts[type].setNull(); + //mObjectParts[type].setNull(); if (!mSoundIds[type].empty() && !mSoundsDisabled) { MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]); @@ -743,6 +746,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } + /* if(mObjectParts[type]->mSkelBase) { Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton(); @@ -795,6 +799,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g ctrl->setSource(mWeaponAnimationTime); } } + */ return true; } @@ -856,7 +861,7 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon != inv.end()) { - Ogre::Vector3 glowColor = getEnchantmentColor(*weapon); + Ogre::Vector3 glowColor (1,1,1); //= getEnchantmentColor(*weapon); std::string mesh = weapon->getClass().getModel(*weapon); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); @@ -868,11 +873,11 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); } - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); } } else @@ -889,29 +894,19 @@ void NpcAnimation::showCarriedLeft(bool show) MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(show && iter != inv.end()) { - Ogre::Vector3 glowColor = getEnchantmentColor(*iter); + Ogre::Vector3 glowColor(1,1,1);// = getEnchantmentColor(*iter); std::string mesh = iter->getClass().getModel(*iter); if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { - if (iter->getTypeName() == typeid(ESM::Light).name()) - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + //if (iter->getTypeName() == typeid(ESM::Light).name()) + //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); } } else removeIndividualPart(ESM::PRT_Shield); } -void NpcAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) -{ - Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - setRenderProperties(object, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, - !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); - - std::for_each(object->mEntities.begin(), object->mEntities.end(), SetObjectGroup(slot)); - std::for_each(object->mParticles.begin(), object->mParticles.end(), SetObjectGroup(slot)); -} - void NpcAnimation::attachArrow() { WeaponAnimation::attachArrow(mPtr); @@ -942,11 +937,13 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { + /* const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + */ } } @@ -956,67 +953,17 @@ void NpcAnimation::setAlpha(float alpha) return; mAlpha = alpha; - for (int i=0; imEntities.size(); ++j) - { - Ogre::Entity* ent = mObjectParts[i]->mEntities[j]; - if (ent != mObjectParts[i]->mSkelBase) - applyAlpha(alpha, ent, mObjectParts[i]); - } - } + // TODO } void NpcAnimation::enableHeadAnimation(bool enable) { - mHeadAnimationTime->setEnabled(enable); + //mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::preRender(Ogre::Camera *camera) +void NpcAnimation::setWeaponGroup(const std::string &group) { - Animation::preRender(camera); - for (int i=0; irotateBillboardNodes(camera); - } -} - -void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectScenePtr scene) -{ - sh::Factory::getInstance()._ensureMaterial(ent->getSubEntity(0)->getMaterial()->getName(), "Default"); - ent->getSubEntity(0)->setRenderQueueGroup(alpha != 1.f || ent->getSubEntity(0)->getMaterial()->isTransparent() - ? RQG_Alpha : RQG_Main); - - - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(ent); - if (mAlpha == 1.f) - { - // Don't bother remembering what the original values were. Just remove the techniques and let the factory restore them. - mat->removeAllTechniques(); - sh::Factory::getInstance()._ensureMaterial(mat->getName(), "Default"); - return; - } - - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) - { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) - { - Ogre::Pass *pass = passes.getNext(); - pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); - pass->setVertexColourTracking(pass->getVertexColourTracking() &~Ogre::TVC_DIFFUSE); - } - } + //mWeaponAnimationTime-> } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 90b1c269bf..28ac6509b8 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,6 +15,7 @@ namespace ESM namespace MWRender { +/* class HeadAnimationTime : public Ogre::ControllerValue { private: @@ -47,6 +48,27 @@ public: virtual void setValue(Ogre::Real value) { } }; +*/ + +/// @brief Detaches the node from its parent when the object goes out of scope. +class PartHolder +{ +public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + +private: + osg::ref_ptr mNode; +}; +typedef boost::shared_ptr PartHolderPtr; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -69,7 +91,7 @@ private: bool mListenerDisabled; // Bounded Parts - NifOgre::ObjectScenePtr mObjectParts[ESM::PRT_Count]; + PartHolderPtr mObjectParts[ESM::PRT_Count]; std::string mSoundIds[ESM::PRT_Count]; const ESM::NPC *mNpc; @@ -94,8 +116,8 @@ private: Ogre::Vector3 mFirstPersonOffset; - Ogre::SharedPtr mHeadAnimationTime; - Ogre::SharedPtr mWeaponAnimationTime; + //Ogre::SharedPtr mHeadAnimationTime; + //Ogre::SharedPtr mWeaponAnimationTime; float mAlpha; bool mSoundsDisabled; @@ -105,9 +127,8 @@ private: void updateNpcBase(); - NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, - const std::string &bonefilter, - bool enchantedGlow, Ogre::Vector3* glowColor=NULL); + PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, + const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); @@ -118,7 +139,7 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); - void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); + //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); public: /** @@ -132,15 +153,16 @@ public: * @param disableSounds Same as \a disableListener but for playing items sounds * @param viewMode */ - NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener = false, + NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + int visibilityFlags, bool disableListener = false, bool disableSounds = false, ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); virtual void enableHeadAnimation(bool enable); - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void setWeaponGroup(const std::string& group); - virtual Ogre::Vector3 runAnimation(float timepassed); + //virtual Ogre::Vector3 runAnimation(float timepassed); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. @@ -158,9 +180,9 @@ public: virtual void releaseArrow(); // WeaponAnimation - virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } + //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); void setViewMode(ViewMode viewMode); @@ -178,9 +200,6 @@ public: virtual void setAlpha(float alpha); virtual void setVampire(bool vampire); - - /// Prepare this animation for being rendered with \a camera (rotates billboard nodes) - virtual void preRender (Ogre::Camera* camera); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 25d57aba08..322d02e94c 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -25,6 +25,7 @@ #include "renderconst.hpp" #include "animation.hpp" +#include "npcanimation.hpp" namespace { @@ -199,7 +200,10 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b void Objects::insertNPC(const MWWorld::Ptr &ptr) { + insertBegin(ptr); + std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + mObjects.insert(std::make_pair(ptr, anim.release())); } bool Objects::deleteObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index e1ccd94656..4009628566 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -1,10 +1,6 @@ #ifndef OPENMW_MWRENDER_WEAPONANIMATION_H #define OPENMW_MWRENDER_WEAPONANIMATION_H -#include - -#include - #include "../mwworld/ptr.hpp" namespace MWRender @@ -12,6 +8,7 @@ namespace MWRender class Animation; + /* class WeaponAnimationTime : public Ogre::ControllerValue { private: @@ -27,6 +24,7 @@ namespace MWRender virtual void setValue(Ogre::Real value) { } }; + */ /// Handles attach & release of projectiles for ranged weapons class WeaponAnimation @@ -36,23 +34,23 @@ namespace MWRender virtual ~WeaponAnimation() {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void attachArrow(MWWorld::Ptr actor); + void attachArrow(MWWorld::Ptr actor) {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor); + void releaseArrow(MWWorld::Ptr actor) {} protected: - NifOgre::ObjectScenePtr mAmmunition; + //NifOgre::ObjectScenePtr mAmmunition; - virtual NifOgre::ObjectScenePtr getWeapon() = 0; + //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character, for ranged weapon aiming. float mPitchFactor; - void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); + //void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); }; } From c334a76a6f41f33ee6544cf6ccdbffde8844f898 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:38:43 +0200 Subject: [PATCH 0121/1812] Fix skinning bug --- apps/openmw/mwrender/sky.cpp | 7 ++----- components/nifosg/nifloader.cpp | 21 ++++++--------------- components/sceneutil/attach.cpp | 1 + 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1ac7ca10be..f843f9a43f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -546,12 +546,10 @@ void SkyManager::create() mCloudNode->accept(modClouds); mCloudUpdater = new CloudUpdater; - //mCloudNode->addUpdateCallback(mCloudUpdater); + mCloudNode->addUpdateCallback(mCloudUpdater); mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - mCloudNode->setNodeMask(0); - osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -568,8 +566,7 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { if (!mCreated) return 0; - return 0; - //return mMasser->getPhaseInt(); + return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b61e3824b8..1f0c368390 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -222,21 +222,12 @@ namespace // Callback method called by the NodeVisitor when visiting a node. void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osgAnimation::Bone* b = dynamic_cast(node); - if (!b) - { - OSG_WARN << "Warning: UpdateBone set on non-Bone object." << std::endl; - return; - } - - osgAnimation::Bone* parent = b->getBoneParent(); - if (parent) - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); - else - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); - } + osgAnimation::Bone* b = static_cast(node); + osgAnimation::Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); traverse(node,nv); } }; diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 47efe986c3..e06155a614 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -96,6 +96,7 @@ namespace SceneUtil bone->addUpdateCallback(old); } } + traverse(node); } private: From 57fd18b161c4a7298aeb4c768ecbcda9a4320bf0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 22:43:53 +0200 Subject: [PATCH 0122/1812] Fix frontface bug --- components/sceneutil/attach.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index e06155a614..882bd66ece 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -172,7 +172,7 @@ namespace SceneUtil // However MW isn't doing this either, so don't. Assuming all meshes are using backface culling is more efficient. osg::FrontFace* frontFace = new osg::FrontFace; frontFace->setMode(osg::FrontFace::CLOCKWISE); - toAttach->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + trans->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); find.mFoundNode->addChild(trans); trans->addChild(toAttach); From 8f6d4fb3e0ce53786a8aad5eb75a94d831f45f15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Apr 2015 01:26:58 +0200 Subject: [PATCH 0123/1812] Fix filtering bug --- components/sceneutil/attach.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 882bd66ece..f084704c38 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "visitor.hpp" namespace SceneUtil @@ -110,13 +112,14 @@ namespace SceneUtil public: FilterVisitor(const std::string& filter) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFilter(filter) + , mFilter(Misc::StringUtils::lowerCase(filter)) { } virtual void apply(osg::Geode &node) { - if (node.getName().find(mFilter) == std::string::npos) + std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + if (lowerName.find(mFilter) == std::string::npos) { mToRemove.push_back(&node); } @@ -133,7 +136,7 @@ namespace SceneUtil private: std::vector mToRemove; - const std::string& mFilter; + std::string mFilter; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) From 083c41c9503ecf4d75e0a3fd2b02c483c29a4bae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Apr 2015 01:23:37 +0200 Subject: [PATCH 0124/1812] Environment map for enchanted objects --- apps/openmw/engine.cpp | 1 - apps/openmw/mwrender/animation.cpp | 98 +++++++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 ++ apps/openmw/mwrender/npcanimation.cpp | 52 +++----------- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/objects.cpp | 4 +- components/resource/resourcesystem.cpp | 5 ++ components/resource/resourcesystem.hpp | 1 + 8 files changed, 123 insertions(+), 48 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f6f2ba9bb7..9a7f023e67 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -491,7 +491,6 @@ void OMW::Engine::go() mViewer.setCameraManipulator(new osgGA::TrackballManipulator); mViewer.addEventHandler(new osgViewer::StatsHandler); - osg::Timer timer; mViewer.realize(); osg::Timer frameTimer; while (!mViewer.done()) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4352520db6..3aeaa2ed1d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,11 +1,68 @@ #include "animation.hpp" +#include +#include +#include + #include #include #include +#include -#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" + +namespace +{ + + class GlowUpdater : public SceneUtil::StateSetUpdater + { + public: + GlowUpdater(osg::Vec4f color, const std::vector >& textures) + : mTexUnit(1) // FIXME: might not always be 1 + , mColor(color) + , mTextures(textures) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); + + osg::TexGen* texGen = new osg::TexGen; + texGen->setMode(osg::TexGen::SPHERE_MAP); + + stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(mColor); + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); + + stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + float time = nv->getFrameStamp()->getSimulationTime(); + int index = (int)(time*16) % mTextures.size(); + stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + private: + int mTexUnit; + osg::Vec4f mColor; + std::vector > mTextures; + }; + +} namespace MWRender { @@ -54,6 +111,42 @@ namespace MWRender return static_cast(mObjectRoot.get()); } + void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor) + { + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::stringstream stream; + stream << "textures/magicitem/caust"; + stream << std::setw(2); + stream << std::setfill('0'); + stream << i; + stream << ".dds"; + + textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT)); + } + + osg::ref_ptr glowupdater (new GlowUpdater(glowColor, textures)); + node->addUpdateCallback(glowupdater); + } + + // TODO: Should not be here + osg::Vec4f Animation::getEnchantmentColor(MWWorld::Ptr item) + { + osg::Vec4f result(1,1,1,1); + std::string enchantmentName = item.getClass().getEnchantment(item); + if (enchantmentName.empty()) + return result; + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); + assert (enchantment->mEffects.mList.size()); + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + enchantment->mEffects.mList.front().mEffectID); + result.x() = magicEffect->mData.mRed / 255.f; + result.y() = magicEffect->mData.mGreen / 255.f; + result.z() = magicEffect->mData.mBlue / 255.f; + return result; + } + // -------------------------------------------------------------------------------- ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) @@ -62,6 +155,9 @@ namespace MWRender if (!model.empty()) { setObjectRoot(model); + + if (!ptr.getClass().getEnchantment(ptr).empty()) + addGlow(mObjectRoot, getEnchantmentColor(ptr)); } else { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 34173c29cd..1feab7bf3a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -172,6 +172,10 @@ protected: //void clearAnimSources(); + osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); + + void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); + public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fe16fa06e0..e30c701fcf 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -328,8 +328,8 @@ void NpcAnimation::updateNpcBase() void NpcAnimation::updateParts() { - //if (!mSkelBase) - // return; + if (!mObjectRoot.get()) + return; mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -386,8 +386,7 @@ void NpcAnimation::updateParts() int prio = 1; bool enchantedGlow = !store->getClass().getEnchantment(*store).empty(); - //Ogre::Vector3 glowColor = getEnchantmentColor(*store); - Ogre::Vector3 glowColor (1,1,1); + osg::Vec4f glowColor = getEnchantmentColor(*store); if(store->getTypeName() == typeid(ESM::Clothing).name()) { prio = ((slotlist[i].mBasePriority+1)<<1) + 0; @@ -588,44 +587,15 @@ public: } }; -PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); -std::cout << "inserting " << model << std::endl; osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + if (enchantedGlow) + addGlow(attached, *glowColor); return PartHolderPtr(new PartHolder(attached)); } -/* -NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor) -{ - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mSkelBase, bonename, bonefilter, mInsert, model); - setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0, - enchantedGlow, glowColor); - - std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group)); - std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group)); - - if(objects->mSkelBase) - { - Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - Ogre::SkeletonInstance *skelinst = objects->mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } - - return objects; -} -*/ - /* Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { @@ -684,7 +654,7 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) mPartPriorities[type] = 0; mPartslots[type] = -1; - //mObjectParts[type].setNull(); + mObjectParts[type].reset(); if (!mSoundIds[type].empty() && !mSoundsDisabled) { MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mSoundIds[type]); @@ -711,7 +681,7 @@ void NpcAnimation::removePartGroup(int group) } } -bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, bool enchantedGlow, Ogre::Vector3* glowColor) +bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, bool enchantedGlow, osg::Vec4f* glowColor) { if(priority <= mPartPriorities[type]) return false; @@ -804,7 +774,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g return true; } -void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow, Ogre::Vector3* glowColor) +void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow, osg::Vec4f* glowColor) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::Store &partStore = store.get(); @@ -861,7 +831,7 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon != inv.end()) { - Ogre::Vector3 glowColor (1,1,1); //= getEnchantmentColor(*weapon); + osg::Vec4f glowColor = getEnchantmentColor(*weapon); std::string mesh = weapon->getClass().getModel(*weapon); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); @@ -894,7 +864,7 @@ void NpcAnimation::showCarriedLeft(bool show) MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(show && iter != inv.end()) { - Ogre::Vector3 glowColor(1,1,1);// = getEnchantmentColor(*iter); + osg::Vec4f glowColor = getEnchantmentColor(*iter); std::string mesh = iter->getClass().getModel(*iter); if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 28ac6509b8..2605d58e3b 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -128,16 +128,16 @@ private: void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, - const std::string &bonefilter, bool enchantedGlow, Ogre::Vector3* glowColor=NULL); + const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); void removePartGroup(int group); void addPartGroup(int group, int priority, const std::vector &parts, - bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 322d02e94c..21d7c1ab59 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -166,10 +166,10 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool osg::Light* light = new osg::Light; lightSource->setLight(light); - float realRadius = esmLight->mData.mRadius * 2; + float realRadius = esmLight->mData.mRadius; lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/realRadius); + light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); //light->setLinearAttenuation(0.05); light->setConstantAttenuation(0.f); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 215b1a67c8..acde8f5d2d 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -18,6 +18,11 @@ namespace Resource return mSceneManager.get(); } + TextureManager* ResourceSystem::getTextureManager() + { + return mTextureManager.get(); + } + const VFS::Manager* ResourceSystem::getVFS() const { return mVFS; diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index a91f3cab3d..3bb4547854 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -23,6 +23,7 @@ namespace Resource ResourceSystem(const VFS::Manager* vfs); SceneManager* getSceneManager(); + TextureManager* getTextureManager(); const VFS::Manager* getVFS() const; From edc5cad79ebc7222ca2d32bca939f216fad5fe28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 01:57:52 +0200 Subject: [PATCH 0125/1812] Port Animation::addEffect --- apps/nifosgtest/test.cpp | 5 + apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 163 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 62 ++++++-- apps/openmw/mwrender/npcanimation.cpp | 5 +- apps/openmw/mwrender/npcanimation.hpp | 20 --- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 + apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/vismask.hpp | 17 +++ apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- components/nifosg/controller.cpp | 5 + components/nifosg/controller.hpp | 2 + components/sceneutil/controller.cpp | 32 +++-- components/sceneutil/controller.hpp | 23 ++- 17 files changed, 294 insertions(+), 61 deletions(-) create mode 100644 apps/openmw/mwrender/vismask.hpp diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 487a91890e..6d05867755 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -129,6 +131,9 @@ int main(int argc, char** argv) Resource::TextureManager texMgr(&resourceMgr); newNode->addChild(loader.load(nif, &texMgr)); + SceneUtil::AssignControllerSourcesVisitor visitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + newNode->accept(visitor); + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; root->addChild(trans); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 91b1ab1c5d..03a4181b59 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky npcanimation + actors objects renderingmanager animation sky npcanimation vismask # debugging camera creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3aeaa2ed1d..2febf9c9a7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,13 +10,18 @@ #include #include +#include + #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "vismask.hpp" + namespace { @@ -62,6 +67,30 @@ namespace std::vector > mTextures; }; + class FindMaxControllerLengthVisitor : public SceneUtil::ControllerVisitor + { + public: + FindMaxControllerLengthVisitor() + : SceneUtil::ControllerVisitor() + , mMaxLength(0) + { + } + + virtual void visit(osg::Node& , SceneUtil::Controller& ctrl) + { + if (ctrl.mFunction) + mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + } + + float getMaxLength() const + { + return mMaxLength; + } + + private: + float mMaxLength; + }; + } namespace MWRender @@ -83,6 +112,8 @@ namespace MWRender osg::Vec3f Animation::runAnimation(float duration) { + updateEffects(duration); + return osg::Vec3f(); } @@ -147,6 +178,133 @@ namespace MWRender return result; } + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) + { + // Early out if we already have this effect + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) + return; + + EffectParams params; + params.mModelName = model; + osg::ref_ptr parentNode; + if (bonename.empty()) + parentNode = mObjectRoot->asGroup(); + else + { + SceneUtil::FindByNameVisitor visitor(bonename); + mObjectRoot->accept(visitor); + if (!visitor.mFoundNode) + throw std::runtime_error("Can't find bone " + bonename); + parentNode = visitor.mFoundNode; + } + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); + params.mObjects = PartHolderPtr(new PartHolder(node)); + + FindMaxControllerLengthVisitor findMaxLengthVisitor; + node->accept(findMaxLengthVisitor); + + params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); + + node->setNodeMask(Mask_Effect); + + params.mLoop = loop; + params.mEffectId = effectId; + params.mBoneName = bonename; + + params.mAnimTime = boost::shared_ptr(new EffectAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(params.mAnimTime)); + node->accept(assignVisitor); + + if (!texture.empty()) + { + std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, mResourceSystem->getVFS()); + // Not sure if wrap settings should be pulled from the overridden texture? + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, + osg::Texture2D::CLAMP); + osg::ref_ptr stateset; + if (node->getStateSet()) + stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); + else + stateset = new osg::StateSet; + + stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); + + node->setStateSet(stateset); + } + + // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. + + mEffects.push_back(params); + } + + void Animation::removeEffect(int effectId) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + if (it->mEffectId == effectId) + { + mEffects.erase(it); + return; + } + } + } + + void Animation::getLoopingEffects(std::vector &out) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + if (it->mLoop) + out.push_back(it->mEffectId); + } + } + + void Animation::updateEffects(float duration) + { + for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ) + { + it->mAnimTime->addTime(duration); + + if (it->mAnimTime->getTime() >= it->mMaxControllerLength) + { + if (it->mLoop) + { + // Start from the beginning again; carry over the remainder + // Not sure if this is actually needed, the controller function might already handle loops + float remainder = it->mAnimTime->getTime() - it->mMaxControllerLength; + it->mAnimTime->resetTime(remainder); + } + else + { + it = mEffects.erase(it); + continue; + } + } + ++it; + } + } + + float Animation::EffectAnimationTime::getValue(osg::NodeVisitor*) + { + return mTime; + } + + void Animation::EffectAnimationTime::addTime(float duration) + { + mTime += duration; + } + + void Animation::EffectAnimationTime::resetTime(float time) + { + mTime = time; + } + + float Animation::EffectAnimationTime::getTime() const + { + return mTime; + } + // -------------------------------------------------------------------------------- ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) @@ -159,11 +317,6 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - //mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1feab7bf3a..ccc4bfa23b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -61,17 +61,18 @@ protected: virtual void setValue(Ogre::Real value); }; - class EffectAnimationTime : public Ogre::ControllerValue + class EffectAnimationTime : public SceneUtil::ControllerSource { private: float mTime; public: - EffectAnimationTime() : mTime(0) { } - void addTime(float time) { mTime += time; } - void resetTime(float value) { mTime = value; } + virtual float getValue(osg::NodeVisitor* nv); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value); + void addTime(float duration); + void resetTime(float time); + float getTime() const; + + EffectAnimationTime() : mTime(0) { } }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -124,6 +125,44 @@ protected: Resource::ResourceSystem* mResourceSystem; + /// @brief Detaches the node from its parent when the object goes out of scope. + class PartHolder + { + public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + + osg::ref_ptr getNode() + { + return mNode; + } + + private: + osg::ref_ptr mNode; + }; + typedef boost::shared_ptr PartHolderPtr; + + struct EffectParams + { + std::string mModelName; // Just here so we don't add the same effect twice + PartHolderPtr mObjects; + boost::shared_ptr mAnimTime; + float mMaxControllerLength; + int mEffectId; + bool mLoop; + std::string mBoneName; + }; + + std::vector mEffects; + /* Sets the appropriate animations on the bone groups based on priority. */ //void resetActiveGroups(); @@ -192,12 +231,12 @@ public: * @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true, * you need to remove it manually using removeEffect when the effect should end. * @param bonename Bone to attach to, or empty string to use the scene node instead - * @param texture override the texture specified in the model's materials + * @param texture override the texture specified in the model's materials - if empty, do not override * @note Will not add an effect twice. */ - //void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); - //void removeEffect (int effectId); - //void getLoopingEffects (std::vector& out); + void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = ""); + void removeEffect (int effectId); + void getLoopingEffects (std::vector& out); //void updatePtr(const MWWorld::Ptr &ptr); @@ -273,6 +312,9 @@ public: //float getVelocity(const std::string &groupname) const; virtual osg::Vec3f runAnimation(float duration); + + /// This is typically called as part of runAnimation, but may be called manually if needed. + void updateEffects(float duration); }; class ObjectAnimation : public Animation { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e30c701fcf..c413d9334c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -587,12 +587,15 @@ public: } }; -PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); if (enchantedGlow) addGlow(attached, *glowColor); + + // TODO: set group userdata for inventory picking + return PartHolderPtr(new PartHolder(attached)); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 2605d58e3b..16bd45cc47 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -50,26 +50,6 @@ public: }; */ -/// @brief Detaches the node from its parent when the object goes out of scope. -class PartHolder -{ -public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } - - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } - -private: - osg::ref_ptr mNode; -}; -typedef boost::shared_ptr PartHolderPtr; - class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 21d7c1ab59..4564e3a972 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -246,7 +246,7 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::update(float dt, Ogre::Camera* camera) +void Objects::update(float dt) { PtrAnimationMap::const_iterator it = mObjects.begin(); for(;it != mObjects.end();++it) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 07328b9592..f4d5675aa1 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -49,7 +49,7 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - void update (float dt, Ogre::Camera* camera); + void update (float dt); ///< per-frame update //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ba34cf303b..26b86d1b26 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -160,4 +160,9 @@ namespace MWRender return mSky.get(); } + void RenderingManager::update(float dt, bool paused) + { + mObjects->update(dt); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1db0467efc..b7aec37866 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -63,6 +63,8 @@ namespace MWRender osg::Vec3f getEyePos(); + void update(float dt, bool paused); + private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp new file mode 100644 index 0000000000..4a064b60f3 --- /dev/null +++ b/apps/openmw/mwrender/vismask.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWRENDER_VISMASK_H +#define OPENMW_MWRENDER_VISMASK_H + +namespace MWRender +{ + + /// Node masks used for controlling visibility of game objects. + enum VisMask + { + Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors + + Mask_Effect = 0x2 + }; + +} + +#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1084ae03ac..c9fd84ee3b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -180,7 +180,7 @@ namespace MWWorld } } - //mRendering.update (duration, paused); + mRendering.update (duration, paused); } void Scene::unloadCell (CellStoreCollection::iterator iter) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 20298bd858..c6a1b5477c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1606,13 +1606,13 @@ namespace MWWorld goToJail(); updateWeather(duration, paused); - /* - if (!paused) - doPhysics (duration); + //if (!paused) + // doPhysics (duration); mWorldScene->update (duration, paused); + /* performUpdateSceneQueries (); updateWindowManager (); diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index ce004dc796..499a74d958 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -64,6 +64,11 @@ float ControllerFunction::calculate(float value) } } +float ControllerFunction::getMaximum() const +{ + return mStopTime; +} + KeyframeController::KeyframeController() { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 3136b31181..e480f4c13e 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -95,6 +95,8 @@ namespace NifOsg ControllerFunction(const Nif::Controller *ctrl); float calculate(float value); + + virtual float getMaximum() const; }; class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 565d486723..1f1b95ac81 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -32,31 +32,26 @@ namespace SceneUtil return nv->getFrameStamp()->getSimulationTime(); } - AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + ControllerVisitor::ControllerVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { + } - AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) - : mToAssign(toAssign) - , osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - void AssignControllerSourcesVisitor::apply(osg::Node &node) + void ControllerVisitor::apply(osg::Node &node) { osg::NodeCallback* callback = node.getUpdateCallback(); while (callback) { if (Controller* ctrl = dynamic_cast(callback)) - assign(node, *ctrl); + visit(node, *ctrl); if (CompositeStateSetUpdater* composite = dynamic_cast(callback)) { for (unsigned int i=0; igetNumControllers(); ++i) { StateSetUpdater* statesetcontroller = composite->getController(i); if (Controller* ctrl = dynamic_cast(statesetcontroller)) - assign(node, *ctrl); + visit(node, *ctrl); } } @@ -66,18 +61,29 @@ namespace SceneUtil traverse(node); } - void AssignControllerSourcesVisitor::apply(osg::Geode &geode) + void ControllerVisitor::apply(osg::Geode &geode) { for (unsigned int i=0; igetUpdateCallback(); if (Controller* ctrl = dynamic_cast(callback)) - assign(geode, *ctrl); + visit(geode, *ctrl); } } - void AssignControllerSourcesVisitor::assign(osg::Node&, Controller &ctrl) + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() + : ControllerVisitor() + { + } + + AssignControllerSourcesVisitor::AssignControllerSourcesVisitor(boost::shared_ptr toAssign) + : ControllerVisitor() + , mToAssign(toAssign) + { + } + + void AssignControllerSourcesVisitor::visit(osg::Node&, Controller &ctrl) { if (!ctrl.mSource.get()) ctrl.mSource = mToAssign; diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index de73c7e802..655e021641 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -25,6 +25,10 @@ namespace SceneUtil { public: virtual float calculate(float input) = 0; + + /// Get the "stop time" of the controller function, typically the maximum of the calculate() function. + /// May not be meaningful for all types of controller functions. + virtual float getMaximum() const = 0; }; class Controller @@ -42,18 +46,27 @@ namespace SceneUtil boost::shared_ptr mFunction; }; - class AssignControllerSourcesVisitor : public osg::NodeVisitor + /// Pure virtual base class - visit() all controllers that are attached as UpdateCallbacks in a scene graph. + class ControllerVisitor : public osg::NodeVisitor + { + public: + ControllerVisitor(); + + virtual void apply(osg::Node& node); + virtual void apply(osg::Geode& geode); + + virtual void visit(osg::Node& node, Controller& ctrl) = 0; + }; + + class AssignControllerSourcesVisitor : public ControllerVisitor { public: AssignControllerSourcesVisitor(); AssignControllerSourcesVisitor(boost::shared_ptr toAssign); - virtual void apply(osg::Node& node); - virtual void apply(osg::Geode& geode); - /// Assign the wanted ControllerSource. May be overriden in derived classes. /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. - virtual void assign(osg::Node& node, Controller& ctrl); + virtual void visit(osg::Node& node, Controller& ctrl); private: boost::shared_ptr mToAssign; From 27cfe8fb5892f7795fe0c78cb2200d6e98f16bdc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 02:39:10 +0200 Subject: [PATCH 0126/1812] Crash fix --- apps/openmw/mwworld/inventorystore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2de3abc750..e3254d30a9 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -587,10 +587,12 @@ void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) mListener->equipmentChanged(); // if player, update inventory window + /* if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } + */ } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) From 9c4b2ea61a5183902200e0de89c8dc4fe69dfff4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 03:05:47 +0200 Subject: [PATCH 0127/1812] CreatureAnimation compiles --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/engine.cpp | 13 +-- apps/openmw/mwrender/creatureanimation.cpp | 108 +++++++++++---------- apps/openmw/mwrender/creatureanimation.hpp | 26 ++--- apps/openmw/mwrender/npcanimation.cpp | 22 ----- apps/openmw/mwrender/objects.cpp | 9 +- 6 files changed, 80 insertions(+), 101 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 03a4181b59..32ed17c5be 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask -# debugging camera creatureanimation activatoranimation + creatureanimation +# debugging camera activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9a7f023e67..fe61802991 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -497,6 +497,7 @@ void OMW::Engine::go() { double dt = frameTimer.time_s(); frameTimer.setStartTick(); + //dt = std::min(dt, 0.2f); // frameRenderingQueued(dt); MWBase::Environment::get().getWorld()->update(dt, false); @@ -507,18 +508,6 @@ void OMW::Engine::go() mViewer.frame(/*simulationTime*/); } - /* - Ogre::Timer timer; - while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) - { - float dt = timer.getMilliseconds()/1000.f; - dt = std::min(dt, 0.2f); - - timer.reset(); - Ogre::Root::getSingleton().renderOneFrame(dt); - } - */ - // Save user settings settings.saveUser(settingspath); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7260fc6d15..9ccdf390ee 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,11 +1,13 @@ #include "creatureanimation.hpp" -#include -#include -#include - #include +#include + +#include +#include +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -16,45 +18,46 @@ namespace MWRender { -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, + const std::string& model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - MWWorld::LiveCellRef *ref = mPtr.get(); + //MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); + setObjectRoot(model /* , baseonly = false */); + //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + // addAnimSource("meshes\\xbase_anim.nif"); + //addAnimSource(model); } } -CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) +CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) + : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) , mShowWeapons(false) , mShowCarriedLeft(false) { - MWWorld::LiveCellRef *ref = mPtr.get(); + //MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); + setObjectRoot(model /* , baseonly = false*/); + //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + // addAnimSource("meshes\\xbase_anim.nif"); + //addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); updateParts(); } - mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); } void CreatureWeaponAnimation::showWeapons(bool showWeapon) @@ -77,8 +80,8 @@ void CreatureWeaponAnimation::showCarriedLeft(bool show) void CreatureWeaponAnimation::updateParts() { - mWeapon.setNull(); - mShield.setNull(); + mWeapon.reset(); + mShield.reset(); if (mShowWeapons) updatePart(mWeapon, MWWorld::InventoryStore::Slot_CarriedRight); @@ -86,9 +89,9 @@ void CreatureWeaponAnimation::updateParts() updatePart(mShield, MWWorld::InventoryStore::Slot_CarriedLeft); } -void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) +void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) { - if (!mSkelBase) + if (!mObjectRoot) return; MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); @@ -96,7 +99,7 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo if (it == inv.end()) { - scene.setNull(); + scene.reset(); return; } MWWorld::Ptr item = *it; @@ -107,13 +110,16 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo else bonename = "Shield Bone"; - scene = NifOgre::Loader::createObjects(mSkelBase, bonename, bonename, mInsert, item.getClass().getModel(item)); - Ogre::Vector3 glowColor = getEnchantmentColor(item); + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item)); + SceneUtil::attach(node, mObjectRoot, bonename, bonename); - setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0, - !item.getClass().getEnchantment(item).empty(), &glowColor); + scene.reset(new PartHolder(node)); + + if (!item.getClass().getEnchantment(item).empty()) + addGlow(node, getEnchantmentColor(item)); // Crossbows start out with a bolt attached + // FIXME: code duplicated from NpcAnimation if (slot == MWWorld::InventoryStore::Slot_CarriedRight && item.getTypeName() == typeid(ESM::Weapon).name() && item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) @@ -121,12 +127,14 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - else - mAmmunition.setNull(); + //else + // mAmmunition.setNull(); } - else - mAmmunition.setNull(); + //else + //mAmmunition.setNull(); + // FIXME: code duplicated from NpcAnimation + /* if(scene->mSkelBase) { Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton(); @@ -149,7 +157,9 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo } updateSkeletonInstance(mSkelBase->getSkeleton(), skel); } + */ + /* std::vector >::iterator ctrl(scene->mControllers.begin()); for(;ctrl != scene->mControllers.end();++ctrl) { @@ -161,45 +171,39 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo ctrl->setSource(Ogre::SharedPtr(new NullAnimationTime())); } } + */ } +/* void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) { - Ogre::Vector3 glowColor = getEnchantmentColor(ptr); + //Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, - !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); + //setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, + // !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); } +*/ void CreatureWeaponAnimation::attachArrow() { - WeaponAnimation::attachArrow(mPtr); + //WeaponAnimation::attachArrow(mPtr); } void CreatureWeaponAnimation::releaseArrow() { - WeaponAnimation::releaseArrow(mPtr); + //WeaponAnimation::releaseArrow(mPtr); } -Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) +osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { + /* Ogre::Vector3 ret = Animation::runAnimation(duration); if (mSkelBase) pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + */ - if (!mWeapon.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mWeapon->mControllers[i].update(); - } - if (!mShield.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mShield->mControllers[i].update(); - } - - return ret; + return osg::Vec3f(); } } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 6201c7af4a..ccb553d990 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,17 +15,17 @@ namespace MWRender class CreatureAnimation : public Animation { public: - CreatureAnimation(const MWWorld::Ptr& ptr, const std::string &model); + CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); virtual ~CreatureAnimation() {} }; // For creatures with weapons and shields // Animation is already virtual anyway, so might as well make a separate class. // Most creatures don't need weapons/shields, so this will save some memory. - class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public Animation/*, public WeaponAnimation*/, public MWWorld::InventoryStoreListener { public: - CreatureWeaponAnimation(const MWWorld::Ptr& ptr, const std::string &model); + CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); virtual ~CreatureWeaponAnimation() {} virtual void equipmentChanged() { updateParts(); } @@ -35,31 +35,31 @@ namespace MWRender void updateParts(); - void updatePart(NifOgre::ObjectScenePtr& scene, int slot); + void updatePart(PartHolderPtr& scene, int slot); virtual void attachArrow(); virtual void releaseArrow(); - virtual Ogre::Vector3 runAnimation(float duration); + virtual osg::Vec3f runAnimation(float duration); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. - virtual void setPitchFactor(float factor) { mPitchFactor = factor; } + //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + //virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } // WeaponAnimation - virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } - virtual void showWeapon(bool show) { showWeapons(show); } - virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); + //virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } + //virtual void showWeapon(bool show) { showWeapons(show); } + //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); private: - NifOgre::ObjectScenePtr mWeapon; - NifOgre::ObjectScenePtr mShield; + PartHolderPtr mWeapon; + PartHolderPtr mShield; bool mShowWeapons; bool mShowCarriedLeft; - Ogre::SharedPtr mWeaponAnimationTime; + //Ogre::SharedPtr mWeaponAnimationTime; }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c413d9334c..eeb5298b81 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,15 +1,5 @@ #include "npcanimation.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include @@ -575,18 +565,6 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; } -class SetObjectGroup { - int mGroup; - -public: - SetObjectGroup(int group) : mGroup(group) { } - - void operator()(Ogre::MovableObject *obj) const - { - obj->getUserObjectBindings().setUserAny(Ogre::Any(mGroup)); - } -}; - Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4564e3a972..3d11662aad 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -26,6 +26,7 @@ #include "renderconst.hpp" #include "animation.hpp" #include "npcanimation.hpp" +#include "creatureanimation.hpp" namespace { @@ -194,7 +195,13 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b insertBegin(ptr); // CreatureAnimation - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + std::auto_ptr anim; + + if (weaponsShields) + anim.reset(new CreatureWeaponAnimation(ptr, mesh, mResourceSystem)); + else + anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + mObjects.insert(std::make_pair(ptr, anim.release())); } From f7d2a2893090a9bfb1b7890ca94d0354156b4627 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 14:25:36 +0200 Subject: [PATCH 0128/1812] Port BoneOffset --- apps/openmw/mwrender/creatureanimation.cpp | 26 ---------------------- apps/openmw/mwrender/npcanimation.cpp | 25 --------------------- components/sceneutil/attach.cpp | 23 ++++++++++++++++++- components/sceneutil/visitor.hpp | 2 +- 4 files changed, 23 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9ccdf390ee..241ea56a36 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -133,32 +133,6 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) //else //mAmmunition.setNull(); - // FIXME: code duplicated from NpcAnimation - /* - if(scene->mSkelBase) - { - Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton(); - if(scene->mSkelBase->isParentTagPoint()) - { - Ogre::Node *root = scene->mSkelBase->getParentNode(); - if(skel->hasBone("BoneOffset")) - { - Ogre::Bone *offset = skel->getBone("BoneOffset"); - - root->translate(offset->getPosition()); - - // It appears that the BoneOffset rotation is completely bogus, at least for light models. - //root->rotate(offset->getOrientation()); - root->pitch(Ogre::Degree(-90.0f)); - - root->scale(offset->getScale()); - root->setInitialState(); - } - } - updateSkeletonInstance(mSkelBase->getSkeleton(), skel); - } - */ - /* std::vector >::iterator ctrl(scene->mControllers.begin()); for(;ctrl != scene->mControllers.end();++ctrl) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index eeb5298b81..719fb336b7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -698,31 +698,6 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } /* - if(mObjectParts[type]->mSkelBase) - { - Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton(); - if(mObjectParts[type]->mSkelBase->isParentTagPoint()) - { - Ogre::Node *root = mObjectParts[type]->mSkelBase->getParentNode(); - if(skel->hasBone("BoneOffset")) - { - Ogre::Bone *offset = skel->getBone("BoneOffset"); - - root->translate(offset->getPosition()); - - // It appears that the BoneOffset rotation is completely bogus, at least for light models. - //root->rotate(offset->getOrientation()); - root->pitch(Ogre::Degree(-90.0f)); - - root->scale(offset->getScale()); - root->setInitialState(); - } - } - - if (isSkinned(mObjectParts[type])) - updateSkeletonInstance(mSkelBase->getSkeleton(), skel); - } - std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); for(;ctrl != mObjectParts[type]->mControllers.end();++ctrl) { diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index f084704c38..26185eb3ed 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -165,9 +165,27 @@ namespace SceneUtil if (!find.mFoundNode) throw std::runtime_error(std::string("Can't find attachment node ") + attachNode); + FindByNameVisitor findBoneOffset("BoneOffset"); + toAttach->accept(findBoneOffset); + + osg::ref_ptr trans; + + if (findBoneOffset.mFoundNode) + { + osg::MatrixTransform* boneOffset = dynamic_cast(findBoneOffset.mFoundNode); + if (!boneOffset) + throw std::runtime_error("BoneOffset must be a MatrixTransform"); + + trans = new osg::PositionAttitudeTransform; + trans->setPosition(boneOffset->getMatrix().getTrans()); + // The BoneOffset rotation seems to be incorrect + trans->setAttitude(osg::Quat(-90, osg::Vec3f(1,0,0))); + } + if (attachNode.find("Left") != std::string::npos) { - osg::ref_ptr trans = new osg::PositionAttitudeTransform; + if (!trans) + trans = new osg::PositionAttitudeTransform; trans->setScale(osg::Vec3f(-1.f, 1.f, 1.f)); // Need to invert culling because of the negative scale @@ -176,7 +194,10 @@ namespace SceneUtil osg::FrontFace* frontFace = new osg::FrontFace; frontFace->setMode(osg::FrontFace::CLOCKWISE); trans->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + } + if (trans) + { find.mFoundNode->addChild(trans); trans->addChild(toAttach); return trans; diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 59c706f110..d26f95116d 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -28,7 +28,7 @@ namespace SceneUtil traverse(node); } - const std::string& mNameToFind; + std::string mNameToFind; osg::Group* mFoundNode; }; From c924e6404788bb8a875cd1f1907c4d8bb498078f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 14:42:09 +0200 Subject: [PATCH 0129/1812] Port HeadAnimationTime --- apps/openmw/mwrender/npcanimation.cpp | 77 +++++++++++++++------------ apps/openmw/mwrender/npcanimation.hpp | 12 ++--- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 719fb336b7..6a6b8a3159 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,5 +1,7 @@ #include "npcanimation.hpp" +#include + #include #include @@ -8,6 +10,8 @@ #include #include +#include // TextKeyMapHolder + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -67,7 +71,6 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { -/* HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mValue(0), mEnabled(true) { @@ -107,13 +110,14 @@ void HeadAnimationTime::update(float dt) } else { + // FIXME: would be nice to hold on to the SoundPtr so we don't have to retrieve it every frame mValue = mTalkStart + (mTalkStop - mTalkStart) * std::min(1.f, MWBase::Environment::get().getSoundManager()->getSaySoundLoudness(mReference)*2); // Rescale a bit (most voices are not very loud) } } -float HeadAnimationTime::getValue() const +float HeadAnimationTime::getValue(osg::NodeVisitor*) { return mValue; } @@ -137,7 +141,6 @@ void HeadAnimationTime::setBlinkStop(float value) { mBlinkStop = value; } -*/ static NpcAnimation::PartBoneMap createPartListMap() { @@ -196,7 +199,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par { mNpc = mPtr.get()->mBase; - //mHeadAnimationTime = Ogre::SharedPtr(new HeadAnimationTime(mPtr)); + mHeadAnimationTime = boost::shared_ptr(new HeadAnimationTime(mPtr)); //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) @@ -577,13 +580,13 @@ Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& mode return PartHolderPtr(new PartHolder(attached)); } -/* -Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) +osg::Vec3f NpcAnimation::runAnimation(float timepassed) { - Ogre::Vector3 ret = Animation::runAnimation(timepassed); + osg::Vec3f ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); + /* if (mSkelBase) { Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); @@ -625,10 +628,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } + */ return ret; } -*/ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { @@ -697,35 +700,44 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } - /* - std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); - for(;ctrl != mObjectParts[type]->mControllers.end();++ctrl) - { - if(ctrl->getSource().isNull()) - { - ctrl->setSource(mNullAnimationTimePtr); - if (type == ESM::PRT_Head) + boost::shared_ptr src; + if (type == ESM::PRT_Head) + { + src = mHeadAnimationTime; + + osg::Node* node = mObjectParts[type]->getNode(); + if (node->getUserDataContainer()) + { + for (unsigned int i=0; igetUserDataContainer()->getNumUserObjects(); ++i) { - ctrl->setSource(mHeadAnimationTime); - const NifOgre::TextKeyMap& keys = mObjectParts[type]->mTextKeys; - for (NifOgre::TextKeyMap::const_iterator it = keys.begin(); it != keys.end(); ++it) + osg::Object* obj = node->getUserDataContainer()->getUserObject(i); + if (NifOsg::TextKeyMapHolder* keys = dynamic_cast(obj)) { - if (Misc::StringUtils::ciEqual(it->second, "talk: start")) - mHeadAnimationTime->setTalkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "talk: stop")) - mHeadAnimationTime->setTalkStop(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: start")) - mHeadAnimationTime->setBlinkStart(it->first); - if (Misc::StringUtils::ciEqual(it->second, "blink: stop")) - mHeadAnimationTime->setBlinkStop(it->first); + for (NifOsg::TextKeyMap::const_iterator it = keys->mTextKeys.begin(); it != keys->mTextKeys.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->second, "talk: start")) + mHeadAnimationTime->setTalkStart(it->first); + if (Misc::StringUtils::ciEqual(it->second, "talk: stop")) + mHeadAnimationTime->setTalkStop(it->first); + if (Misc::StringUtils::ciEqual(it->second, "blink: start")) + mHeadAnimationTime->setBlinkStart(it->first); + if (Misc::StringUtils::ciEqual(it->second, "blink: stop")) + mHeadAnimationTime->setBlinkStop(it->first); + } + + break; } } - else if (type == ESM::PRT_Weapon) - ctrl->setSource(mWeaponAnimationTime); } } - */ + //else if (type == ESM::PRT_Weapon) + // src = mWeaponAnimationTime; + else + src.reset(new NullAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(src); + mObjectParts[type]->getNode()->accept(assignVisitor); return true; } @@ -825,6 +837,7 @@ void NpcAnimation::showCarriedLeft(bool show) if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { + // TODO //if (iter->getTypeName() == typeid(ESM::Light).name()) //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); } @@ -863,13 +876,11 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { - /* const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); - */ } } @@ -884,7 +895,7 @@ void NpcAnimation::setAlpha(float alpha) void NpcAnimation::enableHeadAnimation(bool enable) { - //mHeadAnimationTime->setEnabled(enable); + mHeadAnimationTime->setEnabled(enable); } void NpcAnimation::setWeaponGroup(const std::string &group) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 16bd45cc47..309bc5ef58 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,8 +15,7 @@ namespace ESM namespace MWRender { -/* -class HeadAnimationTime : public Ogre::ControllerValue +class HeadAnimationTime : public SceneUtil::ControllerSource { private: MWWorld::Ptr mReference; @@ -44,11 +43,8 @@ public: void setBlinkStart(float value); void setBlinkStop(float value); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor* nv); }; -*/ class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -96,7 +92,7 @@ private: Ogre::Vector3 mFirstPersonOffset; - //Ogre::SharedPtr mHeadAnimationTime; + boost::shared_ptr mHeadAnimationTime; //Ogre::SharedPtr mWeaponAnimationTime; float mAlpha; @@ -142,7 +138,7 @@ public: virtual void setWeaponGroup(const std::string& group); - //virtual Ogre::Vector3 runAnimation(float timepassed); + virtual osg::Vec3f runAnimation(float timepassed); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. From fcc7aa02abba9858d33e2757681e2dedaf169524 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 15:03:08 +0200 Subject: [PATCH 0130/1812] Port addExtraLight --- apps/openmw/mwrender/animation.cpp | 50 ++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 6 +-- apps/openmw/mwrender/npcanimation.cpp | 7 ++- apps/openmw/mwrender/objects.cpp | 62 ++++++--------------------- 4 files changed, 67 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2febf9c9a7..e4c05bc1ed 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -14,6 +15,8 @@ #include #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -178,6 +181,48 @@ namespace MWRender return result; } + void Animation::addExtraLight(osg::ref_ptr parent, const ESM::Light *esmLight) + { + SceneUtil::FindByNameVisitor visitor("AttachLight"); + parent->accept(visitor); + + osg::Group* attachTo = NULL; + if (visitor.mFoundNode) + { + attachTo = visitor.mFoundNode; + } + else + { + osg::ComputeBoundsVisitor computeBound; + parent->accept(computeBound); + + // PositionAttitudeTransform seems to be slightly faster than MatrixTransform + osg::ref_ptr trans(new osg::PositionAttitudeTransform); + trans->setPosition(computeBound.getBoundingBox().center()); + + parent->addChild(trans); + + attachTo = trans; + } + + osg::ref_ptr lightSource = new SceneUtil::LightSource; + osg::Light* light = new osg::Light; + lightSource->setLight(light); + + float realRadius = esmLight->mData.mRadius; + + lightSource->setRadius(realRadius); + light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); + //light->setLinearAttenuation(0.05); + light->setConstantAttenuation(0.f); + + light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + + attachTo->addChild(lightSource); + } + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { // Early out if we already have this effect @@ -307,7 +352,7 @@ namespace MWRender // -------------------------------------------------------------------------------- - ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem) + ObjectAnimation::ObjectAnimation(const MWWorld::Ptr &ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { if (!model.empty()) @@ -316,6 +361,9 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); + + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) + addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ccc4bfa23b..797c215c57 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -206,8 +206,8 @@ protected: * extension will be replaced with .kf. */ //void addAnimSource(const std::string &model); - /** Adds an additional light to the given object list using the specified ESM record. */ - //void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light); + /** Adds an additional light to the given node using the specified ESM record. */ + void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); //void clearAnimSources(); @@ -319,7 +319,7 @@ public: class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight); }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6a6b8a3159..56f12da139 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -431,7 +431,7 @@ void NpcAnimation::updateParts() const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); - //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), light); } } @@ -837,9 +837,8 @@ void NpcAnimation::showCarriedLeft(bool show) if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { - // TODO - //if (iter->getTypeName() == typeid(ESM::Light).name()) - //addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + if (iter->getTypeName() == typeid(ESM::Light).name()) + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); } } else diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d11662aad..1d28291de2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -17,7 +16,6 @@ #include #include -#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" @@ -120,9 +118,10 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) osg::Quat zr(-f[2], osg::Vec3(0,0,1)); // Rotates first around z, then y, then x - insert->setAttitude(zr*yr*xr); - - // TODO: actors rotate around z only + if (ptr.getClass().isActor()) + insert->setAttitude(zr); + else + insert->setAttitude(zr*yr*xr); ptr.getRefData().setBaseNode(insert); } @@ -131,55 +130,11 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool { insertBegin(ptr); - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) - { - SceneUtil::FindByNameVisitor visitor("AttachLight"); - ptr.getRefData().getBaseNode()->accept(visitor); - - osg::Group* attachTo = NULL; - if (visitor.mFoundNode) - { - attachTo = visitor.mFoundNode; - } - else - { - osg::ComputeBoundsVisitor computeBound; - osg::Group* objectRoot = anim->getOrCreateObjectRoot(); - objectRoot->accept(computeBound); - - // PositionAttitudeTransform seems to be slightly faster than MatrixTransform - osg::ref_ptr trans(new osg::PositionAttitudeTransform); - trans->setPosition(computeBound.getBoundingBox().center()); - - objectRoot->addChild(trans); - - attachTo = trans; - } - - const ESM::Light* esmLight = ptr.get()->mBase; - - osg::ref_ptr lightSource = new SceneUtil::LightSource; - osg::Light* light = new osg::Light; - lightSource->setLight(light); - - float realRadius = esmLight->mData.mRadius; - - lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); - //light->setLinearAttenuation(0.05); - light->setConstantAttenuation(0.f); - - light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); - light->setAmbient(osg::Vec4f(0,0,0,1)); - light->setSpecular(osg::Vec4f(0,0,0,0)); - - attachTo->addChild(lightSource); - } if (!allowLight) { RemoveParticlesVisitor visitor; @@ -202,6 +157,9 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -210,6 +168,10 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + mObjects.insert(std::make_pair(ptr, anim.release())); } From 68f93294da2b286448b2658ea8a067bdcee6a085 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 17:55:56 +0200 Subject: [PATCH 0131/1812] Port EffectManager --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/world.hpp | 9 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 4 +- apps/openmw/mwrender/animation.cpp | 52 ++------- apps/openmw/mwrender/animation.hpp | 28 ++--- apps/openmw/mwrender/effectmanager.cpp | 123 +++++++++------------- apps/openmw/mwrender/effectmanager.hpp | 57 ++++++---- apps/openmw/mwrender/objects.cpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 21 ++++ apps/openmw/mwrender/renderingmanager.hpp | 10 ++ apps/openmw/mwrender/util.cpp | 31 ++++++ apps/openmw/mwrender/util.hpp | 24 +++++ apps/openmw/mwworld/refdata.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 19 ++-- apps/openmw/mwworld/worldimp.hpp | 4 +- components/esm/defs.hpp | 7 ++ components/sceneutil/controller.cpp | 17 +++ components/sceneutil/controller.hpp | 14 +++ 21 files changed, 261 insertions(+), 172 deletions(-) create mode 100644 apps/openmw/mwrender/util.cpp create mode 100644 apps/openmw/mwrender/util.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 32ed17c5be..09f2e08fa8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,11 +21,11 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation + creatureanimation effectmanager util # debugging camera activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction -# terrainstorage renderconst effectmanager weaponanimation +# terrainstorage renderconst weaponanimation ) #add_openmw_dir (mwinput diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9e6c6d9bf3..0c1874ce6d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -17,6 +17,11 @@ namespace Ogre class Image; } +namespace osg +{ + class Vec3f; +} + namespace Loading { class Listener; @@ -546,9 +551,9 @@ namespace MWBase virtual void spawnRandomCreature(const std::string& creatureList) = 0; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0; + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c1b8177f78..a2451e1a16 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -319,7 +319,7 @@ namespace MWClass damage = 0; if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); MWMechanics::diseaseContact(victim, ptr); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 506852a908..b5ac8f6c6e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -583,7 +583,7 @@ namespace MWClass damage = 0; if (healthdmg && damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); MWMechanics::diseaseContact(victim, ptr); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 64456dd11d..b80ac8cf92 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -218,7 +218,7 @@ namespace MWMechanics appliedEnchantment = applyEnchantment(attacker, victim, projectile, hitPosition); if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index daf4424c55..221c672671 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -34,7 +34,7 @@ namespace MWMechanics .search("VFX_Summon_End"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + "", ptr.getRefData().getPosition().asVec3()); } else { @@ -190,7 +190,7 @@ namespace MWMechanics .search("VFX_Summon_End"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + "", ptr.getRefData().getPosition().asVec3()); MWBase::Environment::get().getWorld()->deleteObject(ptr); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e4c05bc1ed..d54e87dc56 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -24,6 +24,7 @@ #include "../mwworld/class.hpp" #include "vismask.hpp" +#include "util.hpp" namespace { @@ -70,30 +71,6 @@ namespace std::vector > mTextures; }; - class FindMaxControllerLengthVisitor : public SceneUtil::ControllerVisitor - { - public: - FindMaxControllerLengthVisitor() - : SceneUtil::ControllerVisitor() - , mMaxLength(0) - { - } - - virtual void visit(osg::Node& , SceneUtil::Controller& ctrl) - { - if (ctrl.mFunction) - mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); - } - - float getMaxLength() const - { - return mMaxLength; - } - - private: - float mMaxLength; - }; - } namespace MWRender @@ -246,7 +223,7 @@ namespace MWRender osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); params.mObjects = PartHolderPtr(new PartHolder(node)); - FindMaxControllerLengthVisitor findMaxLengthVisitor; + SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; node->accept(findMaxLengthVisitor); params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); @@ -262,22 +239,7 @@ namespace MWRender SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(params.mAnimTime)); node->accept(assignVisitor); - if (!texture.empty()) - { - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, mResourceSystem->getVFS()); - // Not sure if wrap settings should be pulled from the overridden texture? - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, - osg::Texture2D::CLAMP); - osg::ref_ptr stateset; - if (node->getStateSet()) - stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); - else - stateset = new osg::StateSet; - - stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); - - node->setStateSet(stateset); - } + overrideTexture(texture, mResourceSystem, node); // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. @@ -330,22 +292,22 @@ namespace MWRender } } - float Animation::EffectAnimationTime::getValue(osg::NodeVisitor*) + float EffectAnimationTime::getValue(osg::NodeVisitor*) { return mTime; } - void Animation::EffectAnimationTime::addTime(float duration) + void EffectAnimationTime::addTime(float duration) { mTime += duration; } - void Animation::EffectAnimationTime::resetTime(float time) + void EffectAnimationTime::resetTime(float time) { mTime = time; } - float Animation::EffectAnimationTime::getTime() const + float EffectAnimationTime::getTime() const { return mTime; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 797c215c57..aef4d4b80f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,6 +22,20 @@ namespace MWRender { class Camera; +class EffectAnimationTime : public SceneUtil::ControllerSource +{ +private: + float mTime; +public: + virtual float getValue(osg::NodeVisitor* nv); + + void addTime(float duration); + void resetTime(float time); + float getTime() const; + + EffectAnimationTime() : mTime(0) { } +}; + class Animation { public: @@ -61,20 +75,6 @@ protected: virtual void setValue(Ogre::Real value); }; - class EffectAnimationTime : public SceneUtil::ControllerSource - { - private: - float mTime; - public: - virtual float getValue(osg::NodeVisitor* nv); - - void addTime(float duration); - void resetTime(float time); - float getTime() const; - - EffectAnimationTime() : mTime(0) { } - }; - class NullAnimationTime : public SceneUtil::ControllerSource { public: diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 503a0223e8..642909cda2 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -1,102 +1,83 @@ #include "effectmanager.hpp" +#include + #include -#include -#include -#include -#include +#include +#include + +#include #include "animation.hpp" -#include "renderconst.hpp" +#include "vismask.hpp" +#include "util.hpp" namespace MWRender { -EffectManager::EffectManager(Ogre::SceneManager *sceneMgr) - : mSceneMgr(sceneMgr) +EffectManager::EffectManager(osg::ref_ptr parent, Resource::ResourceSystem* resourceSystem) + : mParentNode(parent) + , mResourceSystem(resourceSystem) { } -void EffectManager::addEffect(const std::string &model, std::string textureOverride, const Ogre::Vector3 &worldPosition, float scale) +EffectManager::~EffectManager() { - Ogre::SceneNode* sceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(worldPosition); - sceneNode->setScale(scale,scale,scale); - - NifOgre::ObjectScenePtr scene = NifOgre::Loader::createObjects(sceneNode, model); - - MWRender::Animation::setRenderProperties(scene, RV_Effects, - RQG_Main, RQG_Alpha, 0.f, false, NULL); - - for(size_t i = 0;i < scene->mControllers.size();i++) - { - if(scene->mControllers[i].getSource().isNull()) - scene->mControllers[i].setSource(Ogre::SharedPtr (new EffectAnimationTime())); - } - - if (!textureOverride.empty()) - { - std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(textureOverride); - for(size_t i = 0;i < scene->mParticles.size(); ++i) - { - Ogre::ParticleSystem* partSys = scene->mParticles[i]; - - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(partSys); - - for (int t=0; tgetNumTechniques(); ++t) - { - Ogre::Technique* tech = mat->getTechnique(t); - for (int p=0; pgetNumPasses(); ++p) - { - Ogre::Pass* pass = tech->getPass(p); - for (int tex=0; texgetNumTextureUnitStates(); ++tex) - { - Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex); - tus->setTextureName(correctedTexture); - } - } - } - } - } - - mEffects.push_back(std::make_pair(sceneNode, scene)); + clear(); } -void EffectManager::update(float dt, Ogre::Camera* camera) +void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale) { - for (std::vector >::iterator it = mEffects.begin(); it != mEffects.end(); ) + osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model); + + node->setNodeMask(Mask_Effect); + + Effect effect; + effect.mAnimTime.reset(new EffectAnimationTime); + + SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; + node->accept(findMaxLengthVisitor); + effect.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); + + osg::ref_ptr trans = new osg::PositionAttitudeTransform; + trans->setPosition(worldPosition); + trans->setScale(osg::Vec3f(scale, scale, scale)); + trans->addChild(node); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); + node->accept(assignVisitor); + + overrideTexture(textureOverride, mResourceSystem, node); + + mParentNode->addChild(trans); + + mEffects[trans] = effect; +} + +void EffectManager::update(float dt) +{ + for (EffectMap::iterator it = mEffects.begin(); it != mEffects.end(); ) { - NifOgre::ObjectScenePtr objects = it->second; - for(size_t i = 0; i < objects->mControllers.size() ;i++) - { - EffectAnimationTime* value = dynamic_cast(objects->mControllers[i].getSource().get()); - if (value) - value->addTime(dt); + it->second.mAnimTime->addTime(dt); - objects->mControllers[i].update(); - } - objects->rotateBillboardNodes(camera); - - // Finished playing? - if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength) + if (it->second.mAnimTime->getTime() >= it->second.mMaxControllerLength) { - Ogre::SceneNode* node = it->first; - it = mEffects.erase(it); - mSceneMgr->destroySceneNode(node); - continue; + mParentNode->removeChild(it->first); + mEffects.erase(it++); } - ++it; + else + ++it; } } void EffectManager::clear() { - for (std::vector >::iterator it = mEffects.begin(); it != mEffects.end(); ) + for (EffectMap::iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - Ogre::SceneNode* node = it->first; - it = mEffects.erase(it); - mSceneMgr->destroySceneNode(node); + mParentNode->removeChild(it->first); } + mEffects.clear(); } } diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index eb68636555..6d7aaaf4ff 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -1,43 +1,60 @@ #ifndef OPENMW_MWRENDER_EFFECTMANAGER_H #define OPENMW_MWRENDER_EFFECTMANAGER_H -#include +#include +#include + +#include + +#include + +namespace osg +{ + class Group; + class Vec3f; + class PositionAttitudeTransform; +} + +namespace Resource +{ + class ResourceSystem; +} namespace MWRender { - - class EffectAnimationTime : public Ogre::ControllerValue - { - private: - float mTime; - public: - EffectAnimationTime() : mTime(0) { } - void addTime(float time) { mTime += time; } - - virtual Ogre::Real getValue() const { return mTime; } - virtual void setValue(Ogre::Real value) {} - }; - + class EffectAnimationTime; // Note: effects attached to another object should be managed by MWRender::Animation::addEffect. // This class manages "free" effects, i.e. attached to a dedicated scene node in the world. class EffectManager { public: - EffectManager(Ogre::SceneManager* sceneMgr); - ~EffectManager() { clear(); } + EffectManager(osg::ref_ptr parent, Resource::ResourceSystem* resourceSystem); + ~EffectManager(); /// Add an effect. When it's finished playing, it will be removed automatically. - void addEffect (const std::string& model, std::string textureOverride, const Ogre::Vector3& worldPosition, float scale); + void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale); - void update(float dt, Ogre::Camera* camera); + void update(float dt); /// Remove all effects void clear(); private: - std::vector > mEffects; - Ogre::SceneManager* mSceneMgr; + struct Effect + { + float mMaxControllerLength; + boost::shared_ptr mAnimTime; + }; + + typedef std::map, Effect> EffectMap; + EffectMap mEffects; + + osg::ref_ptr mParentNode; + Resource::ResourceSystem* mResourceSystem; + + EffectManager(const EffectManager&); + void operator=(const EffectManager&); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 1d28291de2..4b1fa6d5b8 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -19,7 +19,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "renderconst.hpp" #include "animation.hpp" diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 26b86d1b26..becd563b96 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,7 @@ #include #include "sky.hpp" +#include "effectmanager.hpp" namespace MWRender { @@ -60,6 +61,8 @@ namespace MWRender mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); + mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -163,6 +166,24 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { mObjects->update(dt); + mEffectManager->update(dt); + } + + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) + { + mEffectManager->addEffect(model, texture, worldPosition, scale); + } + + void RenderingManager::notifyWorldSpaceChanged() + { + mEffectManager->clear(); + //mWater->clearRipples(); + } + + void RenderingManager::clear() + { + //mLocalMap->clear(); + notifyWorldSpaceChanged(); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b7aec37866..61f611a8c8 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -33,6 +33,7 @@ namespace MWRender class StateUpdater; + class EffectManager; class SkyManager; class RenderingManager : public MWRender::RenderingInterface @@ -63,6 +64,14 @@ namespace MWRender osg::Vec3f getEyePos(); + void spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale = 1.f); + + /// Clear all savegame-specific data + void clear(); + + /// Clear all worldspace-specific data + void notifyWorldSpaceChanged(); + void update(float dt, bool paused); private: @@ -74,6 +83,7 @@ namespace MWRender std::auto_ptr mObjects; std::auto_ptr mSky; + std::auto_ptr mEffectManager; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp new file mode 100644 index 0000000000..e1af1c3393 --- /dev/null +++ b/apps/openmw/mwrender/util.cpp @@ -0,0 +1,31 @@ +#include "util.hpp" + +#include + +#include +#include +#include + +namespace MWRender +{ + +void overrideTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) +{ + if (texture.empty()) + return; + std::string correctedTexture = Misc::ResourceHelpers::correctTexturePath(texture, resourceSystem->getVFS()); + // Not sure if wrap settings should be pulled from the overridden texture? + osg::ref_ptr tex = resourceSystem->getTextureManager()->getTexture2D(correctedTexture, osg::Texture2D::CLAMP, + osg::Texture2D::CLAMP); + osg::ref_ptr stateset; + if (node->getStateSet()) + stateset = static_cast(node->getStateSet()->clone(osg::CopyOp::SHALLOW_COPY)); + else + stateset = new osg::StateSet; + + stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); + + node->setStateSet(stateset); +} + +} diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp new file mode 100644 index 0000000000..d078f0d982 --- /dev/null +++ b/apps/openmw/mwrender/util.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_MWRENDER_UTIL_H +#define OPENMW_MWRENDER_UTIL_H + +#include +#include + +namespace osg +{ + class Node; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + + void overrideTexture(const std::string& texture, Resource::ResourceSystem* resourceSystem, osg::ref_ptr node); + +} + +#endif diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 2099b859fd..955913d9c4 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c6a1b5477c..0628b42d7c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -276,7 +276,7 @@ namespace MWWorld void World::clear() { mWeatherManager->clear(); - //mRendering->clear(); + mRendering->clear(); #if 0 mProjectileManager->clear(); #endif @@ -991,8 +991,9 @@ namespace MWWorld // changed worldspace #if 0 mProjectileManager->clear(); - mRendering->notifyWorldSpaceChanged(); #endif + mRendering->notifyWorldSpaceChanged(); + mCurrentWorldSpace = cellName; } @@ -1010,8 +1011,8 @@ namespace MWWorld // changed worldspace #if 0 mProjectileManager->clear(); - mRendering->notifyWorldSpaceChanged(); #endif + mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); mWorldScene->changeToExteriorCell(position, true); @@ -3203,7 +3204,7 @@ namespace MWWorld } } - void World::spawnBloodEffect(const Ptr &ptr, const Vector3 &worldPosition) + void World::spawnBloodEffect(const Ptr &ptr, const osg::Vec3f &worldPosition) { if (ptr == getPlayerPtr() && Settings::Manager::getBool("hit fader", "GUI")) return; @@ -3230,12 +3231,12 @@ namespace MWWorld modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); - //mRendering->spawnEffect(model, texture, worldPosition); + mRendering->spawnEffect(model, texture, worldPosition); } - void World::spawnEffect(const std::string &model, const std::string &textureOverride, const Vector3 &worldPos) + void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos) { - //mRendering->spawnEffect(model, textureOverride, worldPos); + mRendering->spawnEffect(model, textureOverride, worldPos); } void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, @@ -3251,15 +3252,13 @@ namespace MWWorld continue; // Not an area effect // Spawn the explosion orb effect - /* const ESM::Static* areaStatic; if (!effect->mCasting.empty()) areaStatic = getStore().get().find (effect->mArea); else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); - */ + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", osg::Vec3f(origin.x, origin.y, origin.z), static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9afda480b6..5f79f52dcf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -650,9 +650,9 @@ namespace MWWorld virtual void spawnRandomCreature(const std::string& creatureList); /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition); + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition); - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index d261d7247d..8ce76a8eac 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -3,6 +3,8 @@ #include +#include + namespace ESM { @@ -37,6 +39,11 @@ struct Position { float pos[3]; float rot[3]; + + osg::Vec3f asVec3() const + { + return osg::Vec3f(pos[0], pos[1], pos[2]); + } }; #pragma pack(pop) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 1f1b95ac81..79a75063a9 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -89,4 +89,21 @@ namespace SceneUtil ctrl.mSource = mToAssign; } + FindMaxControllerLengthVisitor::FindMaxControllerLengthVisitor() + : SceneUtil::ControllerVisitor() + , mMaxLength(0) + { + } + + void FindMaxControllerLengthVisitor::visit(osg::Node &, Controller &ctrl) + { + if (ctrl.mFunction) + mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + } + + float FindMaxControllerLengthVisitor::getMaxLength() const + { + return mMaxLength; + } + } diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 655e021641..a4e209e8c3 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -72,6 +72,20 @@ namespace SceneUtil boost::shared_ptr mToAssign; }; + /// Finds the maximum of all controller functions in the given scene graph + class FindMaxControllerLengthVisitor : public ControllerVisitor + { + public: + FindMaxControllerLengthVisitor(); + + virtual void visit(osg::Node& , Controller& ctrl); + + float getMaxLength() const; + + private: + float mMaxLength; + }; + } #endif From 42f6d9e15b642c69ce7adb745a3304c8a2d7a526 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 20:07:18 +0200 Subject: [PATCH 0132/1812] Port video player --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/sky.cpp | 13 +-- apps/openmw/mwsound/movieaudiofactory.cpp | 5 +- .../ogre-ffmpeg-videoplayer/videoplayer.cpp | 25 ++--- .../ogre-ffmpeg-videoplayer/videoplayer.hpp | 18 +++- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 100 +++++++++--------- extern/ogre-ffmpeg-videoplayer/videostate.hpp | 22 ++-- 9 files changed, 104 insertions(+), 86 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d5403337..c5319d6006 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,7 +549,7 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -#add_subdirectory (extern/ogre-ffmpeg-videoplayer) +add_subdirectory (extern/ogre-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 09f2e08fa8..46eb794622 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -59,8 +59,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper -# movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory ) add_openmw_dir (mwworld @@ -138,6 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} + "ogre-ffmpeg-videoplayer" "oics" components ) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index becd563b96..412d10ba2e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -167,6 +167,7 @@ namespace MWRender { mObjects->update(dt); mEffectManager->update(dt); + mSky->update(dt); } void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f843f9a43f..f4028caa76 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -599,8 +599,8 @@ void SkyManager::update(float duration) mCloudAnimationTimer += duration * mCloudSpeed; /// \todo improve this - //mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - //mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); + mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); //mMasser->setColour (ColourValue(1,1,1,1)); @@ -684,13 +684,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) DisableCullingVisitor visitor; mParticleEffect->accept(visitor); - /* - for (size_t i = 0; i < mParticle->mControllers.size(); ++i) - { - if (mParticle->mControllers[i].getSource().isNull()) - mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); - } - */ + SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + mParticleEffect->accept(assignVisitor); } } diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 468f8c82c7..198a66c533 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -17,7 +17,8 @@ namespace MWSound { public: MWSoundDecoderBridge(MWSound::MovieAudioDecoder* decoder) - : mDecoder(decoder) + : Sound_Decoder(NULL) + , mDecoder(decoder) { } @@ -51,7 +52,7 @@ namespace MWSound std::string getStreamName() { - return mVideoState->stream->getName(); + return std::string(); } private: diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index c2daf35795..8dedeaf648 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,7 @@ #include "videoplayer.hpp" +#include + #include "audiofactory.hpp" #include "videostate.hpp" @@ -23,7 +25,7 @@ void VideoPlayer::setAudioFactory(MovieAudioFactory *factory) mAudioFactory.reset(factory); } -void VideoPlayer::playVideo(const std::string &resourceName) +void VideoPlayer::playVideo(boost::shared_ptr inputstream) { if(mState) close(); @@ -31,10 +33,10 @@ void VideoPlayer::playVideo(const std::string &resourceName) try { mState = new VideoState; mState->setAudioFactory(mAudioFactory.get()); - mState->init(resourceName); + mState->init(inputstream); // wait until we have the first picture - while (mState->video_st && mState->mTexture.isNull()) + while (mState->video_st && !mState->mTexture.get()) { if (!mState->update()) break; @@ -53,27 +55,26 @@ bool VideoPlayer::update () return false; } -std::string VideoPlayer::getTextureName() +osg::ref_ptr VideoPlayer::getVideoTexture() { - std::string name; - if (mState && !mState->mTexture.isNull()) - name = mState->mTexture->getName(); - return name; + if (mState) + return mState->mTexture; + return osg::ref_ptr(); } int VideoPlayer::getVideoWidth() { int width=0; - if (mState && !mState->mTexture.isNull()) - width = mState->mTexture->getWidth(); + if (mState && mState->mTexture.get()) + width = mState->mTexture->getTextureWidth(); return width; } int VideoPlayer::getVideoHeight() { int height=0; - if (mState && !mState->mTexture.isNull()) - height = mState->mTexture->getHeight(); + if (mState && mState->mTexture.get()) + height = mState->mTexture->getTextureHeight(); return height; } diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp index 2727ac6f08..073dc6be22 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp @@ -4,6 +4,17 @@ #include #include +#include + +#include + +#include + +namespace osg +{ + class Texture2D; +} + namespace Video { @@ -30,7 +41,7 @@ namespace Video /// Play the given video. If a video is already playing, the old video is closed first. /// @note The video will be unpaused by default. Use the pause() and play() methods to control pausing. - void playVideo (const std::string& resourceName); + void playVideo (boost::shared_ptr inputstream); /// Get the current playback time position in the video, in seconds double getCurrentTime(); @@ -52,8 +63,9 @@ namespace Video /// Stop the currently playing video, if a video is playing. void close(); - /// Return the texture name of the currently playing video, or "" if no video is playing. - std::string getTextureName(); + /// Return the texture of the currently playing video, or a null pointer if no video is playing. + osg::ref_ptr getVideoTexture(); + /// Return the width of the currently playing video, or 0 if no video is playing. int getVideoWidth(); /// Return the height of the currently playing video, or 0 if no video is playing. diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 66c7c2ad50..e95a0ca7bb 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -11,6 +11,8 @@ #include #include +#include + extern "C" { #include @@ -172,12 +174,14 @@ void PacketQueue::clear() this->mutex.unlock (); } -int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) +int VideoState::istream_read(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; try { - return stream->read(buf, buf_size); + std::istream& stream = *static_cast(user_data)->stream; + stream.read((char*)buf, buf_size); + stream.clear(); + return stream.gcount(); } catch (std::exception& ) { @@ -185,57 +189,57 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) } } -int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) +int VideoState::istream_write(void *, uint8_t *, int) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - try - { - return stream->write(buf, buf_size); - } - catch (std::exception& ) - { - return 0; - } + throw std::runtime_error("can't write to read-only stream"); } -int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whence) +int64_t VideoState::istream_seek(void *user_data, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + std::istream& stream = *static_cast(user_data)->stream; whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) - return stream->size(); + { + size_t prev = stream.tellg(); + stream.seekg(0, std::ios_base::end); + size_t size = stream.tellg(); + stream.seekg(prev, std::ios_base::beg); + return size; + } + if(whence == SEEK_SET) - stream->seek(static_cast(offset)); + stream.seekg(offset, std::ios_base::beg); else if(whence == SEEK_CUR) - stream->seek(static_cast(stream->tell()+offset)); + stream.seekg(offset, std::ios_base::cur); else if(whence == SEEK_END) - stream->seek(static_cast(stream->size() + offset)); + stream.seekg(offset, std::ios_base::end); else return -1; - return stream->tell(); + return stream.tellg(); } void VideoState::video_display(VideoPicture *vp) { if((*this->video_st)->codec->width != 0 && (*this->video_st)->codec->height != 0) { - if (mTexture.isNull()) + if (!mTexture.get()) { - static int i = 0; - mTexture = Ogre::TextureManager::getSingleton().createManual( - "ffmpeg/VideoTexture" + Ogre::StringConverter::toString(++i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - (*this->video_st)->codec->width, (*this->video_st)->codec->height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + mTexture = new osg::Texture2D; + mTexture->setDataVariance(osg::Object::DYNAMIC); + mTexture->setResizeNonPowerOfTwoHint(false); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); } - Ogre::PixelBox pb((*this->video_st)->codec->width, (*this->video_st)->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); - Ogre::HardwarePixelBufferSharedPtr buffer = mTexture->getBuffer(); - buffer->blitFromMemory(pb); + + osg::ref_ptr image = new osg::Image; + + image->setImage((*this->video_st)->codec->width, (*this->video_st)->codec->height, + 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, &vp->data[0], osg::Image::NO_DELETE); + + mTexture->setImage(image); } } @@ -250,7 +254,7 @@ void VideoState::video_refresh() VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); - this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_rindex = (pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->frame_last_pts = vp->pts; this->pictq_size--; this->pictq_cond.notify_one(); @@ -267,12 +271,12 @@ void VideoState::video_refresh() for (; ipictq_size-1; ++i) { if (this->pictq[pictq_rindex].pts + threshold <= this->get_master_clock()) - this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; // not enough time to show this picture + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; // not enough time to show this picture else break; } - assert (this->pictq_rindex < VIDEO_PICTURE_QUEUE_SIZE); + assert (this->pictq_rindex < VIDEO_PICTURE_ARRAY_SIZE); VideoPicture* vp = &this->pictq[this->pictq_rindex]; this->video_display(vp); @@ -282,7 +286,7 @@ void VideoState::video_refresh() this->pictq_size -= i; // update queue for next picture this->pictq_size--; - this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_cond.notify_one(); } } @@ -328,7 +332,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) 0, (*this->video_st)->codec->height, &dst, this->rgbaFrame->linesize); // now we inform our display thread that we have a pic ready - this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_ARRAY_SIZE; this->pictq_size++; this->pictq_mutex.unlock(); @@ -605,7 +609,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) return 0; } -void VideoState::init(const std::string& resourceName) +void VideoState::init(boost::shared_ptr inputstream) { int video_index = -1; int audio_index = -1; @@ -614,17 +618,19 @@ void VideoState::init(const std::string& resourceName) this->av_sync_type = AV_SYNC_DEFAULT; this->mQuit = false; - this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); - if(this->stream.isNull()) + this->stream = inputstream; + if(!this->stream.get()) throw std::runtime_error("Failed to open video resource"); - AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, istream_read, istream_write, istream_seek); if(!ioCtx) throw std::runtime_error("Failed to allocate AVIOContext"); this->format_ctx = avformat_alloc_context(); if(this->format_ctx) this->format_ctx->pb = ioCtx; + std::string videoName; + // Open video file /// /// format_ctx->pb->buffer must be freed by hand, @@ -632,7 +638,7 @@ void VideoState::init(const std::string& resourceName) /// /// https://trac.ffmpeg.org/ticket/1357 /// - if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) + if(!this->format_ctx || avformat_open_input(&this->format_ctx, videoName.c_str(), NULL, NULL)) { if (this->format_ctx != NULL) { @@ -656,7 +662,7 @@ void VideoState::init(const std::string& resourceName) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); + av_dump_format(this->format_ctx, 0, videoName.c_str(), 0); for(i = 0;i < this->format_ctx->nb_streams;i++) { @@ -724,11 +730,7 @@ void VideoState::deinit() avformat_close_input(&this->format_ctx); } - if (!mTexture.isNull()) - { - Ogre::TextureManager::getSingleton().remove(mTexture->getName()); - mTexture.setNull(); - } + mTexture = NULL; } double VideoState::get_external_clock() diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.hpp b/extern/ogre-ffmpeg-videoplayer/videostate.hpp index cdeb2d0e39..40925e0141 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.hpp @@ -3,11 +3,17 @@ #include -#include +#include +namespace osg +{ + class Texture2D; +} #include "videodefs.hpp" #define VIDEO_PICTURE_QUEUE_SIZE 50 +// allocate one extra to make sure we do not overwrite the osg::Image currently set on the texture +#define VIDEO_PICTURE_ARRAY_SIZE (VIDEO_PICTURE_QUEUE_SIZE+1) extern "C" { @@ -78,7 +84,7 @@ struct VideoState { void setAudioFactory(MovieAudioFactory* factory); - void init(const std::string& resourceName); + void init(boost::shared_ptr inputstream); void deinit(); void setPaused(bool isPaused); @@ -104,18 +110,18 @@ struct VideoState { double get_external_clock(); double get_master_clock(); - static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); - static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); - static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); + static int istream_read(void *user_data, uint8_t *buf, int buf_size); + static int istream_write(void *user_data, uint8_t *buf, int buf_size); + static int64_t istream_seek(void *user_data, int64_t offset, int whence); - Ogre::TexturePtr mTexture; + osg::ref_ptr mTexture; MovieAudioFactory* mAudioFactory; boost::shared_ptr mAudioDecoder; ExternalClock mExternalClock; - Ogre::DataStreamPtr stream; + boost::shared_ptr stream; AVFormatContext* format_ctx; int av_sync_type; @@ -130,7 +136,7 @@ struct VideoState { double video_clock; /// Date: Sun, 19 Apr 2015 20:12:37 +0200 Subject: [PATCH 0133/1812] Dead code removal --- extern/ogre-ffmpeg-videoplayer/videoplayer.hpp | 2 +- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp index 073dc6be22..261246f39b 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp @@ -22,7 +22,7 @@ namespace Video class MovieAudioFactory; /** - * @brief Plays a video on an Ogre texture. + * @brief Plays a video on an osg texture. */ class VideoPlayer { diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index e95a0ca7bb..6a054d99e6 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -5,12 +5,6 @@ #endif #include -// Has to be included *before* ffmpeg, due to a macro collision with ffmpeg (#define PixelFormat in avformat.h - grumble) -#include -#include -#include -#include - #include extern "C" @@ -535,12 +529,9 @@ void VideoState::decode_thread_loop(VideoState *self) av_free_packet(packet); } } - catch(std::runtime_error& e) { + catch(std::exception& e) { std::cerr << "An error occured playing the video: " << e.what () << std::endl; } - catch(Ogre::Exception& e) { - std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; - } self->mQuit = true; } From 92ef9b1c57130698b7882af7d0aa71339089e5b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Apr 2015 20:14:06 +0200 Subject: [PATCH 0134/1812] Rename to osg-ffmpeg-videoplayer --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/videowidget.cpp | 2 +- apps/openmw/mwsound/movieaudiofactory.cpp | 4 ++-- apps/openmw/mwsound/movieaudiofactory.hpp | 2 +- .../CMakeLists.txt | 8 ++++---- .../License.txt | 0 .../audiodecoder.cpp | 0 .../audiodecoder.hpp | 0 .../audiofactory.hpp | 0 .../libavwrapper.cpp | 0 .../videodefs.hpp | 0 .../videoplayer.cpp | 0 .../videoplayer.hpp | 0 .../videostate.cpp | 0 .../videostate.hpp | 0 16 files changed, 10 insertions(+), 10 deletions(-) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/CMakeLists.txt (78%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/License.txt (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiodecoder.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiodecoder.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/audiofactory.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/libavwrapper.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videodefs.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videoplayer.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videoplayer.hpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videostate.cpp (100%) rename extern/{ogre-ffmpeg-videoplayer => osg-ffmpeg-videoplayer}/videostate.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5319d6006..e806b25782 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,7 +549,7 @@ include_directories(libs) add_subdirectory(libs/openengine) # Extern -add_subdirectory (extern/ogre-ffmpeg-videoplayer) +add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) #add_subdirectory (extern/sdl4ogre) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 46eb794622..c8854f84bf 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -137,7 +137,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - "ogre-ffmpeg-videoplayer" + "osg-ffmpeg-videoplayer" "oics" components ) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 4ead16c5b3..28771f14fd 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,6 +1,6 @@ #include "videowidget.hpp" -//#include +//#include #include diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 198a66c533..47889051ae 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -1,7 +1,7 @@ #include "movieaudiofactory.hpp" -#include -#include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwsound/movieaudiofactory.hpp b/apps/openmw/mwsound/movieaudiofactory.hpp index a3c6021972..1391a0012d 100644 --- a/apps/openmw/mwsound/movieaudiofactory.hpp +++ b/apps/openmw/mwsound/movieaudiofactory.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWSOUND_MOVIEAUDIOFACTORY_H #define OPENMW_MWSOUND_MOVIEAUDIOFACTORY_H -#include +#include namespace MWSound { diff --git a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt similarity index 78% rename from extern/ogre-ffmpeg-videoplayer/CMakeLists.txt rename to extern/osg-ffmpeg-videoplayer/CMakeLists.txt index 299a57799b..92a2f3424f 100644 --- a/extern/ogre-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt @@ -1,8 +1,8 @@ -set(OGRE_FFMPEG_VIDEOPLAYER_LIBRARY "ogre-ffmpeg-videoplayer") +set(OSG_FFMPEG_VIDEOPLAYER_LIBRARY "osg-ffmpeg-videoplayer") # Sources -set(OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES +set(OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES videoplayer.cpp videostate.cpp videodefs.hpp @@ -36,7 +36,7 @@ set(BOOST_COMPONENTS thread) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) include_directories(${Boost_INCLUDE_DIRS}) -add_library(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OGRE_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) -target_link_libraries(${OGRE_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) +add_library(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) +target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${VIDEO_FFMPEG_LIBRARIES} ${Boost_LIBRARIES}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/ogre-ffmpeg-videoplayer/License.txt b/extern/osg-ffmpeg-videoplayer/License.txt similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/License.txt rename to extern/osg-ffmpeg-videoplayer/License.txt diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp rename to extern/osg-ffmpeg-videoplayer/audiodecoder.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiodecoder.hpp rename to extern/osg-ffmpeg-videoplayer/audiodecoder.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/osg-ffmpeg-videoplayer/audiofactory.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/audiofactory.hpp rename to extern/osg-ffmpeg-videoplayer/audiofactory.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/libavwrapper.cpp rename to extern/osg-ffmpeg-videoplayer/libavwrapper.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videodefs.hpp b/extern/osg-ffmpeg-videoplayer/videodefs.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videodefs.hpp rename to extern/osg-ffmpeg-videoplayer/videodefs.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videoplayer.cpp rename to extern/osg-ffmpeg-videoplayer/videoplayer.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videoplayer.hpp rename to extern/osg-ffmpeg-videoplayer/videoplayer.hpp diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videostate.cpp rename to extern/osg-ffmpeg-videoplayer/videostate.cpp diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp similarity index 100% rename from extern/ogre-ffmpeg-videoplayer/videostate.hpp rename to extern/osg-ffmpeg-videoplayer/videostate.hpp From 167ae600c5a87b1d0fcbea6570992026d29a31a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Apr 2015 00:37:17 +0200 Subject: [PATCH 0135/1812] Implement gravity decay (previously unknown float) --- components/nif/controlled.cpp | 5 +---- components/nif/controlled.hpp | 1 + components/nifosg/particle.cpp | 38 +++++++++++++++++++++++++--------- components/nifosg/particle.hpp | 4 +++- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index bf391d388b..5c63094ce1 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -54,10 +54,7 @@ namespace Nif { Controlled::read(nif); - float decay = nif->getFloat(); - if (decay != 0.f) - nif->file->warn("Unhandled gravity decay factor"); - + mDecay = nif->getFloat(); mForce = nif->getFloat(); mType = nif->getUInt(); mPosition = nif->getVector3(); diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36d90b03dd..4bd7ce1f9d 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -92,6 +92,7 @@ public: * 1 - Point (fixed origin) */ int mType; + float mDecay; osg::Vec3f mPosition; osg::Vec3f mDirection; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 59a4a981b3..3cfd91f1f0 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -155,13 +155,14 @@ void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* d GravityAffector::GravityAffector(const Nif::NiGravity *gravity) : mForce(gravity->mForce) , mType(static_cast(gravity->mType)) + , mDecay(gravity->mDecay) , mPosition(gravity->mPosition) , mDirection(gravity->mDirection) { } GravityAffector::GravityAffector() - : mForce(0), mType(Type_Wind) + : mForce(0), mType(Type_Wind), mDecay(0.f) { } @@ -175,10 +176,12 @@ GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp void GravityAffector::beginOperate(osgParticle::Program* program) { bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); - if (mType == Type_Wind) - mCachedWorldPositionDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; - else // Type_Point - mCachedWorldPositionDirection = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + if (mType == Type_Point || mDecay != 0.f) // we don't need the position for Wind gravity, except if decay is being applied + mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition; + + mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; + mCachedWorldDirection.normalize(); } void GravityAffector::operate(osgParticle::Particle *particle, double dt) @@ -187,18 +190,33 @@ void GravityAffector::operate(osgParticle::Particle *particle, double dt) switch (mType) { case Type_Wind: - particle->addVelocity(mCachedWorldPositionDirection * mForce * dt * magic); + { + float decayFactor = 1.f; + if (mDecay != 0.f) + { + osg::Plane gravityPlane(mCachedWorldDirection, mCachedWorldPosition); + float distance = std::abs(gravityPlane.distance(particle->getPosition())); + decayFactor = std::exp(-1.f * mDecay * distance); + } + + particle->addVelocity(mCachedWorldDirection * mForce * dt * decayFactor * magic); + break; + } case Type_Point: { - osg::Vec3f diff = mCachedWorldPositionDirection - particle->getPosition(); + osg::Vec3f diff = mCachedWorldPosition - particle->getPosition(); + + float decayFactor = 1.f; + if (mDecay != 0.f) + decayFactor = std::exp(-1.f * mDecay * diff.length()); + diff.normalize(); - particle->addVelocity(diff * mForce * dt * magic); + + particle->addVelocity(diff * mForce * dt * decayFactor * magic); break; } } - - // velocity *= e^-[(dist/decay)^2] } Emitter::Emitter() diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 99db3c83aa..416477cddb 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -169,7 +169,9 @@ namespace NifOsg ForceType mType; osg::Vec3f mPosition; osg::Vec3f mDirection; - osg::Vec3f mCachedWorldPositionDirection; + float mDecay; + osg::Vec3f mCachedWorldPosition; + osg::Vec3f mCachedWorldDirection; }; // NodeVisitor to find a child node with the given record index, stored in the node's user data container. From 4ea6d4aa0107b95a0ec0655ba1c3e88458baea9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 16:02:40 +0200 Subject: [PATCH 0136/1812] Rewrite of skinning code Goals: - get rid of the mesh pre-transform (this requires supporting different bind matrices for each mesh) - bounding box should be relative to the bone the mesh is attached to, ideally we can then get rid of the expensive skeleton-based bounding boxes - update bone matrices in CullCallback instead of UpdateCallback Works OK, though the bounding boxes are not correct yet. --- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 345 +++++------------------------- components/nifosg/riggeometry.cpp | 201 +++++++++++++++++ components/nifosg/riggeometry.hpp | 56 +++++ components/nifosg/skeleton.cpp | 148 +++++++++++++ components/nifosg/skeleton.hpp | 58 +++++ 6 files changed, 520 insertions(+), 290 deletions(-) create mode 100644 components/nifosg/riggeometry.cpp create mode 100644 components/nifosg/riggeometry.hpp create mode 100644 components/nifosg/skeleton.cpp create mode 100644 components/nifosg/skeleton.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f61724eeb2..b49beea0b6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -47,7 +47,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle userdata + nifloader controller particle userdata skeleton riggeometry ) #add_component_dir (nifcache diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1f0c368390..f0bb538f2d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include + #include // resource @@ -14,11 +17,7 @@ #include // skel -#include -#include -#include #include -#include // particle #include @@ -45,6 +44,8 @@ #include "particle.hpp" #include "userdata.hpp" +#include "skeleton.hpp" +#include "riggeometry.hpp" namespace { @@ -206,32 +207,6 @@ namespace } }; - // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. - // Must be set on a Bone. - class UpdateBone : public osg::NodeCallback - { - public: - UpdateBone() {} - UpdateBone(const UpdateBone& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) - { - } - - META_Object(NifOsg, UpdateBone) - - // Callback method called by the NodeVisitor when visiting a node. - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgAnimation::Bone* b = static_cast(node); - osgAnimation::Bone* parent = b->getBoneParent(); - if (parent) - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); - else - b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); - traverse(node,nv); - } - }; - // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. class BillboardCallback : public osg::NodeCallback @@ -304,7 +279,7 @@ namespace for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - if (dynamic_cast(*it)) + if (dynamic_cast(*it)) { path.erase(path.begin(), it+1); // the bone's transform in skeleton space @@ -357,95 +332,6 @@ namespace }; */ - // Node callback used to dirty a RigGeometry's bounding box every frame, so that RigBoundingBoxCallback updates. - // This has to be attached to the geode, because the RigGeometry's Drawable::UpdateCallback is already used internally and not extensible. - // Kind of awful, not sure of a better way to do this. - class DirtyBoundCallback : public osg::NodeCallback - { - public: - DirtyBoundCallback() - { - } - DirtyBoundCallback(const DirtyBoundCallback& copy, const osg::CopyOp& copyop) - : osg::NodeCallback(copy, copyop) - { - } - - META_Object(NifOsg, DirtyBoundCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osg::Geode* geode = node->asGeode(); - if (geode && geode->getNumDrawables()) - { - geode->getDrawable(0)->dirtyBound(); - } - traverse(node, nv); - } - }; - - struct FindNearestParentSkeleton : public osg::NodeVisitor - { - osg::ref_ptr _root; - FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} - void apply(osg::Transform& node) - { - if (_root.valid()) - return; - _root = dynamic_cast(&node); - traverse(node); - } - }; - - // RigGeometry is skinned from a CullCallback to prevent unnecessary updates of culled rig geometries. - // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. - struct UpdateRigGeometry : public osg::Drawable::CullCallback - { - UpdateRigGeometry() - { - } - - UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - { - } - - META_Object(NifOsg, UpdateRigGeometry) - - virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const - { - osgAnimation::RigGeometry* geom = static_cast(drw); - if (!geom) - return false; - if (!geom->getSkeleton() && !geom->getParents().empty()) - { - FindNearestParentSkeleton finder; - if (geom->getParents().size() > 1) - osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; - geom->getParents()[0]->accept(finder); - - if (!finder._root.valid()) - { - osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; - return false; - } - geom->buildVertexInfluenceSet(); - geom->setSkeleton(finder._root.get()); - } - - if (!geom->getSkeleton()) - return false; - - if (geom->getNeedToComputeMatrix()) - geom->computeMatrixFromRootSkeleton(); - - geom->update(); - - return false; - } - }; - - // Same for MorphGeometry struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() @@ -500,88 +386,6 @@ namespace osg::BoundingBox mBoundingBox; }; - class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback - { - public: - RigBoundingBoxCallback() - : mBoneMapInit(false) - { - } - RigBoundingBoxCallback(const RigBoundingBoxCallback& copy, const osg::CopyOp& copyop) - : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) - , mBoneMapInit(false) - , mBoundSpheres(copy.mBoundSpheres) - { - } - - META_Object(NifOsg, RigBoundingBoxCallback) - - void addBoundSphere(const std::string& bonename, const osg::BoundingSphere& sphere) - { - mBoundSpheres[bonename] = sphere; - } - - virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const - { - osg::BoundingBox box; - - const osgAnimation::RigGeometry* rig = dynamic_cast(&drawable); - if (!rig) - { - std::cerr << "Warning: RigBoundingBoxCallback set on non-rig" << std::endl; - return box; - } - - if (!mBoneMapInit) - { - initBoneMap(rig); - } - - for (std::map::const_iterator it = mBoneMap.begin(); - it != mBoneMap.end(); ++it) - { - osgAnimation::Bone* bone = it->first; - osg::BoundingSphere bs = it->second; - SceneUtil::transformBoundingSphere(bone->getMatrixInSkeletonSpace(), bs); - box.expandBy(bs); - } - - return box; - } - - void initBoneMap(const osgAnimation::RigGeometry* rig) const - { - if (!rig->getSkeleton()) - { - // may happen before the first frame update, but we're not animating yet, so no need for a bounding box - return; - } - - osgAnimation::BoneMapVisitor mapVisitor; - { - // const_cast necessary because there does not seem to be a const variant of NodeVisitor. - // Don't worry, we're not actually changing the skeleton. - osgAnimation::Skeleton* skel = const_cast(rig->getSkeleton()); - skel->accept(mapVisitor); - } - - for (osgAnimation::BoneMap::const_iterator it = mapVisitor.getBoneMap().begin(); it != mapVisitor.getBoneMap().end(); ++it) - { - std::map::const_iterator found = mBoundSpheres.find(it->first); - if (found != mBoundSpheres.end()) // not all bones have to be used for skinning - mBoneMap[it->second.get()] = found->second; - } - - mBoneMapInit = true; - } - - private: - mutable bool mBoneMapInit; - mutable std::map mBoneMap; - - std::map mBoundSpheres; - }; - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -731,8 +535,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr skel = new osgAnimation::Skeleton; - skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy + osg::ref_ptr skel = new Skeleton; handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); skel->getOrCreateUserDataContainer()->addUserObject(textkeys); @@ -762,18 +565,8 @@ namespace NifOsg static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode; - if (createSkeleton) - { - osgAnimation::Bone* bone = new osgAnimation::Bone; - transformNode = bone; - bone->setMatrix(toMatrix(nifNode->trafo)); - bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); - } - else - { - transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); - } + osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + if (nifNode->recType == Nif::RC_NiBillboardNode) { transformNode->addCullCallback(new BillboardCallback); @@ -870,10 +663,6 @@ namespace NifOsg if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); - // Added last so the changes from KeyframeControllers are taken into account - if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) - bone->addUpdateCallback(new UpdateBone); - const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -1219,49 +1008,6 @@ namespace NifOsg { const Nif::NiTriShapeData* data = triShape->data.getPtr(); - const Nif::NiSkinInstance *skin = (triShape->skin.empty() ? NULL : triShape->skin.getPtr()); - if (skin) - { - // 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. - osg::ref_ptr newVerts (new osg::Vec3Array(data->vertices.size())); - osg::ref_ptr newNormals (new osg::Vec3Array(data->normals.size())); - - const Nif::NiSkinData *skinData = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - osg::Matrixf mat = toMatrix(skinData->bones[b].trafo); - - mat = mat * getWorldTransform(bones[b].getPtr()); - - const std::vector &weights = skinData->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - osg::Vec4f mult = (osg::Vec4f(data->vertices.at(index),1.f) * mat) * weight; - (*newVerts)[index] += osg::Vec3f(mult.x(),mult.y(),mult.z()); - if(newNormals->size() > index) - { - osg::Vec4 normal(data->normals[index].x(), data->normals[index].y(), data->normals[index].z(), 0.f); - normal = (normal * mat) * weight; - (*newNormals)[index] += osg::Vec3f(normal.x(),normal.y(),normal.z()); - } - } - } - // Interpolating normalized normals doesn't necessarily give you a normalized result - // Currently we're using GL_NORMALIZE, so this isn't needed - //for (unsigned int i=0;isize();++i) - // (*newNormals)[i].normalize(); - - geometry->setVertexArray(newVerts); - if (!data->normals.empty()) - geometry->setNormalArray(newNormals, osg::Array::BIND_PER_VERTEX); - } - else { geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); if (!data->normals.empty()) @@ -1397,6 +1143,24 @@ namespace NifOsg return morphGeom; } + class BoundingBoxCallback : public osg::NodeCallback + { + public: + virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) + { + osg::BoundingBox bb = mDrawable->getBound(); + + static_cast(node)->setMatrix( + osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), bb.zMax()-bb.zMin()) * + osg::Matrix::translate(bb.center()) ); + + traverse(node, nv); + } + + osg::Drawable* mDrawable; + }; + + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1404,21 +1168,13 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - // Note the RigGeometry's UpdateCallback uses the skeleton space bone matrix, so the bone UpdateCallback has to be fired first. - // For this to work properly, all bones used for skinning a RigGeometry need to be created before that RigGeometry. - // All NIFs I've checked seem to conform to this restriction, perhaps Gamebryo update method works similarly. - // If a file violates this assumption, the worst that could happen is the bone position being a frame late. - // If this happens, we should get a warning from the Skeleton's validation update callback on the error log. - osg::ref_ptr rig(new osgAnimation::RigGeometry); + osg::ref_ptr rig(new RigGeometry); rig->setSourceGeometry(geometry); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); - RigBoundingBoxCallback* callback = new RigBoundingBoxCallback; - rig->setComputeBoundingBoxCallback(callback); - // Assign bone weights - osg::ref_ptr map (new osgAnimation::VertexInfluenceMap); + osg::ref_ptr map (new RigGeometry::InfluenceMap); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; @@ -1426,34 +1182,42 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; - callback->addBoundSphere(boneName, osg::BoundingSphere(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius)); - - osgAnimation::VertexInfluence influence; - influence.setName(boneName); + RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; - influence.reserve(weights.size()); + //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { - osgAnimation::VertexIndexWeight indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); - influence.push_back(indexWeight); + std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + influence.mWeights.insert(indexWeight); } + influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); - map->insert(std::make_pair(boneName, influence)); + map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - // Override default update using cull callback instead for efficiency. - rig->setUpdateCallback(NULL); - rig->setCullCallback(new UpdateRigGeometry); - - osg::ref_ptr trans(new osg::MatrixTransform); - trans->setUpdateCallback(new InvertBoneMatrix()); + rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(geometry->getBound())); geode->addDrawable(rig); - geode->addUpdateCallback(new DirtyBoundCallback); + + // World bounding box callback & node + osg::ref_ptr bbcb = new BoundingBoxCallback; + bbcb->mDrawable = rig; + + osg::ref_ptr geode2 = new osg::Geode; + geode2->addDrawable( new osg::ShapeDrawable(new osg::Box) ); + + osg::ref_ptr boundingBoxNode = new osg::MatrixTransform; + boundingBoxNode->addChild( geode2.get() ); + boundingBoxNode->addUpdateCallback( bbcb.get() ); + boundingBoxNode->getOrCreateStateSet()->setAttributeAndModes( + new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE) ); + boundingBoxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost + /* rig->setDataVariance(osg::Object::STATIC); osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); @@ -1463,7 +1227,10 @@ namespace NifOsg frameswitch->addChild(geode2); trans->addChild(frameswitch); - parentNode->addChild(trans); + */ + + parentNode->addChild(geode); + parentNode->addChild(boundingBoxNode); } diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp new file mode 100644 index 0000000000..8283caa234 --- /dev/null +++ b/components/nifosg/riggeometry.cpp @@ -0,0 +1,201 @@ +#include "riggeometry.hpp" + +#include +#include + +#include + +#include + +#include "skeleton.hpp" + +#include + +namespace NifOsg +{ + +// TODO: make threadsafe for multiple cull threads +class UpdateRigGeometry : public osg::Drawable::CullCallback +{ +public: + UpdateRigGeometry() + { + } + + UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) + : osg::Drawable::CullCallback(copy, copyop) + { + } + + META_Object(NifOsg, UpdateRigGeometry) + + virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const + { + RigGeometry* geom = static_cast(drw); + geom->update(nv); + return false; + } +}; + +RigGeometry::RigGeometry() +{ + setCullCallback(new UpdateRigGeometry); + setSupportsDisplayList(false); +} + +RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) + : osg::Geometry(copy, copyop) + , mInfluenceMap(copy.mInfluenceMap) + , mSourceGeometry(copy.mSourceGeometry) +{ + //setVertexArray(dynamic_cast(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); + //setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); +} + +void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) +{ + mSourceGeometry = sourceGeometry; + + osg::Geometry& from = *sourceGeometry; + + if (from.getStateSet()) + setStateSet(from.getStateSet()); + + // copy over primitive sets. + getPrimitiveSetList() = from.getPrimitiveSetList(); + + if (from.getColorArray()) + setColorArray(from.getColorArray()); + + if (from.getSecondaryColorArray()) + setSecondaryColorArray(from.getSecondaryColorArray()); + + if (from.getFogCoordArray()) + setFogCoordArray(from.getFogCoordArray()); + + for(unsigned int ti=0;ti(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); + setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); +} + +bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) +{ + const osg::NodePath& path = nv->getNodePath(); + for (osg::NodePath::const_reverse_iterator it = path.rbegin(); it != path.rend(); ++it) + { + osg::Node* node = *it; + if (Skeleton* skel = dynamic_cast(node)) + { + mSkeleton = skel; + break; + } + } + + if (!mSkeleton) + { + std::cerr << "A RigGeometry did not find its parent skeleton" << std::endl; + return false; + } + + // geometryToSkel = nv->getNodePath()... + + if (!mInfluenceMap) + { + std::cerr << "No InfluenceMap set on RigGeometry" << std::endl; + return false; + } + + for (std::map::const_iterator it = mInfluenceMap->mMap.begin(); it != mInfluenceMap->mMap.end(); ++it) + { + Bone* b = mSkeleton->getBone(it->first); + if (!b) + { + std::cerr << "RigGeometry did not find bone " << it->first << std::endl; + } + + mResolvedInfluenceMap[b] = it->second; + } + return true; +} + +void RigGeometry::update(osg::NodeVisitor* nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + mSkeleton->updateBoneMatrices(); + + osg::NodePath path; + bool foundSkel = false; + for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) + { + if (!foundSkel) + { + if (*it == mSkeleton) + foundSkel = true; + } + else + path.push_back(*it); + } + osg::Matrix geomToSkel = osg::computeWorldToLocal(path); + + // skinning + osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); + + osg::Vec3Array* positionDst = static_cast(getVertexArray()); + osg::Vec3Array* normalDst = static_cast(getNormalArray()); + + for (unsigned int i=0; isize(); ++i) + (*positionDst)[i] = osg::Vec3f(0,0,0); + for (unsigned int i=0; isize(); ++i) + (*normalDst)[i] = osg::Vec3f(0,0,0); + + for (ResolvedInfluenceMap::const_iterator it = mResolvedInfluenceMap.begin(); it != mResolvedInfluenceMap.end(); ++it) + { + const BoneInfluence& bi = it->second; + Bone* bone = it->first; + + // Here we could cache the (weighted) matrix for each combination of bone weights + + osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; + + for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + { + short vertex = weightIt->first; + float weight = weightIt->second; + + osg::Vec3f a = (*positionSrc)[vertex]; + + (*positionDst)[vertex] += finalMatrix.preMult(a) * weight; + (*normalDst)[vertex] += osg::Matrix::transform3x3((*normalSrc)[vertex], finalMatrix) * weight; + } + } + + positionDst->dirty(); + normalDst->dirty(); +} + +void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) +{ + mInfluenceMap = influenceMap; +} + + +} diff --git a/components/nifosg/riggeometry.hpp b/components/nifosg/riggeometry.hpp new file mode 100644 index 0000000000..7c8ea83bc2 --- /dev/null +++ b/components/nifosg/riggeometry.hpp @@ -0,0 +1,56 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H +#define OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H + +#include +#include + +namespace NifOsg +{ + + class Skeleton; + class Bone; + + class RigGeometry : public osg::Geometry + { + public: + RigGeometry(); + RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, RigGeometry) + + struct BoneInfluence + { + osg::Matrixf mInvBindMatrix; + // + std::map mWeights; + }; + + + struct InfluenceMap : public osg::Referenced + { + std::map mMap; + }; + + void setInfluenceMap(osg::ref_ptr influenceMap); + + void setSourceGeometry(osg::ref_ptr sourceGeom); + + // Called automatically by our CullCallback + void update(osg::NodeVisitor* nv); + + + private: + osg::ref_ptr mSourceGeometry; + osg::ref_ptr mSkeleton; + + osg::ref_ptr mInfluenceMap; + + typedef std::map ResolvedInfluenceMap; + ResolvedInfluenceMap mResolvedInfluenceMap; + + bool initFromParentSkeleton(osg::NodeVisitor* nv); + }; + +} + +#endif diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp new file mode 100644 index 0000000000..26c6e80b3f --- /dev/null +++ b/components/nifosg/skeleton.cpp @@ -0,0 +1,148 @@ +#include "skeleton.hpp" + +#include +#include + +#include + +namespace NifOsg +{ + +class InitBoneCacheVisitor : public osg::NodeVisitor +{ +public: + InitBoneCacheVisitor(std::map >& cache) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mCache(cache) + { + } + + void apply(osg::Transform &node) + { + osg::MatrixTransform* bone = node.asMatrixTransform(); + if (!bone) + return; + + mCache[bone->getName()] = std::make_pair(getNodePath(), bone); + + traverse(node); + } +private: + std::map >& mCache; +}; + +Skeleton::Skeleton() + : mBoneCacheInit(false) + , mNeedToUpdateBoneMatrices(true) +{ + +} + +Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) + : mBoneCacheInit(false) + , mNeedToUpdateBoneMatrices(true) +{ + +} + + + +Bone* Skeleton::getBone(const std::string &name) +{ + if (!mBoneCacheInit) + { + InitBoneCacheVisitor visitor(mBoneCache); + accept(visitor); + mBoneCacheInit = true; + } + + BoneCache::iterator found = mBoneCache.find(name); + if (found == mBoneCache.end()) + return NULL; + + // find or insert in the bone hierarchy + + if (!mRootBone.get()) + { + mRootBone.reset(new Bone); + } + + const osg::NodePath& path = found->second.first; + Bone* bone = mRootBone.get(); + for (osg::NodePath::const_iterator it = path.begin(); it != path.end(); ++it) + { + osg::MatrixTransform* matrixTransform = dynamic_cast(*it); + if (!matrixTransform) + continue; + + Bone* child = NULL; + for (unsigned int i=0; imChildren.size(); ++i) + { + if (bone->mChildren[i]->mNode == *it) + { + child = bone->mChildren[i]; + break; + } + } + + if (!child) + { + child = new Bone; + bone->mChildren.push_back(child); + mNeedToUpdateBoneMatrices = true; + } + bone = child; + + bone->mNode = matrixTransform; + } + + return bone; +} + +void Skeleton::updateBoneMatrices() +{ + //if (mNeedToUpdateBoneMatrices) + { + + if (mRootBone.get()) + { + for (unsigned int i=0; imChildren.size(); ++i) + mRootBone->mChildren[i]->update(NULL); + } + else + std::cerr << "no root bone" << std::endl; + + mNeedToUpdateBoneMatrices = false; + } +} + +Bone::Bone() + : mNode(NULL) +{ +} + +Bone::~Bone() +{ + for (unsigned int i=0; igetMatrix() * (*parentMatrixInSkeletonSpace); + else + mMatrixInSkeletonSpace = mNode->getMatrix(); + + for (unsigned int i=0; iupdate(&mMatrixInSkeletonSpace); + } +} + +} diff --git a/components/nifosg/skeleton.hpp b/components/nifosg/skeleton.hpp new file mode 100644 index 0000000000..f006ca84b2 --- /dev/null +++ b/components/nifosg/skeleton.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_SKELETON_H +#define OPENMW_COMPONENTS_NIFOSG_SKELETON_H + +#include + +#include + +namespace NifOsg +{ + + // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. + // To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. + class Bone + { + public: + Bone(); + ~Bone(); + + osg::Matrix mMatrixInSkeletonSpace; + + osg::MatrixTransform* mNode; + + std::vector mChildren; + + void update(const osg::Matrixf* parentMatrixInSkeletonSpace); + + private: + Bone(const Bone&); + void operator=(const Bone&); + }; + + class Skeleton : public osg::Group + { + public: + Skeleton(); + Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); + + Bone* getBone(const std::string& name); + + META_Node(NifOsg, Skeleton) + + void updateBoneMatrices(); + + private: + // The root bone is not a "real" bone, it has no corresponding node in the scene graph. + // As far as the scene graph goes we support multiple root bones. + std::auto_ptr mRootBone; + + typedef std::map > BoneCache; + BoneCache mBoneCache; + bool mBoneCacheInit; + + bool mNeedToUpdateBoneMatrices; + }; + +} + +#endif From c53a56ed6eac74704c846af834d597997493cfaa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 16:10:11 +0200 Subject: [PATCH 0137/1812] clear stream errors before attempting the read --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 +++- extern/osg-ffmpeg-videoplayer/videostate.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 55607b5b72..6a586e81d5 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -31,8 +31,8 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) try { std::istream& stream = *static_cast(user_data)->mDataStream; - stream.read((char*)buf, buf_size); stream.clear(); + stream.read((char*)buf, buf_size); return stream.gcount(); } catch (std::exception& ) @@ -52,6 +52,8 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) whence &= ~AVSEEK_FORCE; + stream.clear(); + if(whence == AVSEEK_SIZE) { size_t prev = stream.tellg(); diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 6a054d99e6..72fc82f860 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -173,8 +173,8 @@ int VideoState::istream_read(void *user_data, uint8_t *buf, int buf_size) try { std::istream& stream = *static_cast(user_data)->stream; - stream.read((char*)buf, buf_size); stream.clear(); + stream.read((char*)buf, buf_size); return stream.gcount(); } catch (std::exception& ) @@ -194,6 +194,8 @@ int64_t VideoState::istream_seek(void *user_data, int64_t offset, int whence) whence &= ~AVSEEK_FORCE; + stream.clear(); + if(whence == AVSEEK_SIZE) { size_t prev = stream.tellg(); From 111e3eb6db5580bc110f83bdfd9852b6244872a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 18:29:28 +0200 Subject: [PATCH 0138/1812] Slightly improve bounding box for skinned meshes --- components/nifosg/nifloader.cpp | 36 ++++++++++++------------------- components/nifosg/riggeometry.cpp | 6 +----- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f0bb538f2d..eb78a0632f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1196,28 +1196,24 @@ namespace NifOsg } rig->setInfluenceMap(map); - rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(geometry->getBound())); + // Compute the bounding box + osg::BoundingBox boundingBox; + + osg::Matrix worldTrans = getWorldTransform(triShape); + for(size_t i = 0;i < bones.length();i++) + { + osg::BoundingSphere boneSphere (data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); + osg::Matrix boneWorldTrans(getWorldTransform(bones[i].getPtr())); + osg::Matrix mat = boneWorldTrans * worldTrans.inverse(worldTrans); + SceneUtil::transformBoundingSphere(mat, boneSphere); + boundingBox.expandBy(boneSphere); + } + rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(boundingBox)); geode->addDrawable(rig); - // World bounding box callback & node - osg::ref_ptr bbcb = new BoundingBoxCallback; - bbcb->mDrawable = rig; - - osg::ref_ptr geode2 = new osg::Geode; - geode2->addDrawable( new osg::ShapeDrawable(new osg::Box) ); - - osg::ref_ptr boundingBoxNode = new osg::MatrixTransform; - boundingBoxNode->addChild( geode2.get() ); - boundingBoxNode->addUpdateCallback( bbcb.get() ); - boundingBoxNode->getOrCreateStateSet()->setAttributeAndModes( - new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE) ); - boundingBoxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); - - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost - /* rig->setDataVariance(osg::Object::STATIC); osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); @@ -1226,11 +1222,7 @@ namespace NifOsg frameswitch->addChild(geode); frameswitch->addChild(geode2); - trans->addChild(frameswitch); - */ - - parentNode->addChild(geode); - parentNode->addChild(boundingBoxNode); + parentNode->addChild(frameswitch); } diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp index 8283caa234..37fee1f515 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/nifosg/riggeometry.cpp @@ -46,10 +46,8 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mInfluenceMap(copy.mInfluenceMap) - , mSourceGeometry(copy.mSourceGeometry) { - //setVertexArray(dynamic_cast(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL))); - //setNormalArray(dynamic_cast(from.getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL)), osg::Array::BIND_PER_VERTEX); + setSourceGeometry(copy.mSourceGeometry); } void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) @@ -110,8 +108,6 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return false; } - // geometryToSkel = nv->getNodePath()... - if (!mInfluenceMap) { std::cerr << "No InfluenceMap set on RigGeometry" << std::endl; From bd88758962628219f1912a12bd96b52f423e1028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 18:52:13 +0200 Subject: [PATCH 0139/1812] Use the new skinning system in OpenMW --- components/nifosg/skeleton.cpp | 3 +- components/sceneutil/attach.cpp | 136 ++++--------------------------- components/sceneutil/visitor.hpp | 9 +- 3 files changed, 24 insertions(+), 124 deletions(-) diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp index 26c6e80b3f..2e00eb76e3 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/nifosg/skeleton.cpp @@ -39,7 +39,8 @@ Skeleton::Skeleton() } Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) - : mBoneCacheInit(false) + : osg::Group(copy, copyop) + , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) { diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 26185eb3ed..b88bddc8df 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -8,155 +8,55 @@ #include #include #include - -#include -#include +#include #include +#include + #include "visitor.hpp" namespace SceneUtil { - class NodeMapVisitor : public osg::NodeVisitor + class CopyRigVisitor : public osg::NodeVisitor { public: - NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - void apply(osg::MatrixTransform& trans) - { - mMap[trans.getName()] = &trans; - traverse(trans); - } - - typedef std::map > NodeMap; - - const NodeMap& getNodeMap() const - { - return mMap; - } - - private: - NodeMap mMap; - }; - - /// Copy the matrix of a "source" node to a "dest" node (the node that the callback is attached to). - /// Must be set on a MatrixTransform. - class CopyController : public osg::NodeCallback - { - public: - CopyController(osg::MatrixTransform* copyFrom) - : mCopyFrom(copyFrom) - { - } - CopyController(const CopyController& copy, const osg::CopyOp& copyop) - : osg::NodeCallback(copy, copyop) - , mCopyFrom(copy.mCopyFrom) - { - } - CopyController() - : mCopyFrom(NULL) - { - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgAnimation::Bone* bone = static_cast(node); - - if (mCopyFrom) - { - bone->setMatrix(mCopyFrom->getMatrix()); - } - - traverse(node, nv); - } - - private: - const osg::MatrixTransform* mCopyFrom; - }; - - class AddCopyControllerVisitor : public osg::NodeVisitor - { - public: - AddCopyControllerVisitor(const NodeMapVisitor::NodeMap& boneMap) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mNodeMap(boneMap) - { - } - - virtual void apply(osg::MatrixTransform &node) - { - if (osgAnimation::Bone* bone = dynamic_cast(&node)) - { - NodeMapVisitor::NodeMap::const_iterator found = mNodeMap.find(bone->getName()); - if (found != mNodeMap.end()) - { - // add the CopyController at position 0 so it's executed before UpdateBone - osg::ref_ptr old = bone->getUpdateCallback(); - bone->setUpdateCallback(new CopyController(found->second.get())); - bone->addUpdateCallback(old); - } - } - traverse(node); - } - - private: - const NodeMapVisitor::NodeMap& mNodeMap; - }; - - // FIXME: would be more efficient to copy only the wanted nodes instead of deleting unwanted ones later - // copying is kinda cheap though, so don't bother for now - class FilterVisitor : public osg::NodeVisitor - { - public: - FilterVisitor(const std::string& filter) + CopyRigVisitor(osg::ref_ptr parent, const std::string& filter) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mParent(parent) , mFilter(Misc::StringUtils::lowerCase(filter)) { } - virtual void apply(osg::Geode &node) + virtual void apply(osg::Node& node) { std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); - if (lowerName.find(mFilter) == std::string::npos) + if (lowerName.find(mFilter) != std::string::npos) { - mToRemove.push_back(&node); - } - } - - void removeFilteredParts() - { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - osg::Geode* geode = *it; - geode->getParent(0)->removeChild(geode); + mParent->addChild(&node); } + else + traverse(node); } private: - std::vector mToRemove; + osg::ref_ptr mParent; std::string mFilter; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) { - if (osgAnimation::Skeleton* skel = dynamic_cast(toAttach.get())) + if (dynamic_cast(toAttach.get())) { - NodeMapVisitor nodeMapVisitor; - master->accept(nodeMapVisitor); + osg::ref_ptr handle = new osg::Group; - // would be more efficient if we could attach the RigGeometry directly to the master skeleton, but currently not possible - // due to a difference in binding pose of the two skeletons - AddCopyControllerVisitor visitor(nodeMapVisitor.getNodeMap()); - toAttach->accept(visitor); + CopyRigVisitor copyVisitor(handle, filter); + toAttach->accept(copyVisitor); - FilterVisitor filterVisitor(filter); - toAttach->accept(filterVisitor); - filterVisitor.removeFilteredParts(); + master->asGroup()->addChild(handle); - master->asGroup()->addChild(skel); - return skel; + return handle; } else { diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index d26f95116d..6bb8b2e357 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -17,15 +17,14 @@ namespace SceneUtil { } - virtual void apply(osg::Node &node) + virtual void apply(osg::Group& group) { - osg::Group* group = node.asGroup(); - if (group && node.getName() == mNameToFind) + if (group.getName() == mNameToFind) { - mFoundNode = group; + mFoundNode = &group; return; } - traverse(node); + traverse(group); } std::string mNameToFind; From 9246a668b9932cb3ebd217799c72430b7a3aae5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:22:32 +0200 Subject: [PATCH 0140/1812] Skeleton update fix --- components/nifosg/riggeometry.cpp | 2 +- components/nifosg/skeleton.cpp | 12 +++++++++--- components/nifosg/skeleton.hpp | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/nifosg/riggeometry.cpp b/components/nifosg/riggeometry.cpp index 37fee1f515..0217a7ac00 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/nifosg/riggeometry.cpp @@ -135,7 +135,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - mSkeleton->updateBoneMatrices(); + mSkeleton->updateBoneMatrices(nv); osg::NodePath path; bool foundSkel = false; diff --git a/components/nifosg/skeleton.cpp b/components/nifosg/skeleton.cpp index 2e00eb76e3..b9d113d341 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/nifosg/skeleton.cpp @@ -34,6 +34,7 @@ private: Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) + , mLastFrameNumber(0) { } @@ -42,6 +43,7 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) + , mLastFrameNumber(0) { } @@ -100,11 +102,15 @@ Bone* Skeleton::getBone(const std::string &name) return bone; } -void Skeleton::updateBoneMatrices() +void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) { - //if (mNeedToUpdateBoneMatrices) - { + if (nv->getFrameStamp()->getFrameNumber() != mLastFrameNumber) + mNeedToUpdateBoneMatrices = true; + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + + if (mNeedToUpdateBoneMatrices) + { if (mRootBone.get()) { for (unsigned int i=0; imChildren.size(); ++i) diff --git a/components/nifosg/skeleton.hpp b/components/nifosg/skeleton.hpp index f006ca84b2..5344f9f5df 100644 --- a/components/nifosg/skeleton.hpp +++ b/components/nifosg/skeleton.hpp @@ -39,7 +39,7 @@ namespace NifOsg META_Node(NifOsg, Skeleton) - void updateBoneMatrices(); + void updateBoneMatrices(osg::NodeVisitor* nv); private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. @@ -51,6 +51,8 @@ namespace NifOsg bool mBoneCacheInit; bool mNeedToUpdateBoneMatrices; + + unsigned int mLastFrameNumber; }; } From eaa4316ff86589e5c01ccdc2b4820cf3dfd150e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:30:48 +0200 Subject: [PATCH 0141/1812] Move skinning code to SceneUtil --- components/CMakeLists.txt | 4 ++-- components/nifosg/nifloader.cpp | 14 +++++++------- components/sceneutil/attach.cpp | 4 ++-- components/{nifosg => sceneutil}/riggeometry.cpp | 2 +- components/{nifosg => sceneutil}/riggeometry.hpp | 2 +- components/{nifosg => sceneutil}/skeleton.cpp | 2 +- components/{nifosg => sceneutil}/skeleton.hpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) rename components/{nifosg => sceneutil}/riggeometry.cpp (99%) rename components/{nifosg => sceneutil}/riggeometry.hpp (98%) rename components/{nifosg => sceneutil}/skeleton.cpp (99%) rename components/{nifosg => sceneutil}/skeleton.hpp (98%) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b49beea0b6..75f6756f87 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry ) add_component_dir (nif @@ -47,7 +47,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle userdata skeleton riggeometry + nifloader controller particle userdata ) #add_component_dir (nifcache diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index eb78a0632f..301c487da4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -41,11 +41,11 @@ #include #include +#include +#include #include "particle.hpp" #include "userdata.hpp" -#include "skeleton.hpp" -#include "riggeometry.hpp" namespace { @@ -279,7 +279,7 @@ namespace for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) { - if (dynamic_cast(*it)) + if (dynamic_cast(*it)) { path.erase(path.begin(), it+1); // the bone's transform in skeleton space @@ -535,7 +535,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr skel = new Skeleton; + osg::ref_ptr skel = new SceneUtil::Skeleton; handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); skel->getOrCreateUserDataContainer()->addUserObject(textkeys); @@ -1168,13 +1168,13 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); - osg::ref_ptr rig(new RigGeometry); + osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); // Assign bone weights - osg::ref_ptr map (new RigGeometry::InfluenceMap); + osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; @@ -1182,7 +1182,7 @@ namespace NifOsg { std::string boneName = bones[i].getPtr()->name; - RigGeometry::BoneInfluence influence; + SceneUtil::RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index b88bddc8df..9f9d63619c 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include "visitor.hpp" @@ -47,7 +47,7 @@ namespace SceneUtil osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) { - if (dynamic_cast(toAttach.get())) + if (dynamic_cast(toAttach.get())) { osg::ref_ptr handle = new osg::Group; diff --git a/components/nifosg/riggeometry.cpp b/components/sceneutil/riggeometry.cpp similarity index 99% rename from components/nifosg/riggeometry.cpp rename to components/sceneutil/riggeometry.cpp index 0217a7ac00..00f80c8297 100644 --- a/components/nifosg/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -11,7 +11,7 @@ #include -namespace NifOsg +namespace SceneUtil { // TODO: make threadsafe for multiple cull threads diff --git a/components/nifosg/riggeometry.hpp b/components/sceneutil/riggeometry.hpp similarity index 98% rename from components/nifosg/riggeometry.hpp rename to components/sceneutil/riggeometry.hpp index 7c8ea83bc2..e99bc757e2 100644 --- a/components/nifosg/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -4,7 +4,7 @@ #include #include -namespace NifOsg +namespace SceneUtil { class Skeleton; diff --git a/components/nifosg/skeleton.cpp b/components/sceneutil/skeleton.cpp similarity index 99% rename from components/nifosg/skeleton.cpp rename to components/sceneutil/skeleton.cpp index b9d113d341..c1ab36136b 100644 --- a/components/nifosg/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -5,7 +5,7 @@ #include -namespace NifOsg +namespace SceneUtil { class InitBoneCacheVisitor : public osg::NodeVisitor diff --git a/components/nifosg/skeleton.hpp b/components/sceneutil/skeleton.hpp similarity index 98% rename from components/nifosg/skeleton.hpp rename to components/sceneutil/skeleton.hpp index 5344f9f5df..c241844f11 100644 --- a/components/nifosg/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -5,7 +5,7 @@ #include -namespace NifOsg +namespace SceneUtil { // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. From 10644544ab22c433eea6f5e9dcad6ffa862193b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:31:20 +0200 Subject: [PATCH 0142/1812] Dead code removal --- components/nifosg/nifloader.cpp | 41 --------------------------------- 1 file changed, 41 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 301c487da4..b28412cb68 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -253,47 +253,6 @@ namespace } }; - // NodeCallback used to set the inverse of the parent bone's matrix in skeleton space - // on the MatrixTransform that the NodeCallback is attached to. This is used so we can - // attach skinned meshes to their actual parent node, while still having the skinning - // work in skeleton space as expected. - // Must be set on a MatrixTransform. - class InvertBoneMatrix : public osg::NodeCallback - { - public: - InvertBoneMatrix() {} - - InvertBoneMatrix(const InvertBoneMatrix& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) {} - - META_Object(NifOsg, InvertBoneMatrix) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - osg::NodePath path = nv->getNodePath(); - path.pop_back(); - - osg::MatrixTransform* trans = dynamic_cast(node); - - for (osg::NodePath::iterator it = path.begin(); it != path.end(); ++it) - { - if (dynamic_cast(*it)) - { - path.erase(path.begin(), it+1); - // the bone's transform in skeleton space - osg::Matrix boneMat = osg::computeLocalToWorld( path ); - trans->setMatrix(osg::Matrix::inverse(boneMat)); - break; - } - } - } - traverse(node,nv); - } - }; - - // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files /* class LoadKfVisitor : public osg::NodeVisitor From 102eadf91c103867a6c86f8bb85599cd2edc1fb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:42:50 +0200 Subject: [PATCH 0143/1812] Add some comments --- components/sceneutil/riggeometry.hpp | 4 +++- components/sceneutil/skeleton.hpp | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e99bc757e2..70f2c6e7db 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -10,6 +10,9 @@ namespace SceneUtil class Skeleton; class Bone; + /// @brief Mesh skinning implementation. + /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. + /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. class RigGeometry : public osg::Geometry { public: @@ -25,7 +28,6 @@ namespace SceneUtil std::map mWeights; }; - struct InfluenceMap : public osg::Referenced { std::map mMap; diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index c241844f11..acb9e61363 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -8,8 +8,8 @@ namespace SceneUtil { - // Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. - // To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. + /// @brief Defines a Bone hierarchy, used for updating of skeleton-space bone matrices. + /// @note To prevent unnecessary updates, only bones that are used for skinning will be added to this hierarchy. class Bone { public: @@ -22,6 +22,7 @@ namespace SceneUtil std::vector mChildren; + /// Update the skeleton-space matrix of this bone and all its children. void update(const osg::Matrixf* parentMatrixInSkeletonSpace); private: @@ -29,16 +30,21 @@ namespace SceneUtil void operator=(const Bone&); }; + /// @brief Handles the bone matrices for any number of child RigGeometries. + /// @par Bones should be created as osg::MatrixTransform children of the skeleton. + /// To be a referenced by a RigGeometry, a bone needs to have a unique name. class Skeleton : public osg::Group { public: Skeleton(); Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); - Bone* getBone(const std::string& name); - META_Node(NifOsg, Skeleton) + /// Retrieve a bone by name. + Bone* getBone(const std::string& name); + + /// Request an update of bone matrices. May be a no-op if already updated in this frame. void updateBoneMatrices(osg::NodeVisitor* nv); private: From 28643660d3dbfb10c3c8613711606652f31b4263 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 20:56:16 +0200 Subject: [PATCH 0144/1812] Change triangle indices to unsigned --- components/nif/data.cpp | 2 +- components/nif/data.hpp | 4 ++-- components/nif/nifstream.cpp | 4 ++-- components/nif/nifstream.hpp | 2 +- components/nifosg/nifloader.cpp | 2 +- components/sceneutil/riggeometry.cpp | 4 ++-- components/sceneutil/riggeometry.hpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 3a06e40060..fc0631b841 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -71,7 +71,7 @@ void NiTriShapeData::read(NIFStream *nif) // 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); + nif->getUShorts(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 diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 1b4d02f26c..63dc42aded 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -48,7 +48,7 @@ class NiTriShapeData : public ShapeData { public: // Triangles, three vertex indices per triangle - std::vector triangles; + std::vector triangles; void read(NIFStream *nif); }; @@ -144,7 +144,7 @@ class NiSkinData : public Record public: struct VertWeight { - short vertex; + unsigned short vertex; float weight; }; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 628541933f..d0fc9bab03 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -103,11 +103,11 @@ std::string NIFStream::getVersionString() return result; } -void NIFStream::getShorts(std::vector &vec, size_t size) +void NIFStream::getUShorts(std::vector &vec, size_t size) { vec.resize(size); for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + vec[i] = getUShort(); } void NIFStream::getFloats(std::vector &vec, size_t size) { diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index b732c83af2..45733f48fe 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -59,7 +59,7 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - void getShorts(std::vector &vec, size_t size); + void getUShorts(std::vector &vec, size_t size); void getFloats(std::vector &vec, size_t size); void getVector2s(std::vector &vec, size_t size); void getVector3s(std::vector &vec, size_t size); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b28412cb68..f7f6af0ae6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1146,7 +1146,7 @@ namespace NifOsg //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { - std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); + std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 00f80c8297..4d4ea22d25 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -172,9 +172,9 @@ void RigGeometry::update(osg::NodeVisitor* nv) osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; - for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) { - short vertex = weightIt->first; + unsigned short vertex = weightIt->first; float weight = weightIt->second; osg::Vec3f a = (*positionSrc)[vertex]; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 70f2c6e7db..c77ff7c726 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -25,7 +25,7 @@ namespace SceneUtil { osg::Matrixf mInvBindMatrix; // - std::map mWeights; + std::map mWeights; }; struct InfluenceMap : public osg::Referenced From a254877abe7d51df387bee721524028e070dae39 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 22:53:28 +0200 Subject: [PATCH 0145/1812] Clone fix --- components/sceneutil/clone.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index f124d7de76..eb7e635879 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -6,9 +6,11 @@ #include #include #include -#include + #include +#include + namespace SceneUtil { @@ -45,7 +47,7 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable) + if (dynamic_cast(drawable) || dynamic_cast(drawable)) return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); From 9e177df61b1fe33140db6200328c32d2530e94c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:27:26 +0200 Subject: [PATCH 0146/1812] Add fog, view distance, and far plane culling --- apps/openmw/mwrender/renderingmanager.cpp | 54 +++++++++++++++++++++-- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 2 +- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 412d10ba2e..b7265533ca 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -5,10 +5,13 @@ #include #include #include +#include #include #include +#include + #include #include @@ -26,25 +29,49 @@ namespace MWRender class StateUpdater : public SceneUtil::StateSetUpdater { public: + StateUpdater() + : mFogEnd(0.f) + { + } + virtual void setDefaults(osg::StateSet *stateset) { osg::LightModel* lightModel = new osg::LightModel; stateset->setAttribute(lightModel, osg::StateAttribute::ON); + osg::Fog* fog = new osg::Fog; + fog->setStart(1); + stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { osg::LightModel* lightModel = static_cast(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); lightModel->setAmbientIntensity(mAmbientColor); + osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); + fog->setColor(mFogColor); + fog->setEnd(mFogEnd); + fog->setMode(osg::Fog::LINEAR); } - void setAmbientColor(osg::Vec4f col) + void setAmbientColor(const osg::Vec4f& col) { mAmbientColor = col; } + void setFogColor(const osg::Vec4f& col) + { + mFogColor = col; + } + + void setFogEnd(float end) + { + mFogEnd = end; + } + private: osg::Vec4f mAmbientColor; + osg::Vec4f mFogColor; + float mFogEnd; }; RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) @@ -80,16 +107,25 @@ namespace MWRender source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); mStateUpdater = new StateUpdater; - mRootNode->addUpdateCallback(mStateUpdater); + lightRoot->addUpdateCallback(mStateUpdater); + + osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; // for consistent benchmarks against the ogre branch. remove later - osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + viewer.getCamera()->setCullingMode( cullingMode ); + mViewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + mViewer.getCamera()->setCullingMode(cullingMode); + + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + double fovy, aspect, zNear, zFar; mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = 55.f; + zNear = 5.f; + zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); } @@ -153,9 +189,19 @@ namespace MWRender mSky->setEnabled(enabled); } - void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &colour) + void RenderingManager::configureFog(const ESM::Cell *cell) + { + osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); + + configureFog (cell->mAmbi.mFogDensity, color); + } + + void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) { mViewer.getCamera()->setClearColor(colour); + + mStateUpdater->setFogColor(colour); + mStateUpdater->setFogEnd(mViewDistance); } SkyManager* RenderingManager::getSkyManager() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 61f611a8c8..d8744db4ae 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -53,7 +53,7 @@ namespace MWRender void setSunColour(const osg::Vec4f& colour); void configureAmbient(const ESM::Cell* cell); - + void configureFog(const ESM::Cell* cell); void configureFog(float fogDepth, const osg::Vec4f& colour); void removeCell(const MWWorld::CellStore* store); @@ -87,6 +87,8 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mViewDistance; + void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c9fd84ee3b..aabe4d6d86 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -511,7 +511,7 @@ namespace MWWorld changePlayerCell(cell, position, true); // adjust fog - //mRendering.configureFog(*mCurrentCell); + mRendering.configureFog(mCurrentCell->getCell()); // Sky system MWBase::Environment::get().getWorld()->adjustSky(); From 26766b8e0a9b9979a64381fa935d01c336f95ab4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:35:35 +0200 Subject: [PATCH 0147/1812] Dead code removal --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 16 +- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +- apps/openmw/mwrender/debugging.hpp | 3 +- apps/openmw/mwworld/physicssystem.cpp | 5 +- apps/openmw/mwworld/physicssystem.hpp | 7 +- libs/openengine/CMakeLists.txt | 3 +- libs/openengine/ogre/renderer.cpp | 241 ------------------------- libs/openengine/ogre/renderer.hpp | 147 --------------- 9 files changed, 15 insertions(+), 413 deletions(-) delete mode 100644 libs/openengine/ogre/renderer.cpp delete mode 100644 libs/openengine/ogre/renderer.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fe61802991..68f4e82257 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -370,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, NULL, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 319e1d7ec9..4ae610f514 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -24,8 +24,6 @@ #include #include -#include - #include #include @@ -99,12 +97,10 @@ namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) //, mGuiManager(NULL) - , mRendering(ogre) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -838,7 +834,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mRendering->getWindow()->update(); + //mRendering->getWindow()->update(); } } } @@ -1714,6 +1710,7 @@ namespace MWGui } // Turn off all rendering except for the GUI + /* mRendering->getScene()->clearSpecialCaseRenderQueues(); // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work? for(int i = 0;i < Ogre::RENDER_QUEUE_MAX;++i) @@ -1722,6 +1719,7 @@ namespace MWGui mRendering->getScene()->addSpecialCaseRenderQueue(i); } mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + */ MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); @@ -1741,7 +1739,7 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mRendering->getWindow()->update(); + //mRendering->getWindow()->update(); } mVideoWidget->stop(); @@ -1750,8 +1748,8 @@ namespace MWGui setCursorVisible(cursorWasVisible); // Restore normal rendering - mRendering->getScene()->clearSpecialCaseRenderQueues(); - mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + //mRendering->getScene()->clearSpecialCaseRenderQueues(); + //mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); mVideoBackground->setVisible(false); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 297480d20f..ddb9368c57 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -99,8 +99,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, - OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, + WindowManager(const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -366,7 +365,6 @@ namespace MWGui CustomMarkerCollection mCustomMarkers; OEngine::GUI::MyGUIManager *mGuiManager; - OEngine::Render::OgreRenderer *mRendering; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 39be34cb02..e243318013 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -2,10 +2,10 @@ #define GAME_RENDER_MWSCENE_H #include -#include #include #include +#include namespace ESM { @@ -29,6 +29,7 @@ namespace Ogre class RaySceneQuery; class Quaternion; class Vector3; + class ManualObject; } namespace MWWorld diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b8e4a06a8d..ae6cce6c7c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -13,7 +13,6 @@ #include #include #include -#include //#include #include @@ -499,8 +498,8 @@ namespace MWWorld }; - PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) + PhysicsSystem::PhysicsSystem() : + mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c1046aacb4..bc61914bc7 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -12,10 +12,6 @@ namespace OEngine { - namespace Render - { - class OgreRenderer; - } namespace Physic { class PhysicEngine; @@ -31,7 +27,7 @@ namespace MWWorld class PhysicsSystem { public: - PhysicsSystem (OEngine::Render::OgreRenderer &_rend); + PhysicsSystem (); ~PhysicsSystem (); void enableWater(float height); @@ -116,7 +112,6 @@ namespace MWWorld void updateWater(); - OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index eaf92c6734..f3622b2eea 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,6 +1,5 @@ set(OENGINE_OGRE - #ogre/renderer.cpp - ogre/lights.cpp + #ogre/lights.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp deleted file mode 100644 index bdeeeb8c4b..0000000000 --- a/libs/openengine/ogre/renderer.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "renderer.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -OgreRenderer::~OgreRenderer() -{ - cleanup(); - restoreWindowGammaRamp(); -} - -void OgreRenderer::cleanup() -{ - if (mWindow) - Ogre::Root::getSingleton().destroyRenderTarget(mWindow); - mWindow = NULL; - - delete mOgreInit; - mOgreInit = NULL; - - // If we don't do this, the desktop resolution is not restored on exit - SDL_SetWindowFullscreen(mSDLWindow, 0); - - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; -} - -void OgreRenderer::update(float dt) -{ -} - -void OgreRenderer::screenshot(const std::string &file, const std::string& imageFormat) -{ - /* Since Ogre uses narrow character interfaces, it does not support - Unicode paths on Windows. Therefore we had to implement screenshot - saving manually. - */ - namespace bfs = boost::filesystem; - bfs::ofstream out(bfs::path(file), std::ios::binary); - - Ogre::Image image; - - Ogre::PixelFormat pf = mWindow->suggestPixelFormat(); - int w = mWindow->getWidth(); - int h = mWindow->getHeight(); - - image.loadDynamicImage( - OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL), - w, h, 1, pf, true - ); - mWindow->copyContentsToMemory(image.getPixelBox()); - - Ogre::DataStreamPtr stream = image.encode(imageFormat); - Ogre::MemoryDataStream *mem = dynamic_cast(stream.get()); - if (mem != 0) { // likely - const char *ptr = reinterpret_cast(mem->getCurrentPtr()); - out.write(ptr, mem->size()); - } - else { - char buf[4096]; - size_t size = stream->size(); - while (size > 0) { - size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size; - stream->read(buf, chunk); - out.write(buf, chunk); - size -= chunk; - } - } -} - -void OgreRenderer::configure(const std::string &logPath, - const std::string& renderSystem, - const std::string& rttMode - ) -{ - mOgreInit = new OgreInit::OgreInit(); - mRoot = mOgreInit->init(logPath + "/ogre.log"); - - RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); - if (rs == 0) - throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); - mRoot->setRenderSystem(rs); - - if (rs->getName().find("OpenGL") != std::string::npos) - rs->setConfigOption ("RTT Preferred Mode", rttMode); -} - -void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) -{ - assert(mRoot); - mRoot->initialise(false); - - NameValuePairList params; - params.insert(std::make_pair("title", title)); - params.insert(std::make_pair("FSAA", settings.fsaa)); - params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); - - int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen), - pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen); - - if(settings.fullscreen) - { - pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen); - pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen); - } - - - // Create an application window with the following settings: - mSDLWindow = SDL_CreateWindow( - "OpenMW", // window title - pos_x, // initial x position - pos_y, // initial y position - settings.window_x, // width, in pixels - settings.window_y, // height, in pixels - SDL_WINDOW_SHOWN - | SDL_WINDOW_RESIZABLE - | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN : 0) - | (settings.window_border ? 0 : SDL_WINDOW_BORDERLESS) - ); - if (mSDLWindow == 0) - throw std::runtime_error("Failed to create window: " + std::string(SDL_GetError())); - - SFO::SDLWindowHelper helper(mSDLWindow, settings.window_x, settings.window_y, title, settings.fullscreen, params); - if (settings.icon != "") - helper.setWindowIcon(settings.icon); - mWindow = helper.getWindow(); - - SDL_GetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); - - // create the semi-transparent black background texture used by the GUI. - // has to be created in code with TU_DYNAMIC_WRITE_ONLY param - // so that it can be modified at runtime. - Ogre::TextureManager::getSingleton().createManual( - "transparent.png", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - 1, 1, - 0, - Ogre::PF_A8R8G8B8, - Ogre::TU_WRITE_ONLY); - - mScene = mRoot->createSceneManager(ST_GENERIC); - - mCamera = mScene->createCamera("cam"); - - // Create one viewport, entire window - mView = mWindow->addViewport(mCamera); - // Alter the camera aspect ratio to match the viewport - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); -} - -void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) -{ - if (mSDLWindow == NULL) return; - - Uint16 red[256], green[256], blue[256]; - for (int i = 0; i < 256; i++) - { - float k = i/256.0f; - k = (k - 0.5f) * contrast + 0.5f; - k = pow(k, 1.f/gamma); - k *= 256; - float value = k*256; - if (value > 65535) value = 65535; - else if (value < 0) value = 0; - - red[i] = green[i] = blue[i] = static_cast(value); - } - if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) - std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; -} - -void OgreRenderer::restoreWindowGammaRamp() -{ - if (mSDLWindow != NULL) - { - SDL_SetWindowGammaRamp(mSDLWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); - } -} - -void OgreRenderer::adjustCamera(float fov, float nearClip) -{ - mCamera->setNearClipDistance(nearClip); - mCamera->setFOVy(Degree(fov)); -} - -void OgreRenderer::adjustViewport() -{ - // Alter the camera aspect ratio to match the viewport - if(mCamera != NULL) - { - mView->setDimensions(0, 0, 1, 1); - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); - } -} - -void OgreRenderer::setFov(float fov) -{ - mCamera->setFOVy(Degree(fov)); -} - -void OgreRenderer::windowResized(int x, int y) -{ - if (mWindowListener) { - mWindowListener->windowResized(x,y); - } - else { - mWindowWidth = x; - mWindowHeight = y; - mOutstandingResize = true; - } -} - -void OgreRenderer::setWindowListener(WindowSizeListener* listener) -{ - mWindowListener = listener; - if (mOutstandingResize) { - windowResized(mWindowWidth, mWindowHeight); - mOutstandingResize = false; - } -} diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp deleted file mode 100644 index 33a42f8cd8..0000000000 --- a/libs/openengine/ogre/renderer.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef OENGINE_OGRE_RENDERER_H -#define OENGINE_OGRE_RENDERER_H - -/* - Ogre renderer class - */ - -#include -#include - -#include - - -struct SDL_Window; -struct SDL_Surface; - -namespace Ogre -{ - class Root; - class RenderWindow; - class SceneManager; - class Camera; - class Viewport; - class ParticleEmitterFactory; - class ParticleAffectorFactory; -} - -namespace OgreInit -{ - class OgreInit; -} - -namespace OEngine -{ - namespace Render - { - struct WindowSettings - { - bool vsync; - bool fullscreen; - bool window_border; - int window_x, window_y; - int screen; - std::string fsaa; - std::string icon; - }; - - class WindowSizeListener - { - public: - virtual void windowResized (int x, int y) = 0; - }; - - class OgreRenderer - { - Ogre::Root *mRoot; - Ogre::RenderWindow *mWindow; - SDL_Window *mSDLWindow; - Ogre::SceneManager *mScene; - Ogre::Camera *mCamera; - Ogre::Viewport *mView; - - OgreInit::OgreInit* mOgreInit; - - WindowSizeListener* mWindowListener; - - int mWindowWidth; - int mWindowHeight; - bool mOutstandingResize; - - // Store system gamma ramp on window creation. Restore system gamma ramp on exit - uint16_t mOldSystemGammaRamp[256*3]; - - public: - OgreRenderer() - : mRoot(NULL) - , mWindow(NULL) - , mSDLWindow(NULL) - , mScene(NULL) - , mCamera(NULL) - , mView(NULL) - , mOgreInit(NULL) - , mWindowListener(NULL) - , mWindowWidth(0) - , mWindowHeight(0) - , mOutstandingResize(false) - { - } - - ~OgreRenderer(); - - /** Configure the renderer. This will load configuration files and - set up the Root and logging classes. */ - void configure( - const std::string &logPath, // Path to directory where to store log files - const std::string &renderSystem, - const std::string &rttMode); // Enable or disable logging - - /// Create a window with the given title - void createWindow(const std::string &title, const WindowSettings& settings); - - void setWindowGammaContrast(float gamma, float contrast); - void restoreWindowGammaRamp(); - - /// Set up the scene manager, camera and viewport - void adjustCamera( - float fov=55, // Field of view angle - float nearClip=5 // Near clip distance - ); - - void setFov(float fov); - - /// Kill the renderer. - void cleanup(); - - void update(float dt); - - /// Write a screenshot to file - void screenshot(const std::string &file, const std::string& imageFormat); - - void windowResized(int x, int y); - - /// Get the Root - Ogre::Root *getRoot() { return mRoot; } - - /// Get the rendering window - Ogre::RenderWindow *getWindow() { return mWindow; } - - /// Get the SDL Window - SDL_Window *getSDLWindow() { return mSDLWindow; } - - /// Get the scene manager - Ogre::SceneManager *getScene() { return mScene; } - - /// Camera - Ogre::Camera *getCamera() { return mCamera; } - - /// Viewport - Ogre::Viewport *getViewport() { return mView; } - - void setWindowListener(WindowSizeListener* listener); - - void adjustViewport(); - }; - } -} -#endif From dfd8e08698ec01be3f8fcd24c4230af265d2094b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 21 Apr 2015 23:40:10 +0200 Subject: [PATCH 0148/1812] Dead code removal --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/actors.cpp | 211 -------------------- apps/openmw/mwrender/actors.hpp | 64 ------ apps/openmw/mwrender/renderinginterface.hpp | 3 +- apps/openmw/mwrender/renderingmanager.cpp | 5 - apps/openmw/mwrender/renderingmanager.hpp | 1 - 6 files changed, 3 insertions(+), 285 deletions(-) delete mode 100644 apps/openmw/mwrender/actors.cpp delete mode 100644 apps/openmw/mwrender/actors.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c8854f84bf..84dcb60fae 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,9 +21,9 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util + creatureanimation effectmanager util renderinginterface # debugging camera activatoranimation -# renderinginterface localmap occlusionquery water shadows +# localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst weaponanimation ) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp deleted file mode 100644 index 878712ecc4..0000000000 --- a/apps/openmw/mwrender/actors.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "actors.hpp" - -#include -#include - -#include "../mwworld/ptr.hpp" -#include "../mwworld/class.hpp" - -//#include "../mwrender/renderingmanager.hpp" - -/* -#include "animation.hpp" -#include "activatoranimation.hpp" -#include "creatureanimation.hpp" -#include "npcanimation.hpp" -*/ -#include "renderconst.hpp" - - -namespace MWRender -{ -using namespace Ogre; - -Actors::~Actors() -{ - /* - PtrAnimationMap::iterator it = mAllActors.begin(); - for(;it != mAllActors.end();++it) - { - delete it->second; - it->second = NULL; - } - */ -} - -//void Actors::setRootNode(Ogre::SceneNode* root) -//{ mRootNode = root; } - -void Actors::insertBegin(const MWWorld::Ptr &ptr) -{ - /* - Ogre::SceneNode* cellnode; - CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); - if(celliter != mCellSceneNodes.end()) - cellnode = celliter->second; - else - { - //Create the scenenode and put it in the map - cellnode = mRootNode->createChildSceneNode(); - mCellSceneNodes[ptr.getCell()] = cellnode; - } - - Ogre::SceneNode* insert = cellnode->createChildSceneNode(); - const float *f = ptr.getRefData().getPosition().pos; - insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); - - // Convert MW rotation to a quaternion: - f = ptr.getCellRef().getPosition().rot; - - // For rendering purposes, actors should only rotate around the Z axis. - // X rotation is used for camera rotation (for the player) and for - // ranged magic / ranged weapon aiming. - Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); - - insert->setOrientation(zr); - ptr.getRefData().setBaseNode(insert); - */ -} - -void Actors::insertNPC(const MWWorld::Ptr& ptr) -{ - /* - insertBegin(ptr); - NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors); - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - mRendering->addWaterRippleEmitter (ptr); - */ -} -void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) -{ - /* - insertBegin(ptr); - Animation* anim = NULL; - if (weaponsShields) - anim = new CreatureWeaponAnimation(ptr, model); - else - anim = new CreatureAnimation(ptr, model); - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - mRendering->addWaterRippleEmitter (ptr); - */ -} -void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) -{ - /* - insertBegin(ptr); - ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); - - if(ptr.getTypeName() == typeid(ESM::Light).name()) - { - if (addLight) - anim->addLight(ptr.get()->mBase); - else - anim->removeParticles(); - } - - delete mAllActors[ptr]; - mAllActors[ptr] = anim; - */ -} - -bool Actors::deleteObject (const MWWorld::Ptr& ptr) -{ - /* - if (mAllActors.find(ptr) == mAllActors.end()) - return false; - - mRendering->removeWaterRippleEmitter (ptr); - - delete mAllActors[ptr]; - mAllActors.erase(ptr); - - if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode()) - { - Ogre::SceneNode *parent = base->getParentSceneNode(); - CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin()); - for(;iter != mCellSceneNodes.end();++iter) - { - if(iter->second == parent) - { - base->removeAndDestroyAllChildren(); - mRend.getScene()->destroySceneNode (base); - ptr.getRefData().setBaseNode (0); - return true; - } - } - - return false; - } -*/ - return true; -} - -void Actors::removeCell(MWWorld::CellStore* store) -{ - /* - for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) - { - if(iter->first.getCell() == store) - { - mRendering->removeWaterRippleEmitter (iter->first); - delete iter->second; - mAllActors.erase(iter++); - } - else - ++iter; - } - CellSceneNodeMap::iterator celliter = mCellSceneNodes.find(store); - if(celliter != mCellSceneNodes.end()) - { - Ogre::SceneNode *base = celliter->second; - base->removeAndDestroyAllChildren(); - mRend.getScene()->destroySceneNode(base); - - mCellSceneNodes.erase(celliter); - } - */ -} - -Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) -{ - /* - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - return iter->second; - */ - return NULL; -} - -void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) -{ - /* - Ogre::SceneNode *node; - MWWorld::CellStore *newCell = cur.getCell(); - - CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); - if(celliter != mCellSceneNodes.end()) - node = celliter->second; - else - { - node = mRootNode->createChildSceneNode(); - mCellSceneNodes[newCell] = node; - } - node->addChild(cur.getRefData().getBaseNode()); - - PtrAnimationMap::iterator iter = mAllActors.find(old); - if(iter != mAllActors.end()) - { - Animation *anim = iter->second; - mAllActors.erase(iter); - anim->updatePtr(cur); - mAllActors[cur] = anim; - } - - mRendering->updateWaterRippleEmitterPtr (old, cur); - */ -} - -} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp deleted file mode 100644 index 931c5bbd59..0000000000 --- a/apps/openmw/mwrender/actors.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef GAME_RENDER_ACTORS_H -#define GAME_RENDER_ACTORS_H - -#include - -namespace OEngine -{ - namespace Render - { - class OgreRenderer; - } -} - -namespace MWWorld -{ - class Ptr; - class CellStore; - class InventoryStore; -} - -namespace MWRender -{ - class Animation; - class RenderingManager; - - class Actors - { - //typedef std::map CellSceneNodeMap; - //typedef std::map PtrAnimationMap; - - OEngine::Render::OgreRenderer &mRend; - MWRender::RenderingManager* mRendering; - //Ogre::SceneNode* mRootNode; - - //CellSceneNodeMap mCellSceneNodes; - //PtrAnimationMap mAllActors; - - void insertBegin(const MWWorld::Ptr &ptr); - - public: - Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) - : mRend(_rend) - , mRendering(rendering) - //, mRootNode(NULL) - {} - ~Actors(); - - //void setRootNode(Ogre::SceneNode* root); - - void insertNPC(const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); - void insertActivator (const MWWorld::Ptr& ptr, const std::string& model, bool addLight=false); - bool deleteObject (const MWWorld::Ptr& ptr); - ///< \return found? - - void removeCell(MWWorld::CellStore* store); - - /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); - - Animation* getAnimation(const MWWorld::Ptr &ptr); - }; -} -#endif diff --git a/apps/openmw/mwrender/renderinginterface.hpp b/apps/openmw/mwrender/renderinginterface.hpp index 02f3c804a0..63039b612a 100644 --- a/apps/openmw/mwrender/renderinginterface.hpp +++ b/apps/openmw/mwrender/renderinginterface.hpp @@ -10,8 +10,7 @@ namespace MWRender { public: virtual MWRender::Objects& getObjects() = 0; - virtual MWRender::Actors& getActors() = 0; - virtual ~RenderingInterface(){}; + virtual ~RenderingInterface(){} }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b7265533ca..dc5b584ccc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -138,11 +138,6 @@ namespace MWRender return *mObjects.get(); } - MWRender::Actors& RenderingManager::getActors() - { - throw std::runtime_error("unimplemented"); - } - Resource::ResourceSystem* RenderingManager::getResourceSystem() { return mResourceSystem; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d8744db4ae..230885cd3f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,7 +43,6 @@ namespace MWRender ~RenderingManager(); MWRender::Objects& getObjects(); - MWRender::Actors& getActors(); Resource::ResourceSystem* getResourceSystem(); From 5fbcf8a85932929ba2be46a9d9c8000c50bf58d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 16:59:23 +0200 Subject: [PATCH 0149/1812] Mesh filtering fix --- components/sceneutil/attach.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 9f9d63619c..49e2acbd24 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -27,12 +27,14 @@ namespace SceneUtil , mParent(parent) , mFilter(Misc::StringUtils::lowerCase(filter)) { + mFilter2 = "tri " + mFilter; } virtual void apply(osg::Node& node) { std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); - if (lowerName.find(mFilter) != std::string::npos) + if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) + || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) { mParent->addChild(&node); } @@ -43,6 +45,7 @@ namespace SceneUtil private: osg::ref_ptr mParent; std::string mFilter; + std::string mFilter2; }; osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) From 04accb7652d7deb681a71f9407bd4fca77d4a98a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:34:39 +0200 Subject: [PATCH 0150/1812] Add LightController --- apps/openmw/mwrender/animation.cpp | 14 +++ components/CMakeLists.txt | 2 +- components/sceneutil/lightcontroller.cpp | 129 +++++++++++++++++++++++ components/sceneutil/lightcontroller.hpp | 42 ++++++++ components/sceneutil/riggeometry.cpp | 2 +- components/sceneutil/skeleton.hpp | 2 +- libs/openengine/CMakeLists.txt | 6 +- libs/openengine/ogre/.gitignore | 1 - libs/openengine/ogre/lights.cpp | 102 ------------------ libs/openengine/ogre/lights.hpp | 64 ----------- 10 files changed, 189 insertions(+), 175 deletions(-) create mode 100644 components/sceneutil/lightcontroller.cpp create mode 100644 components/sceneutil/lightcontroller.hpp delete mode 100644 libs/openengine/ogre/.gitignore delete mode 100644 libs/openengine/ogre/lights.cpp delete mode 100644 libs/openengine/ogre/lights.hpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d54e87dc56..8a0a856205 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -197,6 +198,19 @@ namespace MWRender light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); + osg::ref_ptr ctrl (new SceneUtil::LightController); + ctrl->setDiffuse(light->getDiffuse()); + if (esmLight->mData.mFlags & ESM::Light::Flicker) + ctrl->setType(SceneUtil::LightController::LT_Flicker); + if (esmLight->mData.mFlags & ESM::Light::FlickerSlow) + ctrl->setType(SceneUtil::LightController::LT_FlickerSlow); + if (esmLight->mData.mFlags & ESM::Light::Pulse) + ctrl->setType(SceneUtil::LightController::LT_Pulse); + if (esmLight->mData.mFlags & ESM::Light::PulseSlow) + ctrl->setType(SceneUtil::LightController::LT_PulseSlow); + + lightSource->addUpdateCallback(ctrl); + attachTo->addChild(lightSource); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 75f6756f87..aa801689a7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller ) add_component_dir (nif diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp new file mode 100644 index 0000000000..d0056ecc6b --- /dev/null +++ b/components/sceneutil/lightcontroller.cpp @@ -0,0 +1,129 @@ +#include "lightcontroller.hpp" + +#include + +#include + +#include + +#include + +namespace +{ + + float pulseAmplitude(float time) + { + return std::sin(time); + } + + float flickerAmplitude(float time) + { + static const float fb = 1.17024f; + static const float f[3] = { 1.5708f, 4.18774f, 5.19934f }; + static const float o[3] = { 0.804248f, 2.11115f, 3.46832f }; + static const float m[3] = { 1.0f, 0.785f, 0.876f }; + static const float s = 0.394f; + + float v = 0.0f; + for(int i = 0;i < 3;++i) + v += std::sin(fb*time*f[i] + o[1])*m[i]; + return v * s; + } + + float flickerFrequency(float phase) + { + static const float fa = 0.785398f; + static const float tdo = 0.94f; + static const float tdm = 2.48f; + + return tdo + tdm*std::sin(fa * phase); + } + +} + +namespace SceneUtil +{ + + LightController::LightController() + : mType(LT_Normal) + , mPhase((OEngine::Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) + , mLastTime(0.0) + , mDeltaCount(0.f) + , mDirection(1.f) + { + } + + void LightController::setType(LightController::LightType type) + { + mType = type; + } + + void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv) + { + double time = nv->getFrameStamp()->getSimulationTime(); + if (time == mLastTime) + return; + + float dt = static_cast(time - mLastTime); + mLastTime = time; + + float brightness = 1.0f; + float cycle_time; + float time_distortion; + + const float pi = 3.14159265359; + + if(mType == LT_Pulse || mType == LT_PulseSlow) + { + cycle_time = 2.0f * pi; + time_distortion = 20.0f; + } + else + { + static const float fa = 0.785398f; + static const float phase_wavelength = 120.0f * pi / fa; + + cycle_time = 500.0f; + mPhase = std::fmod(mPhase + dt, phase_wavelength); + time_distortion = flickerFrequency(mPhase); + } + + mDeltaCount += mDirection*dt*time_distortion; + if(mDirection > 0 && mDeltaCount > +cycle_time) + { + mDirection = -1.0f; + mDeltaCount = 2.0f*cycle_time - mDeltaCount; + } + if(mDirection < 0 && mDeltaCount < -cycle_time) + { + mDirection = +1.0f; + mDeltaCount = -2.0f*cycle_time - mDeltaCount; + } + + static const float fast = 4.0f/1.0f; + static const float slow = 1.0f/1.0f; + + // These formulas are just guesswork, but they work pretty well + if(mType == LT_Normal) + { + // Less than 1/255 light modifier for a constant light: + brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; + } + else if(mType == LT_Flicker) + brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; + else if(mType == LT_FlickerSlow) + brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; + else if(mType == LT_Pulse) + brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; + else if(mType == LT_PulseSlow) + brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; + + static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); + } + + void LightController::setDiffuse(osg::Vec4f color) + { + mDiffuseColor = color; + } + +} diff --git a/components/sceneutil/lightcontroller.hpp b/components/sceneutil/lightcontroller.hpp new file mode 100644 index 0000000000..f6e2fa9faf --- /dev/null +++ b/components/sceneutil/lightcontroller.hpp @@ -0,0 +1,42 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTCONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTCONTROLLER_H + +#include +#include + +namespace SceneUtil +{ + + /// @brief Controller class to handle a pulsing and/or flickering light + /// @note Must be set on a SceneUtil::LightSource. + class LightController : public osg::NodeCallback + { + public: + enum LightType { + LT_Normal, + LT_Flicker, + LT_FlickerSlow, + LT_Pulse, + LT_PulseSlow + }; + + LightController(); + + void setType(LightType type); + + void setDiffuse(osg::Vec4f color); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightType mType; + osg::Vec4f mDiffuseColor; + float mPhase; + float mDeltaCount; + int mDirection; + double mLastTime; + }; + +} + +#endif diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 4d4ea22d25..ab9abcddab 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -149,7 +149,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) else path.push_back(*it); } - osg::Matrix geomToSkel = osg::computeWorldToLocal(path); + osg::Matrixf geomToSkel = osg::computeWorldToLocal(path); // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index acb9e61363..d710ac61b6 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -16,7 +16,7 @@ namespace SceneUtil Bone(); ~Bone(); - osg::Matrix mMatrixInSkeletonSpace; + osg::Matrixf mMatrixInSkeletonSpace; osg::MatrixTransform* mNode; diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index f3622b2eea..0fb39b9d12 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,3 @@ -set(OENGINE_OGRE - #ogre/lights.cpp -) - set(OENGINE_GUI gui/loglistener.cpp #gui/manager.cpp @@ -26,7 +22,7 @@ set(OENGINE_MISC misc/rng.hpp ) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) +set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) diff --git a/libs/openengine/ogre/.gitignore b/libs/openengine/ogre/.gitignore deleted file mode 100644 index 3367afdbbf..0000000000 --- a/libs/openengine/ogre/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp deleted file mode 100644 index 97fa938da6..0000000000 --- a/libs/openengine/ogre/lights.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "lights.hpp" - -#include - - -namespace OEngine { -namespace Render { - -Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time) -{ - return std::sin(time); -} - -Ogre::Real LightFunction::flickerAmplitude(Ogre::Real time) -{ - static const float fb = 1.17024f; - static const float f[3] = { 1.5708f, 4.18774f, 5.19934f }; - static const float o[3] = { 0.804248f, 2.11115f, 3.46832f }; - static const float m[3] = { 1.0f, 0.785f, 0.876f }; - static const float s = 0.394f; - - float v = 0.0f; - for(int i = 0;i < 3;++i) - v += std::sin(fb*time*f[i] + o[1])*m[i]; - return v * s; -} - -Ogre::Real LightFunction::flickerFrequency(Ogre::Real phase) -{ - static const float fa = 0.785398f; - static const float tdo = 0.94f; - static const float tdm = 2.48f; - - return tdo + tdm*std::sin(fa * phase); -} - -Ogre::Real LightFunction::calculate(Ogre::Real value) -{ - Ogre::Real brightness = 1.0f; - float cycle_time; - float time_distortion; - - if(mType == LT_Pulse || mType == LT_PulseSlow) - { - cycle_time = 2.0f * Ogre::Math::PI; - time_distortion = 20.0f; - } - else - { - static const float fa = 0.785398f; - static const float phase_wavelength = 120.0f * 3.14159265359f / fa; - - cycle_time = 500.0f; - mPhase = std::fmod(mPhase + value, phase_wavelength); - time_distortion = flickerFrequency(mPhase); - } - - mDeltaCount += mDirection*value*time_distortion; - if(mDirection > 0 && mDeltaCount > +cycle_time) - { - mDirection = -1.0f; - mDeltaCount = 2.0f*cycle_time - mDeltaCount; - } - if(mDirection < 0 && mDeltaCount < -cycle_time) - { - mDirection = +1.0f; - mDeltaCount = -2.0f*cycle_time - mDeltaCount; - } - - static const float fast = 4.0f/1.0f; - static const float slow = 1.0f/1.0f; - - // These formulas are just guesswork, but they work pretty well - if(mType == LT_Normal) - { - // Less than 1/255 light modifier for a constant light: - brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; - } - else if(mType == LT_Flicker) - brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; - else if(mType == LT_FlickerSlow) - brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; - else if(mType == LT_Pulse) - brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; - else if(mType == LT_PulseSlow) - brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; - - return brightness; -} - -Ogre::Real LightValue::getValue() const -{ - return 0.0f; -} - -void LightValue::setValue(Ogre::Real value) -{ - mTarget->setDiffuseColour(mColor * value); -} - -} -} diff --git a/libs/openengine/ogre/lights.hpp b/libs/openengine/ogre/lights.hpp deleted file mode 100644 index 61d09a0e65..0000000000 --- a/libs/openengine/ogre/lights.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef OENGINE_OGRE_LIGHTS_H -#define OENGINE_OGRE_LIGHTS_H - -#include -#include -#include - -/* - * Controller classes to handle pulsing and flicker lights - */ - -namespace OEngine { -namespace Render { - enum LightType { - LT_Normal, - LT_Flicker, - LT_FlickerSlow, - LT_Pulse, - LT_PulseSlow - }; - - class LightFunction : public Ogre::ControllerFunction - { - LightType mType; - Ogre::Real mPhase; - Ogre::Real mDirection; - - static Ogre::Real pulseAmplitude(Ogre::Real time); - - static Ogre::Real flickerAmplitude(Ogre::Real time); - static Ogre::Real flickerFrequency(Ogre::Real phase); - - public: - // MSVC needs the constructor for a class inheriting a template to be defined in header - LightFunction(LightType type) - : ControllerFunction(true) - , mType(type) - , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f)) - , mDirection(1.0f) - { - } - virtual Ogre::Real calculate(Ogre::Real value); - }; - - class LightValue : public Ogre::ControllerValue - { - Ogre::Light *mTarget; - Ogre::ColourValue mColor; - - public: - // MSVC needs the constructor for a class inheriting a template to be defined in header - LightValue(Ogre::Light *light, const Ogre::ColourValue &color) - : mTarget(light) - , mColor(color) - { - } - - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value); - }; -} -} - -#endif From 7a46d4f46aabb6cb4fb1f925cf87e0b36e90d74d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:48:06 +0200 Subject: [PATCH 0151/1812] Dead code removal --- apps/openmw/mwrender/npcanimation.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 56f12da139..740418a011 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -611,23 +611,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. - - for(size_t i = 0;i < ESM::PRT_Count;i++) - { - if (mObjectParts[i].isNull()) - continue; - std::vector >::iterator ctrl(mObjectParts[i]->mControllers.begin()); - for(;ctrl != mObjectParts[i]->mControllers.end();++ctrl) - ctrl->update(); - - if (!isSkinned(mObjectParts[i])) - continue; - - if (mSkelBase) - updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); - - mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); - } */ return ret; From 8c810e36203b93780cae198a3f7e2fb33ee54b5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 17:58:55 +0200 Subject: [PATCH 0152/1812] Move rng to components --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwclass/creature.cpp | 8 +++---- apps/openmw/mwclass/npc.cpp | 10 ++++---- apps/openmw/mwgui/jailscreen.cpp | 4 ++-- apps/openmw/mwgui/loadingscreen.cpp | 4 ++-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- apps/openmw/mwmechanics/activespells.cpp | 4 ++-- apps/openmw/mwmechanics/aicombat.cpp | 24 +++++++++---------- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++---- apps/openmw/mwmechanics/alchemy.cpp | 6 ++--- apps/openmw/mwmechanics/combat.cpp | 10 ++++---- apps/openmw/mwmechanics/disease.hpp | 4 ++-- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- apps/openmw/mwmechanics/levelledlist.hpp | 6 ++--- .../mwmechanics/mechanicsmanagerimp.cpp | 6 ++--- apps/openmw/mwmechanics/pickpocket.cpp | 4 ++-- apps/openmw/mwmechanics/repair.cpp | 4 ++-- apps/openmw/mwmechanics/security.cpp | 6 ++--- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 8 +++---- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 4 ++-- apps/openmw/mwworld/weather.cpp | 8 +++---- apps/openmw/mwworld/worldimp.cpp | 6 ++--- components/CMakeLists.txt | 2 +- components/interpreter/miscopcodes.hpp | 4 ++-- {libs/openengine => components}/misc/rng.cpp | 5 ++-- {libs/openengine => components}/misc/rng.hpp | 6 ++--- components/sceneutil/lightcontroller.cpp | 4 ++-- libs/openengine/CMakeLists.txt | 7 +----- 36 files changed, 103 insertions(+), 111 deletions(-) rename {libs/openengine => components}/misc/rng.cpp (93%) rename {libs/openengine => components}/misc/rng.hpp (88%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 68f4e82257..64457834c7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -11,7 +11,7 @@ #include // TODO: move to component -#include +#include #include #include @@ -196,7 +196,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { - OEngine::Misc::Rng::init(); + Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a2451e1a16..d4a50ce812 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,7 +1,7 @@ #include "creature.hpp" -#include +#include #include #include @@ -251,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) + if(Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -377,7 +377,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -681,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; + return sounds[Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b5ac8f6c6e..b28fb04997 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -513,7 +513,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) + if (Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -643,7 +643,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -652,7 +652,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -678,7 +678,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; + int hitslot = hitslots[Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 5c0a6ec5f2..2e065c1c27 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -85,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day #include -#include +#include #include @@ -148,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); + std::string const & randomSplash = mResources.at(Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index bc7c5528e8..2620e56609 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,6 +1,6 @@ #include "pickpocketitemmodel.hpp" -#include +#include #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -20,7 +20,7 @@ namespace MWGui { for (size_t i = 0; igetItemCount(); ++i) { - if (chance <= OEngine::Misc::Rng::roll0to99()) + if (chance <= Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a0e5991b46..2e63832107 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -163,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 42491a5e87..a879bf21f5 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -367,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = OEngine::Misc::Rng::rollDice(100) + 1; + int roll = Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f74b068912..afbef5b671 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -156,7 +156,7 @@ namespace MWGui { // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) + if (Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index a6cc9af8ef..7068310a0d 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,6 +1,6 @@ #include "activespells.hpp" -#include +#include #include @@ -231,7 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index e570d1c33a..84cf6f5192 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include @@ -396,7 +396,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = OEngine::Misc::Rng::rollClosedProbability(); + strength = Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -407,7 +407,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (OEngine::Misc::Rng::roll0to99() < chance) + if (Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -514,17 +514,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); + timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) + if (Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); + movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -639,7 +639,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -763,10 +763,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = OEngine::Misc::Rng::rollClosedProbability(); + float roll = Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; + movement.mPosition[0] = Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -790,10 +790,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float total = static_cast(slash + chop + thrust); - float roll = OEngine::Misc::Rng::rollClosedProbability(); + float roll = Misc::Rng::rollClosedProbability(); if(roll <= (slash/total)) { - movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; + movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b6cb553e8f..f6e8c453f1 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include @@ -329,7 +329,7 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; + float roll = Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. @@ -504,7 +504,7 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); + unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); @@ -631,7 +631,7 @@ namespace MWMechanics .get().find("fIdleChanceMultiplier")->getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -653,7 +653,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); + int index = Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 319d01495a..ec45805688 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -297,7 +297,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = OEngine::Misc::Rng::rollDice(6); + int index = Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -470,7 +470,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) + if (getAlchemyFactor() < Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b80ac8cf92..9f5d4fc853 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -109,7 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - if (OEngine::Misc::Rng::roll0to99() < x) + if (Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -187,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) + if (Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); @@ -225,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) + if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -292,7 +292,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); + float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 0153be3dc8..cf21f3806b 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -51,7 +51,7 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - if (OEngine::Misc::Rng::rollDice(10000) < x) + if (Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index bb02fb41d3..2cb963e282 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,6 +1,6 @@ #include "enchanting.hpp" -#include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -70,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) + if(getEnchantChance() <= (Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 76c472001e..f2f0c7cabe 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H -#include +#include #include @@ -26,7 +26,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - if (OEngine::Misc::Rng::roll0to99() < failChance) + if (Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -55,7 +55,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; + std::string item = candidates[Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0b33902719..0e3220cf89 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,7 +2,7 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" -#include +#include #include @@ -733,7 +733,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; + float roll = Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { @@ -1393,7 +1393,7 @@ namespace MWMechanics float target = x - y; - return (OEngine::Misc::Rng::roll0to99() >= target); + return (Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 561011df38..eca24606e6 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,6 +1,6 @@ #include "pickpocket.hpp" -#include +#include #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -41,7 +41,7 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index b5058fb88e..fa429bbeef 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -48,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll <= x) { int y = static_cast(fRepairAmountMult * toolQuality * roll); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 3f72f1b669..9eab5bfef0 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,6 +1,6 @@ #include "security.hpp" -#include +#include #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -50,7 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -91,7 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5f4d986b4c..ff3d2fcebc 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -282,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; + float roll = Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -385,7 +385,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - if (OEngine::Misc::Rng::roll0to99() <= x) + if (Misc::Rng::roll0to99() <= x) { // Fully resisted, show message if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -415,7 +415,7 @@ namespace MWMechanics if (spell && caster != target && target.getClass().isActor()) { float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); + absorbed = (Misc::Rng::roll0to99() < absorb); if (absorbed) { //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -463,7 +463,7 @@ namespace MWMechanics if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); + bool isReflected = (Misc::Rng::roll0to99() < reflect); if (isReflected) { //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -491,7 +491,7 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = OEngine::Misc::Rng::rollClosedProbability(); + float random = Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; @@ -824,7 +824,7 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster); - if (OEngine::Misc::Rng::roll0to99() >= successChance) + if (Misc::Rng::roll0to99() >= successChance) { if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -902,7 +902,7 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = OEngine::Misc::Rng::roll0to99(); + int roll = Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 04225b43eb..4d00d39c91 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = OEngine::Misc::Rng::rollClosedProbability(); + random[i] = Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 740418a011..702fd03aeb 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include @@ -84,7 +84,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); + mBlinkTimer = -(2.0f + Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f4028caa76..0529b9a7ba 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 84f61ddf8d..a5e18dd490 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -235,7 +235,7 @@ namespace MWSound if(!filelist.size()) return; - int i = OEngine::Misc::Rng::rollDice(filelist.size()); + int i = Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -570,7 +570,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = OEngine::Misc::Rng::rollClosedProbability(); + float a = Misc::Rng::rollClosedProbability(); // NOTE: We should use the "Minimum Time Between Environmental Sounds" and // "Maximum Time Between Environmental Sounds" fallback settings here. sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); @@ -599,7 +599,7 @@ namespace MWSound return; } - int r = OEngine::Misc::Rng::rollDice(total); + int r = Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e3254d30a9..e0fd087fb4 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -367,7 +367,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i #include -#include +#include #include @@ -180,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[OEngine::Misc::Rng::rollDice(results.size())]; + return results[Misc::Rng::rollDice(results.size())]; return NULL; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 90aedda1cb..b9d16993f3 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,7 +3,7 @@ #include "weather.hpp" -#include +#include #include @@ -527,7 +527,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = OEngine::Misc::Rng::rollDice(4); + int sound = Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -543,7 +543,7 @@ void WeatherManager::update(float duration, bool paused) //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); //else { - mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); + mThunderChanceNeeded = static_cast(Misc::Rng::rollDice(100)); mThunderChance = 0; //mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +624,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 + int chance = Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0628b42d7c..a2d40930b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include @@ -3176,7 +3176,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] + int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; igetFallbackString(modelName.str()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa801689a7..ece1148cb2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -78,7 +78,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - utf8stream stringops resourcehelpers + utf8stream stringops resourcehelpers rng ) IF(NOT WIN32 AND NOT APPLE) diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index f566a54997..c49bbeb013 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -12,7 +12,7 @@ #include "runtime.hpp" #include "defines.hpp" -#include +#include namespace Interpreter { @@ -148,7 +148,7 @@ namespace Interpreter throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit) + Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mInteger = value; } diff --git a/libs/openengine/misc/rng.cpp b/components/misc/rng.cpp similarity index 93% rename from libs/openengine/misc/rng.cpp rename to components/misc/rng.cpp index 3d50400df0..df0fc687e8 100644 --- a/libs/openengine/misc/rng.cpp +++ b/components/misc/rng.cpp @@ -2,8 +2,8 @@ #include #include -namespace OEngine { -namespace Misc { +namespace Misc +{ void Rng::init() { @@ -26,4 +26,3 @@ namespace Misc { } } -} diff --git a/libs/openengine/misc/rng.hpp b/components/misc/rng.hpp similarity index 88% rename from libs/openengine/misc/rng.hpp rename to components/misc/rng.hpp index 4e1da17e10..01fcdd763d 100644 --- a/libs/openengine/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -1,9 +1,8 @@ -#ifndef MISC_RNG_H -#define MISC_RNG_H +#ifndef OPENMW_COMPONENTS_MISC_RNG_H +#define OPENMW_COMPONENTS_MISC_RNG_H #include -namespace OEngine { namespace Misc { @@ -30,7 +29,6 @@ public: static int roll0to99() { return rollDice(100); } }; -} } #endif diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d0056ecc6b..484cea4476 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -6,7 +6,7 @@ #include -#include +#include namespace { @@ -46,7 +46,7 @@ namespace SceneUtil LightController::LightController() : mType(LT_Normal) - , mPhase((OEngine::Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) + , mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) , mLastTime(0.0) , mDeltaCount(0.f) , mDirection(1.f) diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 0fb39b9d12..07ac60bc6b 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -17,12 +17,7 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_MISC - misc/rng.cpp - misc/rng.hpp -) - -set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) +set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) From 8410966753a7f3a52aef765dd603351e9bf94192 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 18:01:55 +0200 Subject: [PATCH 0153/1812] Disable mygui plugin for now --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e806b25782..e8a2458b1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -557,9 +557,9 @@ add_subdirectory (extern/oics) add_subdirectory (components) # Plugins -if (BUILD_MYGUI_PLUGIN) - add_subdirectory(plugins/mygui_resource_plugin) -endif() +#if (BUILD_MYGUI_PLUGIN) +# add_subdirectory(plugins/mygui_resource_plugin) +#endif() #Testing if (BUILD_NIFTEST) From 460304b0697b96dc58a75ce7ecaf19de61031364 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 18:06:29 +0200 Subject: [PATCH 0154/1812] Port bsatool --- apps/bsatool/bsatool.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index c0a6dcc81f..2ea736db72 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -237,12 +237,14 @@ int extract(Bsa::BSAFile& bsa, Arguments& info) } // Get a stream for the file to extract - Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str()); + Files::IStreamPtr stream = bsa.getFile(archivePath.c_str()); + bfs::ofstream out(target, std::ios::binary); // Write the file to disk std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; - out.write(data->getAsString().c_str(), data->size()); + + out << stream->rdbuf(); out.close(); return 0; @@ -276,12 +278,12 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info) // Get a stream for the file to extract // (inefficient because getFile iter on the list again) - Ogre::DataStreamPtr data = bsa.getFile(archivePath); + Files::IStreamPtr data = bsa.getFile(archivePath); bfs::ofstream out(target, std::ios::binary); // Write the file to disk std::cout << "Extracting " << target << std::endl; - out.write(data->getAsString().c_str(), data->size()); + out << data->rdbuf(); out.close(); } From 1a19cd360766a59eadbc41f8fa4357f9c2fadf97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 19:08:56 +0200 Subject: [PATCH 0155/1812] Some cleanup --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++++ apps/openmw/mwrender/animation.hpp | 19 +++++++------------ apps/openmw/mwrender/npcanimation.cpp | 14 ++++++++------ apps/openmw/mwrender/npcanimation.hpp | 16 ++++++++-------- apps/openmw/mwrender/objects.hpp | 11 ++++++++--- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwworld/scene.cpp | 2 ++ components/nifosg/nifloader.hpp | 3 +-- 8 files changed, 48 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8a0a856205..75d409aeca 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,5 +1,7 @@ #include "animation.hpp" +#include + #include #include #include @@ -91,6 +93,16 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + void Animation::updatePtr(const MWWorld::Ptr &ptr) + { + mPtr = ptr; + } + + void Animation::addAnimSource(const std::string &model) + { + + } + osg::Vec3f Animation::runAnimation(float duration) { updateEffects(duration); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index aef4d4b80f..ea47a5b794 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,9 +1,6 @@ #ifndef GAME_RENDER_ANIMATION_H #define GAME_RENDER_ANIMATION_H -#include -#include - #include "../mwworld/ptr.hpp" #include @@ -55,7 +52,7 @@ protected: /* This is the number of *discrete* groups. */ static const size_t sNumGroups = 4; - class AnimationTime : public Ogre::ControllerValue + class AnimationTime : public SceneUtil::ControllerSource { private: Animation *mAnimation; @@ -71,8 +68,7 @@ protected: const std::string &getAnimName() const { return mAnimationName; } - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value); + virtual float getValue(); }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -85,14 +81,15 @@ protected: }; + /* struct AnimSource : public Ogre::AnimationAlloc { //NifOgre::TextKeyMap mTextKeys; std::vector > mControllers[sNumGroups]; }; typedef std::vector< Ogre::SharedPtr > AnimSourceList; - + */ struct AnimState { - Ogre::SharedPtr mSource; + //Ogre::SharedPtr mSource; float mStartTime; float mLoopStartTime; float mLoopStopTime; @@ -115,8 +112,6 @@ protected: }; typedef std::map AnimStateMap; - typedef std::map ObjectAttachMap; - osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; @@ -204,7 +199,7 @@ protected: /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif * extension will be replaced with .kf. */ - //void addAnimSource(const std::string &model); + void addAnimSource(const std::string &model); /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); @@ -238,7 +233,7 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out); - //void updatePtr(const MWWorld::Ptr &ptr); + void updatePtr(const MWWorld::Ptr &ptr); //bool hasAnimation(const std::string &anim); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 702fd03aeb..03af50c717 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -190,12 +190,12 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), - mFirstPersonOffset(0.f, 0.f, 0.f), + //mFirstPersonOffset(0.f, 0.f, 0.f), mAlpha(1.f), mNpcType(Type_Normal), - mSoundsDisabled(disableSounds), - mHeadPitch(0.f), - mHeadYaw(0.f) + mSoundsDisabled(disableSounds) + //mHeadPitch(0.f), + //mHeadYaw(0.f) { mNpc = mPtr.get()->mBase; @@ -562,11 +562,11 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); } - +/* void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) { mFirstPersonOffset += offset; -} +}*/ Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { @@ -903,6 +903,7 @@ void NpcAnimation::setVampire(bool vampire) } } +/* void NpcAnimation::setHeadPitch(Ogre::Radian pitch) { mHeadPitch = pitch; @@ -922,5 +923,6 @@ Ogre::Radian NpcAnimation::getHeadYaw() const { return mHeadYaw; } +*/ } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 309bc5ef58..0c91dfe6eb 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,7 +90,7 @@ private: int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; - Ogre::Vector3 mFirstPersonOffset; + //Ogre::Vector3 mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; //Ogre::SharedPtr mWeaponAnimationTime; @@ -98,8 +98,8 @@ private: float mAlpha; bool mSoundsDisabled; - Ogre::Radian mHeadYaw; - Ogre::Radian mHeadPitch; + //Ogre::Radian mHeadYaw; + //Ogre::Radian mHeadPitch; void updateNpcBase(); @@ -144,10 +144,10 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setHeadPitch(Ogre::Radian pitch); - virtual void setHeadYaw(Ogre::Radian yaw); - virtual Ogre::Radian getHeadPitch() const; - virtual Ogre::Radian getHeadYaw() const; + //virtual void setHeadPitch(Ogre::Radian pitch); + //virtual void setHeadYaw(Ogre::Radian yaw); + //virtual Ogre::Radian getHeadPitch() const; + //virtual Ogre::Radian getHeadYaw() const; virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); @@ -167,7 +167,7 @@ public: /// \brief Applies a translation to the arms and hands. /// This may be called multiple times before the animation /// is updated to add additional offsets. - void addFirstPersonOffset(const Ogre::Vector3 &offset); + //void addFirstPersonOffset(const Ogre::Vector3 &offset); /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index f4d5675aa1..2acf10d105 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -1,9 +1,9 @@ #ifndef GAME_RENDER_OBJECTS_H #define GAME_RENDER_OBJECTS_H -#include - -#include +#include +#include +#include #include @@ -12,6 +12,11 @@ namespace osg class Group; } +namespace Resource +{ + class ResourceSystem; +} + namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dc5b584ccc..5199e6e126 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -10,12 +10,12 @@ #include +#include + #include #include - #include - #include #include diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aabe4d6d86..ef9e5792ba 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 1c403a4fe6..d1437ff2ac 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,7 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + std::map > mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. @@ -53,7 +53,6 @@ namespace NifOsg class Loader { public: - // TODO: add text keys as user data on the node /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. /// @param node The parent of the new root node for the created scene graph. static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); From 148c041a43788d0d3faf1d7c5bc1bce8fe8d81e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 19:16:49 +0200 Subject: [PATCH 0156/1812] Nif loader cleanup - forcing a skeleton is no longer needed --- components/nifosg/nifloader.cpp | 45 ++++++++------------------------- components/nifosg/nifloader.hpp | 6 +---- 2 files changed, 11 insertions(+), 40 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f7f6af0ae6..63a3ee8879 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -459,9 +459,6 @@ namespace NifOsg static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { - if (nif->getUseSkinning()) - return loadAsSkeleton(nif, textureManager); - if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -473,35 +470,19 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, false, std::map(), 0, 0, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::map(), 0, 0, false, &textkeys->mTextKeys); + if (nif->getUseSkinning()) + { + osg::ref_ptr skel = new SceneUtil::Skeleton; + skel->addChild(created); + created = skel; + } created->getOrCreateUserDataContainer()->addUserObject(textkeys); return created; } - static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) - { - if (nif->numRoots() < 1) - nif->fail("Found no root nodes"); - - const Nif::Record* r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) - nif->fail("First root was not a node, but a " + r->recName); - - osg::ref_ptr textkeys (new TextKeyMapHolder); - - osg::ref_ptr skel = new SceneUtil::Skeleton; - handleNode(nifNode, skel, textureManager, true, std::map(), 0, 0, false, &textkeys->mTextKeys); - - skel->getOrCreateUserDataContainer()->addUserObject(textkeys); - - return skel; - } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; @@ -521,7 +502,7 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } - static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, bool createSkeleton, + static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); @@ -604,7 +585,7 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); - if (!createSkeleton || triShape->skin.empty()) + if (triShape->skin.empty()) handleTriShape(triShape, transformNode, boundTextures, animflags); else handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); @@ -630,8 +611,7 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, textureManager, - createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), transformNode, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } @@ -1451,11 +1431,6 @@ namespace NifOsg return LoaderImpl::load(file, textureManager); } - osg::ref_ptr Loader::loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) - { - return LoaderImpl::loadAsSkeleton(file, textureManager); - } - void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { LoaderImpl::loadKf(kf, target); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index d1437ff2ac..678b8cc64c 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -53,13 +53,9 @@ namespace NifOsg class Loader { public: - /// Create a scene graph for the given NIF. Auto-detects when skinning is used and calls loadAsSkeleton instead. - /// @param node The parent of the new root node for the created scene graph. + /// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton if so. static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Create a scene graph for the given NIF. Always creates a skeleton so that rigs can be attached on the created scene. - static osg::ref_ptr loadAsSkeleton(Nif::NIFFilePtr file, Resource::TextureManager* textureManager); - /// Load keyframe controllers from the given kf file. static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); From cd7808fc11dbd38ba0eed772031ce2f5fe1edbfd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Apr 2015 23:12:58 +0200 Subject: [PATCH 0157/1812] Cleanup in preparation for animation port Scrapped previous idea for multiple animation sources, better approach incoming. --- components/nifosg/controller.cpp | 32 +-------------------- components/nifosg/controller.hpp | 22 +-------------- components/nifosg/nifloader.cpp | 43 ++--------------------------- components/nifosg/nifloader.hpp | 2 +- components/sceneutil/controller.hpp | 3 +- 5 files changed, 7 insertions(+), 95 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 499a74d958..27665b6c64 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -27,7 +27,7 @@ ControllerFunction::ControllerFunction(const Nif::Controller *ctrl) { } -float ControllerFunction::calculate(float value) +float ControllerFunction::calculate(float value) const { float time = mFrequency * value + mPhase; if (time >= mStartTime && time <= mStopTime) @@ -451,34 +451,4 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } -SourcedKeyframeController::SourcedKeyframeController(const Nif::NiKeyframeData *data) - : KeyframeController(data) - , mEnabled(false) -{ -} - -SourcedKeyframeController::SourcedKeyframeController() - : mEnabled(false) -{ -} - -SourcedKeyframeController::SourcedKeyframeController(const SourcedKeyframeController ©, const osg::CopyOp ©op) - : KeyframeController(copy, copyop) - , mEnabled(copy.mEnabled) -{ -} - -void SourcedKeyframeController::setEnabled(bool enabled) -{ - mEnabled = enabled; -} - -void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* nv) -{ - if (mEnabled) - KeyframeController::operator()(node, nv); // calls traverse - else - traverse(node, nv); -} - } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index e480f4c13e..d32c9f977a 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -94,7 +94,7 @@ namespace NifOsg public: ControllerFunction(const Nif::Controller *ctrl); - float calculate(float value); + float calculate(float value) const; virtual float getMaximum() const; }; @@ -144,26 +144,6 @@ namespace NifOsg osg::Quat getXYZRotation(float time) const; }; - // Specialization that can be enabled/disabled. Used for multiple animation sources support, i.e. .kf files. - // A SourcedKeyframeController is disabled by default and should be manually enabled when playing an animation from - // the relevant animation source. - class SourcedKeyframeController : public KeyframeController - { - public: - SourcedKeyframeController(const Nif::NiKeyframeData* data); - SourcedKeyframeController(); - SourcedKeyframeController(const SourcedKeyframeController& copy, const osg::CopyOp& copyop); - - META_Object(NifOsg, SourcedKeyframeController) - - virtual void operator() (osg::Node*, osg::NodeVisitor*); - - void setEnabled(bool enabled); - - private: - bool mEnabled; - }; - class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator { public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 63a3ee8879..3b3ae4b2c8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -253,44 +253,6 @@ namespace } }; - // NodeVisitor that adds keyframe controllers to an existing scene graph, used when loading .kf files - /* - class LoadKfVisitor : public osg::NodeVisitor - { - public: - LoadKfVisitor(std::map map, int sourceIndex) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mMap(map) - , mSourceIndex(sourceIndex) - { - } - - void apply(osg::Node &node) - { - std::map::const_iterator found = mMap.find(node.getName()); - if (node.asTransform() && found != mMap.end()) - { - const Nif::NiKeyframeController* keyframectrl = found->second; - - osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl)); - - // Insert in front of the callback list, to make sure UpdateBone is last. - // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. - osg::ref_ptr old = node.getUpdateCallback(); - node.setUpdateCallback(callback); - callback->setNestedCallback(old); - } - - traverse(node); - } - - private: - std::map mMap; - int mSourceIndex; - }; - */ - struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() @@ -450,7 +412,7 @@ namespace NifOsg if(key->data.empty()) continue; - osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(key->data.getPtr())); + osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); target.mKeyframeControllers[strdata->string] = callback; @@ -1007,7 +969,6 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); geode->addDrawable(geometry); @@ -1103,7 +1064,7 @@ namespace NifOsg static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); - geode->setName(triShape->name); // name will be used for part filtering + osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 678b8cc64c..b6e9b1c8fa 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,7 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + std::map > mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index a4e209e8c3..378837ad78 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -21,10 +21,11 @@ namespace SceneUtil virtual float getValue(osg::NodeVisitor* nv); }; + /// @note ControllerFunctions may be shared - you should not hold any state in it. That is why all its methods are declared const. class ControllerFunction { public: - virtual float calculate(float input) = 0; + virtual float calculate(float input) const = 0; /// Get the "stop time" of the controller function, typically the maximum of the calculate() function. /// May not be meaningful for all types of controller functions. From 12f3198f680e3f189b5b0fa37b239dee7a0414a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 17:15:30 +0200 Subject: [PATCH 0158/1812] Node name lookups should be case insensitive Concerns "AttachLight", "BoneOffset" and equipment part attachment points, that are all case insensitive in vanilla MW. --- components/sceneutil/controller.hpp | 2 +- components/sceneutil/visitor.hpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 378837ad78..6086663bda 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -65,7 +65,7 @@ namespace SceneUtil AssignControllerSourcesVisitor(); AssignControllerSourcesVisitor(boost::shared_ptr toAssign); - /// Assign the wanted ControllerSource. May be overriden in derived classes. + /// Assign the wanted ControllerSource. May be overridden in derived classes. /// By default assigns the ControllerSource passed to the constructor of this class if no ControllerSource is assigned to that controller yet. virtual void visit(osg::Node& node, Controller& ctrl); diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 6bb8b2e357..b9342b884e 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -3,6 +3,8 @@ #include +#include + // Commonly used scene graph visitors namespace SceneUtil { @@ -19,7 +21,7 @@ namespace SceneUtil virtual void apply(osg::Group& group) { - if (group.getName() == mNameToFind) + if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) { mFoundNode = &group; return; From 6fada6acf896b4e68bc487e2500c5b53af4be856 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 20:02:18 +0200 Subject: [PATCH 0159/1812] Remove tests for no longer existing code --- components/misc/tests/.gitignore | 1 - components/misc/tests/Makefile | 12 ----- components/misc/tests/output/slice_test.out | 6 --- components/misc/tests/output/strops_test.out | 0 components/misc/tests/slice_test.cpp | 28 ------------ components/misc/tests/strops_test.cpp | 48 -------------------- components/misc/tests/test.sh | 18 -------- 7 files changed, 113 deletions(-) delete mode 100644 components/misc/tests/.gitignore delete mode 100644 components/misc/tests/Makefile delete mode 100644 components/misc/tests/output/slice_test.out delete mode 100644 components/misc/tests/output/strops_test.out delete mode 100644 components/misc/tests/slice_test.cpp delete mode 100644 components/misc/tests/strops_test.cpp delete mode 100755 components/misc/tests/test.sh diff --git a/components/misc/tests/.gitignore b/components/misc/tests/.gitignore deleted file mode 100644 index 8144904045..0000000000 --- a/components/misc/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/components/misc/tests/Makefile b/components/misc/tests/Makefile deleted file mode 100644 index dc1ded5ff1..0000000000 --- a/components/misc/tests/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -GCC=g++ - -all: strops_test slice_test - -slice_test: slice_test.cpp ../slice_array.hpp - $(GCC) $< -o $@ - -strops_test: strops_test.cpp ../stringops.hpp ../stringops.cpp - $(GCC) $< -o $@ ../stringops.cpp - -clean: - rm *_test diff --git a/components/misc/tests/output/slice_test.out b/components/misc/tests/output/slice_test.out deleted file mode 100644 index 7b054082bb..0000000000 --- a/components/misc/tests/output/slice_test.out +++ /dev/null @@ -1,6 +0,0 @@ -hello, len=5 -001 -hell, len=4 -010 -01 -4 3 diff --git a/components/misc/tests/output/strops_test.out b/components/misc/tests/output/strops_test.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/components/misc/tests/slice_test.cpp b/components/misc/tests/slice_test.cpp deleted file mode 100644 index 0d9d7b4abf..0000000000 --- a/components/misc/tests/slice_test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -using namespace std; - -#include "../slice_array.hpp" - -int main() -{ - Misc::SString s, t; - s = Misc::SString("hello"); - cout << s.toString() << ", len=" << s.length << endl; - cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; - t = s; - - s = Misc::SString("othello"+2, 4); - cout << s.toString() << ", len=" << s.length << endl; - cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; - - cout << (s==t) << (Misc::SString("hello")==t) << endl; - - const int arr[4] = {1,2,3,4}; - - Misc::IntArray ia(arr,4); - - cout << ia.length << " " << ia.ptr[2] << endl; - - return 0; -} diff --git a/components/misc/tests/strops_test.cpp b/components/misc/tests/strops_test.cpp deleted file mode 100644 index 24ab8a298a..0000000000 --- a/components/misc/tests/strops_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include "../stringops.hpp" - -int main() -{ - assert(Misc::begins("abc", "a")); - assert(Misc::begins("abc", "ab")); - assert(Misc::begins("abc", "abc")); - assert(Misc::begins("abcd", "abc")); - - assert(!Misc::begins("abc", "b")); - assert(!Misc::begins("abc", "bc")); - assert(!Misc::begins("abc", "bcd")); - assert(!Misc::begins("abc", "abcd")); - - assert(Misc::ibegins("Abc", "a")); - assert(Misc::ibegins("aBc", "ab")); - assert(Misc::ibegins("abC", "abc")); - assert(Misc::ibegins("abcD", "abc")); - - assert(!Misc::ibegins("abc", "b")); - assert(!Misc::ibegins("abc", "bc")); - assert(!Misc::ibegins("abc", "bcd")); - assert(!Misc::ibegins("abc", "abcd")); - - assert(Misc::ends("abc", "c")); - assert(Misc::ends("abc", "bc")); - assert(Misc::ends("abc", "abc")); - assert(Misc::ends("abcd", "abcd")); - - assert(!Misc::ends("abc", "b")); - assert(!Misc::ends("abc", "ab")); - assert(!Misc::ends("abc", "bcd")); - assert(!Misc::ends("abc", "abcd")); - - assert(Misc::iends("Abc", "c")); - assert(Misc::iends("aBc", "bc")); - assert(Misc::iends("abC", "abc")); - assert(Misc::iends("abcD", "abcd")); - - assert(!Misc::iends("abc", "b")); - assert(!Misc::iends("abc", "ab")); - assert(!Misc::iends("abc", "bcd")); - assert(!Misc::iends("abc", "abcd")); - - return 0; -} diff --git a/components/misc/tests/test.sh b/components/misc/tests/test.sh deleted file mode 100755 index 2d07708adc..0000000000 --- a/components/misc/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 From 09742d5b957b656459c9cf2f69e00d6c14236117 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 20:41:31 +0200 Subject: [PATCH 0160/1812] Animation playback works, no movement accumulation yet --- apps/openmw/mwrender/animation.cpp | 683 ++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 105 ++-- apps/openmw/mwrender/creatureanimation.cpp | 16 +- apps/openmw/mwrender/npcanimation.cpp | 2 - apps/openmw/mwrender/objects.cpp | 1 + components/nifosg/nifloader.cpp | 6 +- components/nifosg/nifloader.hpp | 3 +- components/sceneutil/controller.cpp | 28 +- components/sceneutil/controller.hpp | 7 + 9 files changed, 791 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 75d409aeca..d291e0fd0e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,11 +1,13 @@ #include "animation.hpp" #include +#include #include #include #include #include +#include #include @@ -13,6 +15,10 @@ #include #include +#include // KeyframeHolder + +#include + #include #include @@ -74,6 +80,89 @@ namespace std::vector > mTextures; }; + class NodeMapVisitor : public osg::NodeVisitor + { + public: + NodeMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::MatrixTransform& trans) + { + mMap[Misc::StringUtils::lowerCase(trans.getName())] = &trans; + traverse(trans); + } + + typedef std::map > NodeMap; + + const NodeMap& getNodeMap() const + { + return mMap; + } + + private: + NodeMap mMap; + }; + + NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) + { + NifOsg::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();++iter) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; + } + + float calcAnimVelocity(const std::multimap& keys, + NifOsg::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname) + { + const std::string start = groupname+": start"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + + // Pick the last Loop Stop key and the last Loop Start key. + // This is required because of broken text keys in AshVampire.nif. + // It has *two* WalkForward: Loop Stop keys at different times, the first one is used for stopping playback + // but the animation velocity calculation uses the second one. + // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, + // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. + NifOsg::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); + while(keyiter != keys.rend()) + { + if(keyiter->second == start || keyiter->second == loopstart) + { + starttime = keyiter->first; + break; + } + ++keyiter; + } + keyiter = keys.rbegin(); + while(keyiter != keys.rend()) + { + if (keyiter->second == stop) + stoptime = keyiter->first; + else if (keyiter->second == loopstop) + { + stoptime = keyiter->first; + break; + } + ++keyiter; + } + + if(stoptime > starttime) + { + osg::Vec3f startpos = osg::componentMultiply(nonaccumctrl->getTranslation(starttime), accum); + osg::Vec3f endpos = osg::componentMultiply(nonaccumctrl->getTranslation(stoptime), accum); + + return (startpos-endpos).length() / (stoptime - starttime); + } + + return 0.0f; + } } namespace MWRender @@ -84,7 +173,8 @@ namespace MWRender , mInsert(parentNode) , mResourceSystem(resourceSystem) { - + for(size_t i = 0;i < sNumGroups;i++) + mAnimationTimePtr[i].reset(new AnimationTime(this)); } Animation::~Animation() @@ -98,16 +188,589 @@ namespace MWRender mPtr = ptr; } + void Animation::setAccumulation(const osg::Vec3f& accum) + { + mAccumulate = accum; + } + + size_t Animation::detectAnimGroup(osg::Node* node) + { + static const char sGroupRoots[sNumGroups][32] = { + "", /* Lower body / character root */ + "Bip01 Spine1", /* Torso */ + "Bip01 L Clavicle", /* Left arm */ + "Bip01 R Clavicle", /* Right arm */ + }; + + while(node != mObjectRoot) + { + const std::string &name = node->getName(); + for(size_t i = 1;i < sNumGroups;i++) + { + if(name == sGroupRoots[i]) + return i; + } + + assert(node->getNumParents() > 0); + + node = node->getParent(0); + } + + return 0; + } + + const std::multimap &Animation::AnimSource::getTextKeys() + { + return mKeyframes->mTextKeys; + } + void Animation::addAnimSource(const std::string &model) { + std::string kfname = model; + Misc::StringUtils::toLower(kfname); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + + if(!mResourceSystem->getVFS()->exists(kfname)) + return; + + boost::shared_ptr animsrc; + animsrc.reset(new AnimSource); + animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); + + if (animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) + return; + + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); + it != animsrc->mKeyframes->mKeyframeControllers.end(); ++it) + { + std::string bonename = Misc::StringUtils::lowerCase(it->first); + NodeMap::const_iterator found = mNodeMap.find(bonename); + if (found == mNodeMap.end()) + throw std::runtime_error("addAnimSource: can't find bone " + bonename); + + osg::Node* node = found->second; + + size_t group = detectAnimGroup(node); + + // clone the controller, because each Animation needs its own ControllerSource + osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL); + cloned->setSource(mAnimationTimePtr[group]); + + animsrc->mControllerMap[group].insert(std::make_pair(bonename, cloned)); + } + + mAnimSources.push_back(animsrc); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(mAnimationTimePtr[0]); + mObjectRoot->accept(assignVisitor); + + if (!mAccumRoot) + { + NodeMap::const_iterator found = mNodeMap.find("root bone"); + if (found == mNodeMap.end()) + found = mNodeMap.find("bip01"); + + if (found != mNodeMap.end()) + mAccumRoot = found->second; + } + } + + bool Animation::hasAnimation(const std::string &anim) + { + AnimSourceList::const_iterator iter(mAnimSources.begin()); + for(;iter != mAnimSources.end();++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + if(findGroupStart(keys, anim) != keys.end()) + return true; + } + + return false; + } + + float Animation::getStartTime(const std::string &groupname) const + { + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + + NifOsg::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + if(found != keys.end()) + return found->first; + } + return -1.f; + } + + float Animation::getTextKeyTime(const std::string &textKey) const + { + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + { + const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + + for(NifOsg::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) + { + if(iterKey->second.compare(0, textKey.size(), textKey) == 0) + return iterKey->first; + } + } + + return -1.f; + } + + void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) + { + // TODO: forward to listener? + } + + void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, + const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) + { + if(!mObjectRoot || mAnimSources.empty()) + return; + + if(groupname.empty()) + { + resetActiveGroups(); + return; + } + + priority = std::max(0, priority); + + AnimStateMap::iterator stateiter = mStates.begin(); + while(stateiter != mStates.end()) + { + if(stateiter->second.mPriority == priority) + mStates.erase(stateiter++); + else + ++stateiter; + } + + stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + stateiter->second.mPriority = priority; + resetActiveGroups(); + return; + } + + /* Look in reverse; last-inserted source has priority. */ + AnimState state; + AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); + for(;iter != mAnimSources.rend();++iter) + { + const NifOsg::TextKeyMap &textkeys = (*iter)->getTextKeys(); + if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) + { + state.mSource = *iter; + state.mSpeedMult = speedmult; + state.mLoopCount = loops; + state.mPlaying = (state.mTime < state.mStopTime); + state.mPriority = priority; + state.mGroups = groups; + state.mAutoDisable = autodisable; + mStates[groupname] = state; + + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + if (state.mPlaying) + { + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, groupname, textkey, textkeys); + ++textkey; + } + } + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + { + state.mLoopCount--; + state.mTime = state.mLoopStartTime; + state.mPlaying = true; + if(state.mTime >= state.mLoopStopTime) + break; + + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, groupname, textkey, textkeys); + ++textkey; + } + } + + break; + } + } + if(iter == mAnimSources.rend()) + std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); + } + */ + } + + bool Animation::reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) + { + // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two + // separate walkforward keys, and the last one is supposed to be used. + NifOsg::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); + for(;groupend != keys.rend();++groupend) + { + if(groupend->second.compare(0, groupname.size(), groupname) == 0 && + groupend->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + + std::string starttag = groupname+": "+start; + NifOsg::TextKeyMap::const_reverse_iterator startkey(groupend); + while(startkey != keys.rend() && startkey->second != starttag) + ++startkey; + if(startkey == keys.rend() && start == "loop start") + { + starttag = groupname+": start"; + startkey = groupend; + while(startkey != keys.rend() && startkey->second != starttag) + ++startkey; + } + if(startkey == keys.rend()) + return false; + + const std::string stoptag = groupname+": "+stop; + NifOsg::TextKeyMap::const_reverse_iterator stopkey(groupend); + while(stopkey != keys.rend() + // We have to ignore extra garbage at the end. + // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". + // Why, just why? :( + && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) + ++stopkey; + if(stopkey == keys.rend()) + return false; + + if(startkey->first > stopkey->first) + return false; + + state.mStartTime = startkey->first; + if (loopfallback) + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = stopkey->first; + } + else + { + state.mLoopStartTime = startkey->first; + state.mLoopStopTime = std::numeric_limits::max(); + } + state.mStopTime = stopkey->first; + + state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); + + // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation + // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. + if(state.mTime > state.mStartTime) + { + const std::string loopstarttag = groupname+": loop start"; + const std::string loopstoptag = groupname+": loop stop"; + + NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + for (; key != startkey && key != keys.rend(); ++key) + { + if (key->first > state.mTime) + continue; + + if (key->second == loopstarttag) + state.mLoopStartTime = key->first; + else if (key->second == loopstoptag) + state.mLoopStopTime = key->first; + } + } + + return true; + } + + void Animation::resetActiveGroups() + { + // remove all previous external controllers from the scene graph + for (AnimSourceControllerMap::iterator it = mAnimSourceControllers.begin(); it != mAnimSourceControllers.end(); ++it) + { + osg::Node* node = it->first; + node->removeUpdateCallback(it->second); + } + mAnimSourceControllers.clear(); + + mAccumCtrl = NULL; + + for(size_t grp = 0;grp < sNumGroups;grp++) + { + AnimStateMap::const_iterator active = mStates.end(); + + AnimStateMap::const_iterator state = mStates.begin(); + for(;state != mStates.end();++state) + { + if(!(state->second.mGroups&(1<second.mPriority < state->second.mPriority) + active = state; + } + + mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? + std::string() : active->first); + + // add external controllers for the AnimSource active in this group + if (active != mStates.end()) + { + boost::shared_ptr animsrc = active->second.mSource; + + for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[grp].begin(); it != animsrc->mControllerMap[grp].end(); ++it) + { + osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource + + node->addUpdateCallback(it->second); + mAnimSourceControllers[node] = it->second; + + if (grp == 0 && node == mAccumRoot) + mAccumCtrl = it->second; + } + } + } + + //if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) + // return; + + /* + AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); + if(state == mStates.end()) + { + //if (mAccumRoot && mNonAccumRoot) + // mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); + return; + } + */ + + //if (mAccumRoot && mNonAccumCtrl) + // mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); + } + + void Animation::changeGroups(const std::string &groupname, int groups) + { + AnimStateMap::iterator stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + if(stateiter->second.mGroups != groups) + { + stateiter->second.mGroups = groups; + resetActiveGroups(); + } + return; + } + } + + void Animation::stopLooping(const std::string& groupname) + { + AnimStateMap::iterator stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + stateiter->second.mLoopCount = 0; + return; + } + } + + void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) + { + AnimStateMap::iterator state(mStates.find(groupname)); + if(state != mStates.end()) + state->second.mSpeedMult = speedmult; + } + + bool Animation::isPlaying(const std::string &groupname) const + { + AnimStateMap::const_iterator state(mStates.find(groupname)); + if(state != mStates.end()) + return state->second.mPlaying; + return false; + } + + bool Animation::getInfo(const std::string &groupname, float *complete, float *speedmult) const + { + AnimStateMap::const_iterator iter = mStates.find(groupname); + if(iter == mStates.end()) + { + if(complete) *complete = 0.0f; + if(speedmult) *speedmult = 0.0f; + return false; + } + + if(complete) + { + if(iter->second.mStopTime > iter->second.mStartTime) + *complete = (iter->second.mTime - iter->second.mStartTime) / + (iter->second.mStopTime - iter->second.mStartTime); + else + *complete = (iter->second.mPlaying ? 0.0f : 1.0f); + } + if(speedmult) *speedmult = iter->second.mSpeedMult; + return true; + } + + float Animation::getCurrentTime(const std::string &groupname) const + { + AnimStateMap::const_iterator iter = mStates.find(groupname); + if(iter == mStates.end()) + return -1.f; + + return iter->second.mTime; + } + + void Animation::disable(const std::string &groupname) + { + AnimStateMap::iterator iter = mStates.find(groupname); + if(iter != mStates.end()) + mStates.erase(iter); + resetActiveGroups(); + } + + float Animation::getVelocity(const std::string &groupname) const + { + return 0.f; + /* + // Look in reverse; last-inserted source has priority. + AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); + for(;animsrc != mAnimSources.rend();++animsrc) + { + const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + if(findGroupStart(keys, groupname) != keys.end()) + break; + } + if(animsrc == mAnimSources.rend()) + return 0.0f; + + float velocity = 0.0f; + const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + const std::vector >&ctrls = (*animsrc)->mControllers[0]; + for(size_t i = 0;i < ctrls.size();i++) + { + NifOsg::NodeTargetValue *dstval; + dstval = static_cast*>(ctrls[i].getDestination().getPointer()); + if(dstval->getNode() == mNonAccumRoot) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + + // If there's no velocity, keep looking + if(!(velocity > 1.0f)) + { + AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); + while(*animiter != *animsrc) + ++animiter; + + while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) + { + const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; + const std::vector >&ctrls = (*animiter)->mControllers[0]; + for(size_t i = 0;i < ctrls.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = static_cast*>(ctrls[i].getDestination().getPointer()); + if(dstval->getNode() == mNonAccumRoot) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + } + } + + return velocity; + */ } osg::Vec3f Animation::runAnimation(float duration) { + osg::Vec3f movement(0.f, 0.f, 0.f); + AnimStateMap::iterator stateiter = mStates.begin(); + while(stateiter != mStates.end()) + { + AnimState &state = stateiter->second; + const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); + + float timepassed = duration * state.mSpeedMult; + while(state.mPlaying) + { + float targetTime; + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + goto handle_loop; + + targetTime = state.mTime + timepassed; + if(textkey == textkeys.end() || textkey->first > targetTime) + { + //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + // updatePosition(state.mTime, targetTime, movement); + state.mTime = std::min(targetTime, state.mStopTime); + } + else + { + //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + // updatePosition(state.mTime, textkey->first, movement); + state.mTime = textkey->first; + } + + state.mPlaying = (state.mTime < state.mStopTime); + timepassed = targetTime - state.mTime; + + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, stateiter->first, textkey, textkeys); + ++textkey; + } + + if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + { + handle_loop: + state.mLoopCount--; + state.mTime = state.mLoopStartTime; + state.mPlaying = true; + + textkey = textkeys.lower_bound(state.mTime); + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, stateiter->first, textkey, textkeys); + ++textkey; + } + + if(state.mTime >= state.mLoopStopTime) + break; + } + + if(timepassed <= 0.0f) + break; + } + + if(!state.mPlaying && state.mAutoDisable) + { + mStates.erase(stateiter++); + + resetActiveGroups(); + } + else + ++stateiter; + } + updateEffects(duration); - return osg::Vec3f(); + return movement; } void Animation::setObjectRoot(const std::string &model) @@ -117,7 +780,14 @@ namespace MWRender mObjectRoot->getParent(0)->removeChild(mObjectRoot); } + mNodeMap.clear(); + mAnimSourceControllers.clear(); + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + + NodeMapVisitor visitor; + mObjectRoot->accept(visitor); + mNodeMap = visitor.getNodeMap(); } osg::Group* Animation::getObjectRoot() @@ -318,6 +988,15 @@ namespace MWRender } } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) + { + // FIXME: hold a pointer instead of searching every frame + AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); + if(iter != mAnimation->mStates.end()) + return iter->second.mTime; + return 0.0f; + } + float EffectAnimationTime::getValue(osg::NodeVisitor*) { return mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ea47a5b794..a04544ac8c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,9 +15,13 @@ namespace Resource class ResourceSystem; } +namespace NifOsg +{ + class KeyframeHolder; +} + namespace MWRender { -class Camera; class EffectAnimationTime : public SceneUtil::ControllerSource { @@ -68,7 +72,7 @@ protected: const std::string &getAnimName() const { return mAnimationName; } - virtual float getValue(); + virtual float getValue(osg::NodeVisitor* nv); }; class NullAnimationTime : public SceneUtil::ControllerSource @@ -80,16 +84,19 @@ protected: } }; + struct AnimSource + { + osg::ref_ptr mKeyframes; - /* - struct AnimSource : public Ogre::AnimationAlloc { - //NifOgre::TextKeyMap mTextKeys; - std::vector > mControllers[sNumGroups]; + typedef std::map > ControllerMap; + + ControllerMap mControllerMap[sNumGroups]; + + const std::multimap& getTextKeys(); }; - typedef std::vector< Ogre::SharedPtr > AnimSourceList; - */ + struct AnimState { - //Ogre::SharedPtr mSource; + boost::shared_ptr mSource; float mStartTime; float mLoopStartTime; float mLoopStopTime; @@ -111,15 +118,38 @@ protected: { } }; typedef std::map AnimStateMap; + AnimStateMap mStates; + + typedef std::vector > AnimSourceList; + AnimSourceList mAnimSources; osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; + // The node expected to accumulate movement during movement animations. + osg::ref_ptr mAccumRoot; + + // The controller animating that node. + osg::ref_ptr mAccumCtrl; + + // Keep track of keyframe controllers from external files that we added to our scene graph. + // We may need to rebuild these controllers when the active animation groups / sources change. + typedef std::map, osg::ref_ptr > AnimSourceControllerMap; + AnimSourceControllerMap mAnimSourceControllers; + + boost::shared_ptr mAnimationTimePtr[sNumGroups]; + + // Stored in all lowercase for a case-insensitive lookup + typedef std::map > NodeMap; + NodeMap mNodeMap; + MWWorld::Ptr mPtr; Resource::ResourceSystem* mResourceSystem; + osg::Vec3f mAccumulate; + /// @brief Detaches the node from its parent when the object goes out of scope. class PartHolder { @@ -160,34 +190,25 @@ protected: /* Sets the appropriate animations on the bone groups based on priority. */ - //void resetActiveGroups(); + void resetActiveGroups(); - //static size_t detectAnimGroup(const Ogre::Node *node); - - /* - static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, - NifOgre::NodeTargetValue *nonaccumctrl, - const Ogre::Vector3 &accum, - const std::string &groupname); - */ + size_t detectAnimGroup(osg::Node* node); /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); - //static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); - /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns * false. */ - //bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, - // const std::string &groupname, const std::string &start, const std::string &stop, - // float startpoint, bool loopfallback); + bool reset(AnimState &state, const std::multimap &keys, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint, bool loopfallback); - //void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key, - // const NifOgre::TextKeyMap& map); + void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map); /* Sets the root model of the object. * @@ -235,12 +256,12 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - //bool hasAnimation(const std::string &anim); + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value // should be on the scale of 0 to 1. - //void setAccumulation(const Ogre::Vector3 &accum); + void setAccumulation(const osg::Vec3f& accum); /** Plays an animation. * \param groupname Name of the animation group to play. @@ -262,20 +283,20 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - //void play(const std::string &groupname, int priority, int groups, bool autodisable, - // float speedmult, const std::string &start, const std::string &stop, - // float startpoint, size_t loops, bool loopfallback=false); + void play(const std::string &groupname, int priority, int groups, bool autodisable, + float speedmult, const std::string &start, const std::string &stop, + float startpoint, size_t loops, bool loopfallback=false); /** If the given animation group is currently playing, set its remaining loop count to '0'. */ - //void stopLooping(const std::string& groupName); + void stopLooping(const std::string& groupName); /** Adjust the speed multiplier of an already playing animation. */ - //void adjustSpeedMult (const std::string& groupname, float speedmult); + void adjustSpeedMult (const std::string& groupname, float speedmult); /** Returns true if the named animation group is playing. */ - //bool isPlaying(const std::string &groupname) const; + bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. //bool upperBodyReady() const; @@ -286,30 +307,34 @@ public: * \param speedmult Stores the animation speed multiplier * \return True if the animation is active, false otherwise. */ - //bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; + bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - //float getStartTime(const std::string &groupname) const; + float getStartTime(const std::string &groupname) const; /// Get the absolute position in the animation track of the text key - //float getTextKeyTime(const std::string &textKey) const; + float getTextKeyTime(const std::string &textKey) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. - //float getCurrentTime(const std::string& groupname) const; + float getCurrentTime(const std::string& groupname) const; /** Disables the specified animation group; * \param groupname Animation group to disable. */ - //void disable(const std::string &groupname); - //void changeGroups(const std::string &groupname, int group); + void disable(const std::string &groupname); + void changeGroups(const std::string &groupname, int group); /** Retrieves the velocity (in units per second) that the animation will move. */ - //float getVelocity(const std::string &groupname) const; + float getVelocity(const std::string &groupname) const; virtual osg::Vec3f runAnimation(float duration); /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); + +private: + Animation(const Animation&); + void operator=(Animation&); }; class ObjectAnimation : public Animation { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 241ea56a36..721215749a 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -22,16 +22,16 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { - //MWWorld::LiveCellRef *ref = mPtr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { setObjectRoot(model /* , baseonly = false */); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - // addAnimSource("meshes\\xbase_anim.nif"); - //addAnimSource(model); + if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + addAnimSource("meshes\\xbase_anim.nif"); + addAnimSource(model); } } @@ -41,16 +41,16 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const , mShowWeapons(false) , mShowCarriedLeft(false) { - //MWWorld::LiveCellRef *ref = mPtr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); if(!model.empty()) { setObjectRoot(model /* , baseonly = false*/); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); - //if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - // addAnimSource("meshes\\xbase_anim.nif"); - //addAnimSource(model); + if((ref->mBase->mFlags&ESM::Creature::Bipedal)) + addAnimSource("meshes\\xbase_anim.nif"); + addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03af50c717..ab32864bd3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -281,7 +281,6 @@ void NpcAnimation::updateNpcBase() smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); setObjectRoot(smodel /*, baseonly = true*/); - /* if(mViewMode != VM_FirstPerson) { addAnimSource(smodel); @@ -310,7 +309,6 @@ void NpcAnimation::updateNpcBase() addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } - */ for(size_t i = 0;i < ESM::PRT_Count;i++) removeIndividualPart((ESM::PartReferenceType)i); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4b1fa6d5b8..e278662aa2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -167,6 +167,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + anim->play("idle2", 0, Animation::Group_All, false, 1.f, "loop start", "loop stop", 0.f, 50); //testing if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3b3ae4b2c8..38ead09252 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -413,7 +413,7 @@ namespace NifOsg continue; osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(key)); + callback->setFunction(boost::shared_ptr(new NifOsg::ControllerFunction(key))); target.mKeyframeControllers[strdata->string] = callback; } @@ -459,9 +459,9 @@ namespace NifOsg { bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; if (autoPlay) - toSetup->mSource = boost::shared_ptr(new SceneUtil::FrameTimeSource); + toSetup->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); + toSetup->setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index b6e9b1c8fa..f2f3c25349 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -44,7 +44,8 @@ namespace NifOsg public: TextKeyMap mTextKeys; - std::map > mKeyframeControllers; + typedef std::map > KeyframeControllerMap; + KeyframeControllerMap mKeyframeControllers; }; /// The main class responsible for loading NIF files into an OSG-Scenegraph. diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 79a75063a9..6beb1bc80e 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -23,6 +23,26 @@ namespace SceneUtil return mFunction->calculate(mSource->getValue(nv)); } + void Controller::setSource(boost::shared_ptr source) + { + mSource = source; + } + + void Controller::setFunction(boost::shared_ptr function) + { + mFunction = function; + } + + boost::shared_ptr Controller::getSource() const + { + return mSource; + } + + boost::shared_ptr Controller::getFunction() const + { + return mFunction; + } + FrameTimeSource::FrameTimeSource() { } @@ -85,8 +105,8 @@ namespace SceneUtil void AssignControllerSourcesVisitor::visit(osg::Node&, Controller &ctrl) { - if (!ctrl.mSource.get()) - ctrl.mSource = mToAssign; + if (!ctrl.getSource()) + ctrl.setSource(mToAssign); } FindMaxControllerLengthVisitor::FindMaxControllerLengthVisitor() @@ -97,8 +117,8 @@ namespace SceneUtil void FindMaxControllerLengthVisitor::visit(osg::Node &, Controller &ctrl) { - if (ctrl.mFunction) - mMaxLength = std::max(mMaxLength, ctrl.mFunction->getMaximum()); + if (ctrl.getFunction()) + mMaxLength = std::max(mMaxLength, ctrl.getFunction()->getMaximum()); } float FindMaxControllerLengthVisitor::getMaxLength() const diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 6086663bda..84fe6e8967 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -41,6 +41,13 @@ namespace SceneUtil float getInputValue(osg::NodeVisitor* nv); + void setSource(boost::shared_ptr source); + void setFunction(boost::shared_ptr function); + + boost::shared_ptr getSource() const; + boost::shared_ptr getFunction() const; + + private: boost::shared_ptr mSource; // The source value gets passed through this function before it's passed on to the DestValue. From 86b4a610cb54c4910a3eac5492a65c9acee510af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 22:46:07 +0200 Subject: [PATCH 0161/1812] Movement accumulation works --- apps/openmw/mwrender/animation.cpp | 98 +++++++++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 7 ++- apps/openmw/mwrender/objects.cpp | 1 - 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d291e0fd0e..f490baefe5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -168,10 +169,39 @@ namespace namespace MWRender { + class ResetAccumRootCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::MatrixTransform* transform = static_cast(node); + + osg::Matrix mat = transform->getMatrix(); + osg::Vec3f position = mat.getTrans(); + position = osg::componentMultiply(mResetAxes, position); + mat.setTrans(position); + transform->setMatrix(mat); + + traverse(node, nv); + } + + void setAccumulate(const osg::Vec3f& accumulate) + { + // anything that accumulates (1.f) should be reset in the callback to (0.f) + mResetAxes.x() = accumulate.x() != 0.f ? 0.f : 1.f; + mResetAxes.y() = accumulate.y() != 0.f ? 0.f : 1.f; + mResetAxes.z() = accumulate.z() != 0.f ? 0.f : 1.f; + } + + private: + osg::Vec3f mResetAxes; + }; + Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mPtr(ptr) , mInsert(parentNode) , mResourceSystem(resourceSystem) + , mAccumulate(1.f, 1.f, 0.f) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime(this)); @@ -191,6 +221,9 @@ namespace MWRender void Animation::setAccumulation(const osg::Vec3f& accum) { mAccumulate = accum; + + if (mResetAccumRootCallback) + mResetAccumRootCallback->setAccumulate(mAccumulate); } size_t Animation::detectAnimGroup(osg::Node* node) @@ -322,6 +355,16 @@ namespace MWRender void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap& map) { + const std::string &evt = key->second; + + size_t off = groupname.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "loop start") == 0) + state.mLoopStartTime = key->first; + else if(evt.compare(off, len, "loop stop") == 0) + state.mLoopStopTime = key->first; + // TODO: forward to listener? } @@ -406,16 +449,6 @@ namespace MWRender std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); - } - */ } bool Animation::reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) @@ -504,6 +537,8 @@ namespace MWRender osg::Node* node = it->first; node->removeUpdateCallback(it->second); } + if (mResetAccumRootCallback && mAccumRoot) + mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); mAnimSourceControllers.clear(); mAccumCtrl = NULL; @@ -538,26 +573,19 @@ namespace MWRender mAnimSourceControllers[node] = it->second; if (grp == 0 && node == mAccumRoot) + { mAccumCtrl = it->second; + + if (!mResetAccumRootCallback) + { + mResetAccumRootCallback = new ResetAccumRootCallback; + mResetAccumRootCallback->setAccumulate(mAccumulate); + } + mAccumRoot->addUpdateCallback(mResetAccumRootCallback); + } } } } - - //if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) - // return; - - /* - AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); - if(state == mStates.end()) - { - //if (mAccumRoot && mNonAccumRoot) - // mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); - return; - } - */ - - //if (mAccumRoot && mNonAccumCtrl) - // mAccumRoot->setPosition(-mNonAccumCtrl->getTranslation(state->second.mTime)*mAccumulate); } void Animation::changeGroups(const std::string &groupname, int groups) @@ -695,6 +723,13 @@ namespace MWRender */ } + void Animation::updatePosition(float oldtime, float newtime, osg::Vec3f& position) + { + // Get the difference from the last update, and move the position + osg::Vec3f off = osg::componentMultiply(mAccumCtrl->getTranslation(newtime), mAccumulate); + position += off - osg::componentMultiply(mAccumCtrl->getTranslation(oldtime), mAccumulate); + } + osg::Vec3f Animation::runAnimation(float duration) { osg::Vec3f movement(0.f, 0.f, 0.f); @@ -716,14 +751,14 @@ namespace MWRender targetTime = state.mTime + timepassed; if(textkey == textkeys.end() || textkey->first > targetTime) { - //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - // updatePosition(state.mTime, targetTime, movement); + if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + updatePosition(state.mTime, targetTime, movement); state.mTime = std::min(targetTime, state.mStopTime); } else { - //if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - // updatePosition(state.mTime, textkey->first, movement); + if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) + updatePosition(state.mTime, textkey->first, movement); state.mTime = textkey->first; } @@ -779,9 +814,12 @@ namespace MWRender { mObjectRoot->getParent(0)->removeChild(mObjectRoot); } + mObjectRoot = NULL; mNodeMap.clear(); mAnimSourceControllers.clear(); + mAccumRoot = NULL; + mAccumCtrl = NULL; mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a04544ac8c..083213c85b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,6 +23,8 @@ namespace NifOsg namespace MWRender { +class ResetAccumRootCallback; + class EffectAnimationTime : public SceneUtil::ControllerSource { private: @@ -133,6 +135,9 @@ protected: // The controller animating that node. osg::ref_ptr mAccumCtrl; + // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system + osg::ref_ptr mResetAccumRootCallback; + // Keep track of keyframe controllers from external files that we added to our scene graph. // We may need to rebuild these controllers when the active animation groups / sources change. typedef std::map, osg::ref_ptr > AnimSourceControllerMap; @@ -196,7 +201,7 @@ protected: /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ - //void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position); + void updatePosition(float oldtime, float newtime, osg::Vec3f& position); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index e278662aa2..4b1fa6d5b8 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -167,7 +167,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - anim->play("idle2", 0, Animation::Group_All, false, 1.f, "loop start", "loop stop", 0.f, 50); //testing if (anim->getObjectRoot()) anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); From 6f3e920f85c7786db42cea88edb6fad2ab3e78c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 23:30:06 +0200 Subject: [PATCH 0162/1812] Animation port complete --- apps/openmw/mwrender/animation.cpp | 66 +++++++++++++++------- apps/openmw/mwrender/animation.hpp | 7 ++- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 5 +- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f490baefe5..27e54b2284 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -310,6 +311,18 @@ namespace MWRender } } + void Animation::clearAnimSources() + { + mStates.clear(); + + for(size_t i = 0;i < sNumGroups;i++) + mAnimationTimePtr[i]->setAnimName(std::string()); + + mAccumCtrl = NULL; + + mAnimSources.clear(); + } + bool Animation::hasAnimation(const std::string &anim) { AnimSourceList::const_iterator iter(mAnimSources.begin()); @@ -668,13 +681,14 @@ namespace MWRender float Animation::getVelocity(const std::string &groupname) const { - return 0.f; - /* + if (!mAccumRoot) + return 0.0f; + // Look in reverse; last-inserted source has priority. AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); for(;animsrc != mAnimSources.rend();++animsrc) { - const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; + const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); if(findGroupStart(keys, groupname) != keys.end()) break; } @@ -682,15 +696,14 @@ namespace MWRender return 0.0f; float velocity = 0.0f; - const NifOsg::TextKeyMap &keys = (*animsrc)->mTextKeys; - const std::vector >&ctrls = (*animsrc)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); + + const AnimSource::ControllerMap& ctrls = (*animsrc)->mControllerMap[0]; + for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) { - NifOsg::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); break; } } @@ -704,15 +717,14 @@ namespace MWRender while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) { - const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; - const std::vector >&ctrls = (*animiter)->mControllers[0]; - for(size_t i = 0;i < ctrls.size();i++) + const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); + + const AnimSource::ControllerMap& ctrls = (*animiter)->mControllerMap[0]; + for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) { - NifOgre::NodeTargetValue *dstval; - dstval = static_cast*>(ctrls[i].getDestination().getPointer()); - if(dstval->getNode() == mNonAccumRoot) + if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { - velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); break; } } @@ -720,7 +732,6 @@ namespace MWRender } return velocity; - */ } void Animation::updatePosition(float oldtime, float newtime, osg::Vec3f& position) @@ -808,7 +819,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton) { if (mObjectRoot) { @@ -821,7 +832,20 @@ namespace MWRender mAccumRoot = NULL; mAccumCtrl = NULL; - mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + if (!forceskeleton) + mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + else + { + osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); + if (!dynamic_cast(newObjectRoot.get())) + { + osg::ref_ptr skel = new SceneUtil::Skeleton; + skel->addChild(newObjectRoot); + newObjectRoot = skel; + } + mInsert->addChild(newObjectRoot); + mObjectRoot = newObjectRoot; + } NodeMapVisitor visitor; mObjectRoot->accept(visitor); @@ -1062,7 +1086,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model); + setObjectRoot(model, false); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 083213c85b..d5b2de81b5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -215,12 +215,13 @@ protected: void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap& map); - /* Sets the root model of the object. + /** Sets the root model of the object. * * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. + * @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually. */ - void setObjectRoot(const std::string &model); + void setObjectRoot(const std::string &model, bool forceskeleton); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif @@ -230,7 +231,7 @@ protected: /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); - //void clearAnimSources(); + void clearAnimSources(); osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 721215749a..d2abf14135 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,7 +26,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model /* , baseonly = false */); + setObjectRoot(model, false /* , baseonly = false */); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) @@ -45,7 +45,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model /* , baseonly = false*/); + setObjectRoot(model, true /* , baseonly = false*/); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ab32864bd3..80dbf3c7f6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -233,7 +233,7 @@ void NpcAnimation::rebuild() void NpcAnimation::updateNpcBase() { - //clearAnimSources(); + clearAnimSources(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); @@ -279,7 +279,8 @@ void NpcAnimation::updateNpcBase() : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel /*, baseonly = true*/); + + setObjectRoot(smodel, true /*, baseonly = true*/); if(mViewMode != VM_FirstPerson) { From 1c0e3a648839bd2121573c6077e9b2652d03cfbb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Apr 2015 23:50:46 +0200 Subject: [PATCH 0163/1812] rotateObject, scaleObject --- apps/openmw/mwrender/objects.cpp | 19 ------------------- apps/openmw/mwrender/renderingmanager.cpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 5 +++++ apps/openmw/mwworld/scene.cpp | 23 +++++++---------------- apps/openmw/mwworld/scene.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 17 +++++++---------- 6 files changed, 39 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4b1fa6d5b8..be21b2bec0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -102,25 +102,6 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(osg::Vec3(f[0], f[1], f[2])); - insert->setScale(osg::Vec3(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale())); - - // Convert MW rotation to a quaternion: - f = ptr.getCellRef().getPosition().rot; - - // Rotate around X axis - osg::Quat xr(-f[0], osg::Vec3(1,0,0)); - - // Rotate around Y axis - osg::Quat yr(-f[1], osg::Vec3(0,1,0)); - - // Rotate around Z axis - osg::Quat zr(-f[2], osg::Vec3(0,0,1)); - - // Rotates first around z, then y, then x - if (ptr.getClass().isActor()) - insert->setAttitude(zr); - else - insert->setAttitude(zr*yr*xr); ptr.getRefData().setBaseNode(insert); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5199e6e126..be23ebc2f1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -211,6 +212,25 @@ namespace MWRender mSky->update(dt); } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) + { + //if(ptr.getRefData().getHandle() == mCamera->getHandle() && + // !mCamera->isVanityOrPreviewModeEnabled()) + // mCamera->rotateCamera(-rot, false); + + ptr.getRefData().getBaseNode()->setAttitude(rot); + } + + void RenderingManager::moveObject(const MWWorld::Ptr &ptr, const osg::Vec3f &pos) + { + ptr.getRefData().getBaseNode()->setPosition(pos); + } + + void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) + { + ptr.getRefData().getBaseNode()->setScale(scale); + } + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) { mEffectManager->addEffect(model, texture, worldPosition, scale); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 230885cd3f..c47317608e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -57,6 +57,11 @@ namespace MWRender void removeCell(const MWWorld::CellStore* store); + // TODO rename to setRotation/setPosition/setScale, along with the World equivalents + void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); + void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); + void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); + void setSkyEnabled(bool enabled); SkyManager* getSkyManager(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ef9e5792ba..4f689ee59b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -42,7 +42,7 @@ namespace //ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -60,7 +60,7 @@ namespace if (!ptr.getClass().isActor()) rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - ptr.getRefData().getBaseNode()->setAttitude(rot * worldRotQuat); + rendering.rotateObject(ptr, rot * worldRotQuat); //physics.rotateObject(ptr); } } @@ -102,12 +102,12 @@ namespace try { addObject(ptr, /*mPhysics, */mRendering); - //updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); if (ptr.getRefData().getBaseNode()) { float scale = ptr.getCellRef().getScale(); ptr.getClass().adjustScale(ptr, scale); - //mRendering.scaleObject(ptr, Ogre::Vector3(scale)); + mRendering.scaleObject(ptr, osg::Vec3f(scale, scale, scale)); } ptr.getClass().adjustPosition (ptr, false); } @@ -130,16 +130,7 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - //::updateObjectLocalRotation(ptr, *mPhysics, mRendering); - } - - void Scene::updateObjectRotation (const Ptr& ptr) - { - if(ptr.getRefData().getBaseNodeOld() != 0) - { - //mRendering.rotateObject(ptr); - //mPhysics->rotateObject(ptr); - } + ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); } void Scene::getGridCenter(int &cellX, int &cellY) @@ -563,8 +554,8 @@ namespace MWWorld try { addObject(ptr, /* *mPhysics, */mRendering); - //MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - //MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) { diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 4e8f6a11b6..0ae1ff4da6 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -117,8 +117,6 @@ namespace MWWorld void updateObjectLocalRotation (const Ptr& ptr); - void updateObjectRotation (const Ptr& ptr); - bool isCellActive(const CellStore &cell); Ptr searchPtrViaHandle (const std::string& handle); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2d40930b9..07c3b1b164 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1217,9 +1217,9 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove && ptr.getRefData().getBaseNodeOld()) + if (haveToMove && ptr.getRefData().getBaseNode()) { - //mRendering->moveObject(ptr, vec); + mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z)); //mPhysics->moveObject (ptr); } if (isPlayer) @@ -1256,9 +1256,9 @@ namespace MWWorld ptr.getCellRef().setScale(scale); ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNodeOld() == 0) + if(ptr.getRefData().getBaseNode() == 0) return; - //mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); + mRendering->scaleObject(ptr, osg::Vec3f(scale,scale,scale)); //mPhysics->scaleObject(ptr); } @@ -1307,13 +1307,10 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNodeOld() == 0) + if(ptr.getRefData().getBaseNode() == 0) return; - if (ptr.getClass().isActor()) - mWorldScene->updateObjectRotation(ptr); - else - mWorldScene->updateObjectLocalRotation(ptr); + mWorldScene->updateObjectLocalRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) @@ -1329,7 +1326,7 @@ namespace MWWorld ptr.getRefData().setLocalRotation(rot); - if (ptr.getRefData().getBaseNodeOld() != 0) + if (ptr.getRefData().getBaseNode() != 0) { mWorldScene->updateObjectLocalRotation(ptr); } From 9f12e539565bd71a7b3d196361c11e126ad1d177 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 14:49:20 +0200 Subject: [PATCH 0164/1812] Scale NPCs by their Weight property (Fixes #814) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 15 ++++++++++++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 5 +++-- apps/openmw/mwworld/scene.cpp | 24 ++++++++++++++++++------ apps/openmw/mwworld/scene.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 12 +++--------- 10 files changed, 42 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d4a50ce812..a85c648f45 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -893,7 +893,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const { MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index e11529b2e8..5585835fd2 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -157,7 +157,7 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b28fb04997..8be551dd22 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1110,7 +1110,7 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -1119,9 +1119,18 @@ namespace MWClass MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); if (ref->mBase->isMale()) - scale *= race->mData.mHeight.mMale; + { + scale.x() *= race->mData.mWeight.mMale; + scale.y() *= race->mData.mWeight.mMale; + scale.z() *= race->mData.mHeight.mMale; + } else - scale *= race->mData.mHeight.mFemale; + { + scale.x() *= race->mData.mWeight.mFemale; + scale.y() *= race->mData.mWeight.mFemale; + scale.z() *= race->mData.mHeight.mFemale; + } + } int Npc::getServices(const MWWorld::Ptr &actor) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 27beeb626e..b745463956 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -129,7 +129,7 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, float &scale) const; + virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const; virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6fa9ba9b69..79444e1109 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -295,7 +295,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr,float& scale) const + void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 782aa78151..3f65af05c2 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -266,7 +266,7 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ae6cce6c7c..623a795762 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -769,10 +769,11 @@ namespace MWWorld if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec (scale,scale,scale); if (!ptr.getClass().isNpc()) // NOTE: Ignoring Npc::adjustScale (race height) on purpose. This is a bug in MW and must be replicated for compatibility reasons - ptr.getClass().adjustScale(ptr, scale); - act->setScale(scale); + ptr.getClass().adjustScale(ptr, scaleVec); + act->setScale(scaleVec.x()); } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 4f689ee59b..191a8ffeff 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -65,6 +65,18 @@ namespace } } + void updateObjectScale(const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + MWRender::RenderingManager& rendering) + { + if (ptr.getRefData().getBaseNode() != NULL) + { + float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec (scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec); + rendering.scaleObject(ptr, scaleVec); + } + } + struct InsertFunctor { MWWorld::CellStore& mCell; @@ -103,12 +115,7 @@ namespace { addObject(ptr, /*mPhysics, */mRendering); updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); - if (ptr.getRefData().getBaseNode()) - { - float scale = ptr.getCellRef().getScale(); - ptr.getClass().adjustScale(ptr, scale); - mRendering.scaleObject(ptr, osg::Vec3f(scale, scale, scale)); - } + updateObjectScale(ptr, /*mPhysics,*/ mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) @@ -133,6 +140,11 @@ namespace MWWorld ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); } + void Scene::updateObjectScale(const Ptr &ptr) + { + ::updateObjectScale(ptr, /* *mPhysics,*/ mRendering); + } + void Scene::getGridCenter(int &cellX, int &cellY) { int maxX = std::numeric_limits::min(); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 0ae1ff4da6..ea1a56d636 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -116,6 +116,7 @@ namespace MWWorld ///< Remove an object from the scene, but not from the world model. void updateObjectLocalRotation (const Ptr& ptr); + void updateObjectScale(const Ptr& ptr); bool isCellActive(const CellStore &cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 07c3b1b164..4b1946d1c5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1254,12 +1254,8 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { ptr.getCellRef().setScale(scale); - ptr.getClass().adjustScale(ptr,scale); - if(ptr.getRefData().getBaseNode() == 0) - return; - mRendering->scaleObject(ptr, osg::Vec3f(scale,scale,scale)); - //mPhysics->scaleObject(ptr); + mWorldScene->updateObjectScale(ptr); } void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) @@ -1307,10 +1303,8 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if(ptr.getRefData().getBaseNode() == 0) - return; - - mWorldScene->updateObjectLocalRotation(ptr); + if(ptr.getRefData().getBaseNode() != 0) + mWorldScene->updateObjectLocalRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) From 42d6c6140c8d916343ade6ab595c12854a499abc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 21:55:30 +0200 Subject: [PATCH 0165/1812] Add mygui backend by chris --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/engine.cpp | 26 +- apps/openmw/engine.hpp | 6 - apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/myguidatamanager.cpp | 64 ++ apps/openmw/mwgui/myguidatamanager.hpp | 50 ++ apps/openmw/mwgui/myguiplatform.cpp | 2 + apps/openmw/mwgui/myguiplatform.hpp | 74 +++ apps/openmw/mwgui/myguirendermanager.cpp | 626 ++++++++++++++++++++ apps/openmw/mwgui/myguirendermanager.hpp | 101 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 47 +- apps/openmw/mwgui/windowmanagerimp.hpp | 19 +- apps/openmw/mwrender/renderingmanager.cpp | 6 +- libs/openengine/gui/manager.cpp | 680 ---------------------- libs/openengine/gui/manager.hpp | 53 -- 15 files changed, 962 insertions(+), 800 deletions(-) create mode 100644 apps/openmw/mwgui/myguidatamanager.cpp create mode 100644 apps/openmw/mwgui/myguidatamanager.hpp create mode 100644 apps/openmw/mwgui/myguiplatform.cpp create mode 100644 apps/openmw/mwgui/myguiplatform.hpp create mode 100644 apps/openmw/mwgui/myguirendermanager.cpp create mode 100644 apps/openmw/mwgui/myguirendermanager.hpp delete mode 100644 libs/openengine/gui/manager.cpp delete mode 100644 libs/openengine/gui/manager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 84dcb60fae..3349a1afe8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen + draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager ) add_openmw_dir (mwdialogue @@ -107,6 +107,9 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +# for MyGUI platform +find_package(OpenGL REQUIRED) + if (NOT ANDROID) add_executable(openmw ${OPENMW_FILES} @@ -137,6 +140,7 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} + ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" components diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 64457834c7..7698c31461 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -218,13 +218,6 @@ OMW::Engine::~Engine() SDL_Quit(); } -// add resources directory -// \note This function works recursively. - -void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) -{ -} - void OMW::Engine::enableFSStrict(bool fsStrict) { mFSStrict = fsStrict; @@ -309,16 +302,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) #endif } - // This has to be added BEFORE MyGUI is initialized, as it needs - // to find core.xml here. - - addResourcesDirectory(mCfgMgr.getCachePath ().string()); - - addResourcesDirectory(mResDir / "mygui"); - addResourcesDirectory(mResDir / "water"); - addResourcesDirectory(mResDir / "shadows"); - addResourcesDirectory(mResDir / "materials"); - //OEngine::Render::WindowSettings windowSettings; //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); //windowSettings.window_border = settings.getBool("window border", "Video"); @@ -369,9 +352,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); //mEnvironment.setInputManager (input); - MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); + std::string myguiResources = (mResDir / "mygui").string(); + osg::ref_ptr guiRoot = new osg::Group; + rootNode->addChild(guiRoot); + MWGui::WindowManager* window = new MWGui::WindowManager(&mViewer, guiRoot, mResourceSystem->getTextureManager(), + mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, + mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index de09082d88..8c73920bda 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -99,16 +99,10 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; - //Nif::Cache mNifCache; - // not implemented Engine (const Engine&); Engine& operator= (const Engine&); - /// add resources directory - /// \note This function works recursively. - void addResourcesDirectory (const boost::filesystem::path& path); - void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 6ad4da3bfb..0a8667d808 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -53,7 +53,7 @@ namespace MWGui std::string output = sstream.str(); mVersionText->setCaption(output); - mHasAnimatedMenu = (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); + mHasAnimatedMenu = 0;//(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); updateMenu(); } diff --git a/apps/openmw/mwgui/myguidatamanager.cpp b/apps/openmw/mwgui/myguidatamanager.cpp new file mode 100644 index 0000000000..5ba54b0092 --- /dev/null +++ b/apps/openmw/mwgui/myguidatamanager.cpp @@ -0,0 +1,64 @@ +#include "myguidatamanager.hpp" + +#include + +#include +#include + +#include + +namespace MWGui +{ + +void DataManager::setResourcePath(const std::string &path) +{ + mResourcePath = path; +} + +MyGUI::IDataStream *DataManager::getData(const std::string &name) +{ + std::string fullpath = getDataPath(name); + std::auto_ptr stream; + stream.reset(new boost::filesystem::ifstream); + stream->open(fullpath, std::ios::binary); + if (stream->fail()) + { + std::cerr << "DataManager::getData: Failed to open '" << name << "'" << std::endl; + return NULL; + } + return new MyGUI::DataFileStream(stream.release()); +} + +void DataManager::freeData(MyGUI::IDataStream *data) +{ + delete data; +} + +bool DataManager::isDataExist(const std::string &name) +{ + std::string fullpath = mResourcePath + "/" + name; + return boost::filesystem::exists(fullpath); +} + +const MyGUI::VectorString &DataManager::getDataListNames(const std::string &pattern) +{ + // TODO: pattern matching (unused?) + static MyGUI::VectorString strings; + strings.clear(); + strings.push_back(getDataPath(pattern)); + return strings; +} + +const std::string &DataManager::getDataPath(const std::string &name) +{ + static std::string result; + result.clear(); + if (!isDataExist(name)) + { + return result; + } + result = mResourcePath + "/" + name; + return result; +} + +} diff --git a/apps/openmw/mwgui/myguidatamanager.hpp b/apps/openmw/mwgui/myguidatamanager.hpp new file mode 100644 index 0000000000..eaf60f8b9d --- /dev/null +++ b/apps/openmw/mwgui/myguidatamanager.hpp @@ -0,0 +1,50 @@ +#ifndef OPENMW_MWGUI_MYGUIDATAMANAGER_H +#define OPENMW_MWGUI_MYGUIDATAMANAGER_H + +#include + +namespace MWGui +{ + + +class DataManager : public MyGUI::DataManager +{ +public: + void initialise() {} + void shutdown() {} + + void setResourcePath(const std::string& path); + + /** Get data stream from specified resource name. + @param _name Resource name (usually file name). + */ + virtual MyGUI::IDataStream* getData(const std::string& _name); + + /** Free data stream. + @param _data Data stream. + */ + virtual void freeData(MyGUI::IDataStream* _data); + + /** Is data with specified name exist. + @param _name Resource name. + */ + virtual bool isDataExist(const std::string& _name); + + /** Get all data names with names that matches pattern. + @param _pattern Pattern to match (for example "*.layout"). + */ + virtual const MyGUI::VectorString& getDataListNames(const std::string& _pattern); + + /** Get full path to data. + @param _name Resource name. + @return Return full path to specified data. + */ + virtual const std::string& getDataPath(const std::string& _name); + +private: + std::string mResourcePath; +}; + +} + +#endif diff --git a/apps/openmw/mwgui/myguiplatform.cpp b/apps/openmw/mwgui/myguiplatform.cpp new file mode 100644 index 0000000000..01d6ca567f --- /dev/null +++ b/apps/openmw/mwgui/myguiplatform.cpp @@ -0,0 +1,2 @@ +#include "myguiplatform.hpp" + diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/apps/openmw/mwgui/myguiplatform.hpp new file mode 100644 index 0000000000..4c3e701439 --- /dev/null +++ b/apps/openmw/mwgui/myguiplatform.hpp @@ -0,0 +1,74 @@ +#ifndef OPENMW_MWGUI_MYGUIPLATFORM_H +#define OPENMW_MWGUI_MYGUIPLATFORM_H + +#include "MyGUI_Prerequest.h" +#include "MyGUI_DummyRenderManager.h" +#include "MyGUI_DummyDataManager.h" +#include "MyGUI_DummyDiagnostic.h" +#include "MyGUI_LogManager.h" + +#include "myguirendermanager.hpp" +#include "myguidatamanager.hpp" + +namespace MWGui +{ + + class Platform + { + public: + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) : + mLogManager(nullptr), + mRenderManager(nullptr), + mDataManager(nullptr) + { + mLogManager = new MyGUI::LogManager(); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager); + mDataManager = new DataManager(); + } + + ~Platform() + { + delete mRenderManager; + mRenderManager = nullptr; + delete mDataManager; + mDataManager = nullptr; + delete mLogManager; + mLogManager = nullptr; + } + + void initialise(const std::string& resourcePath, const std::string& _logName = MYGUI_PLATFORM_LOG_FILENAME) + { + if (!_logName.empty()) + MyGUI::LogManager::getInstance().createDefaultSource(_logName); + + mDataManager->setResourcePath(resourcePath); + + mRenderManager->initialise(); + mDataManager->initialise(); + } + + void shutdown() + { + //mRenderManager->shutdown(); + mDataManager->shutdown(); + } + + RenderManager* getRenderManagerPtr() + { + return mRenderManager; + } + + DataManager* getDataManagerPtr() + { + return mDataManager; + } + + private: + RenderManager* mRenderManager; + DataManager* mDataManager; + MyGUI::LogManager* mLogManager; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp new file mode 100644 index 0000000000..53a194c733 --- /dev/null +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -0,0 +1,626 @@ +#include "myguirendermanager.hpp" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#define MYGUI_PLATFORM_LOG_SECTION "Platform" +#define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) + +#define MYGUI_PLATFORM_EXCEPT(dest) do { \ + MYGUI_PLATFORM_LOG(Critical, dest); \ + MYGUI_DBG_BREAK;\ + std::ostringstream stream; \ + stream << dest << "\n"; \ + MYGUI_BASE_EXCEPT(stream.str().c_str(), "MyGUI"); \ +} while(0) + +#define MYGUI_PLATFORM_ASSERT(exp, dest) do { \ + if ( ! (exp) ) \ + { \ + MYGUI_PLATFORM_LOG(Critical, dest); \ + MYGUI_DBG_BREAK;\ + std::ostringstream stream; \ + stream << dest << "\n"; \ + MYGUI_BASE_EXCEPT(stream.str().c_str(), "MyGUI"); \ + } \ +} while(0) + +namespace +{ + +// Proxy to forward a Drawable's draw call to RenderManager::drawFrame +class Renderable : public osg::Drawable { + MWGui::RenderManager *mParent; + + virtual void drawImplementation(osg::RenderInfo &renderInfo) const + { mParent->drawFrame(renderInfo); } + +public: + Renderable(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Drawable(copy, copyop) + , mParent(copy.mParent) + { } + + META_Object(MWGui, Renderable) +}; + +// Proxy to forward an OSG resize event to RenderManager::setViewSize +class ResizeHandler : public osgGA::GUIEventHandler { + MWGui::RenderManager *mParent; + + virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) + { + if(ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) + { + int width = ea.getWindowWidth(); + int height = ea.getWindowHeight(); + mParent->setViewSize(width, height); + } + return false; + } + +public: + ResizeHandler(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) + , mParent(copy.mParent) + { } + + META_Object(MWGui, ResizeHandler) +}; + +} + + +namespace MWGui +{ + +class OSGVertexBuffer : public MyGUI::IVertexBuffer +{ + osg::ref_ptr mBuffer; + osg::ref_ptr mPositionArray; + osg::ref_ptr mColorArray; + osg::ref_ptr mTexCoordArray; + std::vector mLockedData; + + size_t mNeedVertexCount; + +public: + OSGVertexBuffer(); + virtual ~OSGVertexBuffer(); + + virtual void setVertexCount(size_t count); + virtual size_t getVertexCount(); + + virtual MyGUI::Vertex *lock(); + virtual void unlock(); + +/*internal:*/ + void destroy(); + void create(); + + osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } +}; + +OSGVertexBuffer::OSGVertexBuffer() + : mNeedVertexCount(0) +{ +} + +OSGVertexBuffer::~OSGVertexBuffer() +{ + destroy(); +} + +void OSGVertexBuffer::setVertexCount(size_t count) +{ + if(count == mNeedVertexCount) + return; + + mNeedVertexCount = count; + destroy(); + create(); +} + +size_t OSGVertexBuffer::getVertexCount() +{ + return mNeedVertexCount; +} + +MyGUI::Vertex *OSGVertexBuffer::lock() +{ + MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); + + // NOTE: Unfortunately, MyGUI wants the VBO data to be interleaved as a + // MyGUI::Vertex structure. However, OSG uses non-interleaved elements, so + // we have to give back a "temporary" structure array then copy it to the + // actual VBO arrays on unlock. This is extra unfortunate since the VBO may + // be backed by VRAM, meaning we could have up to 3 copies of the data + // (which we'll need to keep for VBOs that are continually updated). + mLockedData.resize(mNeedVertexCount, MyGUI::Vertex()); + return mLockedData.data(); +} + +void OSGVertexBuffer::unlock() +{ + osg::Vec3 *vec = &mPositionArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + vec->set(elem.x, elem.y, elem.z); + ++vec; + } + osg::Vec4ub *clr = &mColorArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + union { + MyGUI::uint32 ui; + unsigned char ub4[4]; + } val = { elem.colour }; + clr->set(val.ub4[0], val.ub4[1], val.ub4[2], val.ub4[3]); + ++clr; + } + osg::Vec2 *crds = &mTexCoordArray->front(); + for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) + { + const MyGUI::Vertex& elem = *it; + crds->set(elem.u, elem.v); + ++crds; + } + + mBuffer->dirty(); +} + +void OSGVertexBuffer::destroy() +{ + mBuffer = nullptr; + mPositionArray = nullptr; + mColorArray = nullptr; + mTexCoordArray = nullptr; + std::vector().swap(mLockedData); +} + +void OSGVertexBuffer::create() +{ + MYGUI_PLATFORM_ASSERT(!mBuffer.valid(), "Vertex buffer already exist"); + + mPositionArray = new osg::Vec3Array(mNeedVertexCount); + mColorArray = new osg::Vec4ubArray(mNeedVertexCount); + mTexCoordArray = new osg::Vec2Array(mNeedVertexCount); + mColorArray->setNormalize(true); + + mBuffer = new osg::VertexBufferObject; + mBuffer->setDataVariance(osg::Object::DYNAMIC); + mBuffer->setUsage(GL_STREAM_DRAW); + mBuffer->setArray(0, mPositionArray.get()); + mBuffer->setArray(1, mColorArray.get()); + mBuffer->setArray(2, mTexCoordArray.get()); +} + +// --------------------------------------------------------------------------- + +class OSGTexture : public MyGUI::ITexture { + std::string mName; + Resource::TextureManager* mTextureManager; + + osg::ref_ptr mLockedImage; + osg::ref_ptr mTexture; + MyGUI::PixelFormat mFormat; + MyGUI::TextureUsage mUsage; + size_t mNumElemBytes; + +public: + OSGTexture(const std::string &name, Resource::TextureManager* textureManager); + virtual ~OSGTexture(); + + virtual const std::string& getName() const { return mName; } + + virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); + virtual void loadFromFile(const std::string &fname); + virtual void saveToFile(const std::string &fname); + + virtual void destroy(); + + virtual void* lock(MyGUI::TextureUsage access); + virtual void unlock(); + virtual bool isLocked(); + + virtual int getWidth(); + virtual int getHeight(); + + virtual MyGUI::PixelFormat getFormat() { return mFormat; } + virtual MyGUI::TextureUsage getUsage() { return mUsage; } + virtual size_t getNumElemBytes() { return mNumElemBytes; } + + virtual MyGUI::IRenderTarget *getRenderTarget(); + +/*internal:*/ + osg::Texture2D *getTexture() const { return mTexture.get(); } +}; + +OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) + : mName(name) + , mTextureManager(textureManager) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) +{ +} + +OSGTexture::~OSGTexture() +{ +} + +void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) +{ + GLenum glfmt = GL_NONE; + size_t numelems = 0; + switch(format.getValue()) + { + case MyGUI::PixelFormat::L8: + glfmt = GL_LUMINANCE; + numelems = 1; + break; + case MyGUI::PixelFormat::L8A8: + glfmt = GL_LUMINANCE_ALPHA; + numelems = 2; + break; + case MyGUI::PixelFormat::R8G8B8: + glfmt = GL_RGB; + numelems = 3; + break; + case MyGUI::PixelFormat::R8G8B8A8: + glfmt = GL_RGBA; + numelems = 4; + break; + } + if(glfmt == GL_NONE) + throw std::runtime_error("Texture format not supported"); + + mTexture = new osg::Texture2D(); + mTexture->setTextureSize(width, height); + mTexture->setSourceFormat(glfmt); + mTexture->setSourceType(GL_UNSIGNED_BYTE); + + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + mFormat = format; + mUsage = usage; + mNumElemBytes = numelems; +} + +void OSGTexture::destroy() +{ + mTexture = nullptr; + mFormat = MyGUI::PixelFormat::Unknow; + mUsage = MyGUI::TextureUsage::Default; + mNumElemBytes = 0; +} + +void OSGTexture::loadFromFile(const std::string &fname) +{ + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + + // FIXME + mFormat = MyGUI::PixelFormat::R8G8B8; + mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; + mNumElemBytes = 3; // FIXME +} + +void OSGTexture::saveToFile(const std::string &fname) +{ + std::cerr << "Would save image to file " << fname << std::endl; +} + + +int OSGTexture::getWidth() +{ + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->s(); + return mTexture->getTextureWidth(); +} + +int OSGTexture::getHeight() +{ + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->t(); + return mTexture->getTextureHeight(); +} + + +void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) +{ + MYGUI_PLATFORM_ASSERT(mTexture.valid(), "Texture is not created"); + MYGUI_PLATFORM_ASSERT(!mLockedImage.valid(), "Texture already locked"); + + mLockedImage = mTexture->getImage(); + if(!mLockedImage.valid()) + { + mLockedImage = new osg::Image(); + mLockedImage->allocateImage( + mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), + mTexture->getSourceFormat(), mTexture->getSourceType() + ); + } + return mLockedImage->data(); +} + +void OSGTexture::unlock() +{ + MYGUI_PLATFORM_ASSERT(mLockedImage.valid(), "Texture not locked"); + + // Tell the texture it can get rid of the image for static textures (since + // they aren't expected to update much at all). + mTexture->setImage(mLockedImage.get()); + mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + mTexture->dirtyTextureObject(); + + mLockedImage = nullptr; +} + +bool OSGTexture::isLocked() +{ + return mLockedImage.valid(); +} + + +// FIXME: Render-to-texture not currently implemented. +MyGUI::IRenderTarget* OSGTexture::getRenderTarget() +{ + return nullptr; +} + +// --------------------------------------------------------------------------- + +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) + : mViewer(viewer) + , mSceneRoot(sceneroot) + , mTextureManager(textureManager) + , mUpdate(false) + , mIsInitialise(false) +{ +} + +RenderManager::~RenderManager() +{ + MYGUI_PLATFORM_LOG(Info, "* Shutdown: "<removeChild(mGuiRoot.get()); + mGuiRoot = nullptr; + mSceneRoot = nullptr; + mViewer = nullptr; + + destroyAllResources(); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName()<<" successfully shutdown"); + mIsInitialise = false; +} + + +void RenderManager::initialise() +{ + MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName()<<" initialised twice"); + MYGUI_PLATFORM_LOG(Info, "* Initialise: "< drawable = new Renderable(this); + drawable->setSupportsDisplayList(false); + drawable->setUseVertexBufferObjects(true); + drawable->setDataVariance(osg::Object::DYNAMIC); + + osg::ref_ptr geode = new osg::Geode; + geode->addDrawable(drawable.get()); + + osg::ref_ptr camera = new osg::Camera(); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setProjectionResizePolicy(osg::Camera::FIXED); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setRenderOrder(osg::Camera::POST_RENDER); + camera->setClearMask(GL_NONE); + osg::StateSet *state = new osg::StateSet; + state->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_GEN_R, osg::StateAttribute::OFF); + state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); + state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + state->setMode(GL_LIGHT0, osg::StateAttribute::OFF); + state->setMode(GL_BLEND, osg::StateAttribute::ON); + state->setMode(GL_FOG, osg::StateAttribute::OFF); + state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); + state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); + state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + state->setRenderBinDetails(11, "RenderBin"); + state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + geode->setStateSet(state); + geode->setCullingActive(false); + camera->addChild(geode.get()); + + mGuiRoot = camera; + mSceneRoot->addChild(mGuiRoot.get()); + mViewer->addEventHandler(new ResizeHandler(this)); + + osg::ref_ptr vp = mViewer->getCamera()->getViewport(); + setViewSize(vp->width(), vp->height()); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName()<<" successfully initialized"); + mIsInitialise = true; +} + +MyGUI::IVertexBuffer* RenderManager::createVertexBuffer() +{ + return new OSGVertexBuffer(); +} + +void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) +{ + delete buffer; +} + + +void RenderManager::begin() +{ + osg::State *state = mRenderInfo->getState(); + state->disableAllVertexArrays(); +} + +void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) +{ + osg::State *state = mRenderInfo->getState(); + osg::VertexBufferObject *vbo = static_cast(buffer)->getBuffer(); + MYGUI_PLATFORM_ASSERT(vbo, "Vertex buffer is not created"); + + if(texture) + { + osg::Texture2D *tex = static_cast(texture)->getTexture(); + MYGUI_PLATFORM_ASSERT(tex, "Texture is not created"); + state->applyTextureAttribute(0, tex); + } + + state->setVertexPointer(vbo->getArray(0)); + state->setColorPointer(vbo->getArray(1)); + state->setTexCoordPointer(0, vbo->getArray(2)); + + glDrawArrays(GL_TRIANGLES, 0, count); +} + +void RenderManager::end() +{ + osg::State *state = mRenderInfo->getState(); + state->disableTexCoordPointer(0); + state->disableColorPointer(); + state->disableVertexPointer(); + state->unbindVertexBufferObject(); +} + +void RenderManager::drawFrame(osg::RenderInfo &renderInfo) +{ + MyGUI::Gui *gui = MyGUI::Gui::getInstancePtr(); + if(gui == nullptr) return; + + mRenderInfo = &renderInfo; + + static MyGUI::Timer timer; + static unsigned long last_time = timer.getMilliseconds(); + unsigned long now_time = timer.getMilliseconds(); + unsigned long time = now_time - last_time; + + onFrameEvent((float)((double)(time) / (double)1000)); + + last_time = now_time; + + begin(); + onRenderToTarget(this, mUpdate); + end(); + + mUpdate = false; +} + +void RenderManager::setViewSize(int width, int height) +{ + if(width < 1) width = 1; + if(height < 1) height = 1; + + mGuiRoot->setViewport(0, 0, width, height); + mViewSize.set(width, height); + + mInfo.maximumDepth = 1; + mInfo.hOffset = 0; + mInfo.vOffset = 0; + mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); + mInfo.pixScaleX = 1.0f / float(mViewSize.width); + mInfo.pixScaleY = 1.0f / float(mViewSize.height); +std::cout << "setviewsize " << width << " " << height << std::endl; + onResizeView(mViewSize); + mUpdate = true; +} + + +bool RenderManager::isFormatSupported(MyGUI::PixelFormat /*format*/, MyGUI::TextureUsage /*usage*/) +{ + return true; +} + +MyGUI::ITexture* RenderManager::createTexture(const std::string &name) +{ + MapTexture::const_iterator item = mTextures.find(name); + MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '"<getName()); + MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '"<getName()<<"' not found"); + + mTextures.erase(item); + delete texture; +} + +MyGUI::ITexture* RenderManager::getTexture(const std::string &name) +{ + MapTexture::const_iterator item = mTextures.find(name); + if(item == mTextures.end()) + { + MyGUI::ITexture* tex = createTexture(name); + tex->loadFromFile(name); + return tex; + } + return item->second; +} + +void RenderManager::destroyAllResources() +{ + for (MapTexture::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + delete it->second; + mTextures.clear(); +} + +bool RenderManager::checkTexture(MyGUI::ITexture* _texture) +{ + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + if (item->second == _texture) + return true; + } + return false; +} + +} diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/apps/openmw/mwgui/myguirendermanager.hpp new file mode 100644 index 0000000000..64a5fe07b1 --- /dev/null +++ b/apps/openmw/mwgui/myguirendermanager.hpp @@ -0,0 +1,101 @@ +#ifndef OPENMW_MWGUI_MYGUIRENDERMANAGER_H +#define OPENMW_MWGUI_MYGUIRENDERMANAGER_H + +#include + +#include + +namespace Resource +{ + class TextureManager; +} + +namespace osgViewer +{ + class Viewer; +} + +namespace osg +{ + class Group; + class Camera; + class RenderInfo; +} + +namespace MWGui +{ + +class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget +{ + osg::ref_ptr mViewer; + osg::ref_ptr mSceneRoot; + Resource::TextureManager* mTextureManager; + + MyGUI::IntSize mViewSize; + bool mUpdate; + MyGUI::VertexColourType mVertexFormat; + MyGUI::RenderTargetInfo mInfo; + + typedef std::map MapTexture; + MapTexture mTextures; + + bool mIsInitialise; + + osg::ref_ptr mGuiRoot; + + // Only valid during drawFrame()! + osg::RenderInfo *mRenderInfo; + + void destroyAllResources(); + +public: + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager); + virtual ~RenderManager(); + + void initialise(); + + static RenderManager& getInstance() { return *getInstancePtr(); } + static RenderManager* getInstancePtr() + { return static_cast(MyGUI::RenderManager::getInstancePtr()); } + + /** @see RenderManager::getViewSize */ + virtual const MyGUI::IntSize& getViewSize() const { return mViewSize; } + + /** @see RenderManager::getVertexFormat */ + virtual MyGUI::VertexColourType getVertexFormat() { return mVertexFormat; } + + /** @see RenderManager::isFormatSupported */ + virtual bool isFormatSupported(MyGUI::PixelFormat format, MyGUI::TextureUsage usage); + + /** @see RenderManager::createVertexBuffer */ + virtual MyGUI::IVertexBuffer* createVertexBuffer(); + /** @see RenderManager::destroyVertexBuffer */ + virtual void destroyVertexBuffer(MyGUI::IVertexBuffer *buffer); + + /** @see RenderManager::createTexture */ + virtual MyGUI::ITexture* createTexture(const std::string &name); + /** @see RenderManager::destroyTexture */ + virtual void destroyTexture(MyGUI::ITexture* _texture); + /** @see RenderManager::getTexture */ + virtual MyGUI::ITexture* getTexture(const std::string &name); + + + /** @see IRenderTarget::begin */ + virtual void begin(); + /** @see IRenderTarget::end */ + virtual void end(); + /** @see IRenderTarget::doRender */ + virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** @see IRenderTarget::getInfo */ + virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } + + bool checkTexture(MyGUI::ITexture* _texture); + +/*internal:*/ + void drawFrame(osg::RenderInfo &renderInfo); + void setViewSize(int width, int height); +}; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4ae610f514..63d74b355a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,8 +19,6 @@ #include #include -#include - #include #include @@ -93,14 +91,16 @@ #include "controllers.hpp" #include "jailscreen.hpp" +#include "myguiplatform.hpp" + namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager + , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) - //, mGuiManager(NULL) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -173,11 +173,8 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - // Set up the GUI system - //mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); - - MyGUI::DummyPlatform* platform = new MyGUI::DummyPlatform; - platform->initialise(logpath); + Platform* platform = new Platform(viewer, guiRoot, textureManager); + platform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); @@ -248,7 +245,6 @@ namespace MWGui void WindowManager::initUI() { - /* // Get size info from the Gui object int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; @@ -304,8 +300,8 @@ namespace MWGui std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) - hitFaderTexture = "textures\\player_hit_01.dds"; + //if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) + // hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); mScreenFader = new ScreenFader("black.png"); @@ -331,8 +327,7 @@ namespace MWGui // Set up visibility updateVisible(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); - */ + //MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::renderWorldMap() @@ -416,8 +411,6 @@ namespace MWGui //delete mCursorManager; cleanupGarbage(); - - //delete mGuiManager; } void WindowManager::cleanupGarbage() @@ -928,7 +921,6 @@ namespace MWGui void WindowManager::changeCell(MWWorld::CellStore* cell) { - /* std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); mMap->setCellName( name ); @@ -953,12 +945,10 @@ namespace MWGui MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); } - */ } void WindowManager::setActiveMap(int x, int y, bool interior) { - /* if (!interior) { mMap->setCellPrefix("Cell"); @@ -967,22 +957,19 @@ namespace MWGui mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); - */ } void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) { - //mMap->setPlayerPos(cellX, cellY, x, y); - //mHud->setPlayerPos(cellX, cellY, x, y); + mMap->setPlayerPos(cellX, cellY, x, y); + mHud->setPlayerPos(cellX, cellY, x, y); } void WindowManager::setPlayerDir(const float x, const float y) { - /* mMap->setPlayerDir(x,y); mMap->setGlobalMapPlayerDir(x, y); mHud->setPlayerDir(x,y); - */ } void WindowManager::setDrowningBarVisibility(bool visible) @@ -1098,7 +1085,7 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { sizeVideo(x, y); - //mGuiManager->windowResized(); + if (!mHud) return; // UI not initialized yet @@ -1279,7 +1266,7 @@ namespace MWGui void WindowManager::executeInConsole (const std::string& path) { - //mConsole->executeFile (path); + mConsole->executeFile (path); } void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) @@ -1520,7 +1507,7 @@ namespace MWGui void WindowManager::updatePlayer() { - //mInventoryWindow->updatePlayer(); + mInventoryWindow->updatePlayer(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getNpcStats(player).isWerewolf()) @@ -1808,29 +1795,23 @@ namespace MWGui void WindowManager::fadeScreenIn(const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeOut(time); - */ } void WindowManager::fadeScreenOut(const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeIn(time); - */ } void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) { - /* if (clearQueue) mScreenFader->clearQueue(); mScreenFader->fadeTo(percent, time); - */ } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ddb9368c57..a98fbf7b8e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -52,6 +52,20 @@ namespace OEngine } } +namespace osg +{ + class Group; +} +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class TextureManager; +} + namespace SFO { class CursorManager; @@ -99,8 +113,8 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, const std::string& logpath, - const std::string& cacheDir, bool consoleOnlyScripts, + WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -364,7 +378,6 @@ namespace MWGui // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). CustomMarkerCollection mCustomMarkers; - OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index be23ebc2f1..32afc73c2d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -101,9 +101,9 @@ namespace MWRender mSunLight->setConstantAttenuation(1.f); lightRoot->addChild(source); - mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp deleted file mode 100644 index 3496478929..0000000000 --- a/libs/openengine/gui/manager.cpp +++ /dev/null @@ -1,680 +0,0 @@ -#include "manager.hpp" -#include "loglistener.hpp" - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -using namespace OEngine::GUI; - -namespace MyGUI -{ - -/* - * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex - * this override fixes the resulting performance issue. - */ -// Remove for MyGUI 3.2.2 -class FixedOgreDataManager : public MyGUI::OgreDataManager -{ -public: - bool isDataExist(const std::string& _name) - { - return Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup (_name); - } -}; - - -/* - * As of MyGUI 3.2.0, rendering with shaders is not supported. - * We definitely need this though to run in GL3 core / DX11 at all. - * To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/ - */ -class ShaderBasedRenderManager : public RenderManager, - public IRenderTarget, - public Ogre::WindowEventListener, - public Ogre::RenderQueueListener, - public Ogre::RenderSystem::Listener -{ - // флаг для обновления всех и вся - bool mUpdate; - - IntSize mViewSize; - - Ogre::SceneManager* mSceneManager; - - VertexColourType mVertexFormat; - - // окно, на которое мы подписываемся для изменения размеров - Ogre::RenderWindow* mWindow; - - // вьюпорт, с которым работает система - unsigned short mActiveViewport; - - Ogre::RenderSystem* mRenderSystem; - Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode; - Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode; - - RenderTargetInfo mInfo; - - typedef std::map MapTexture; - MapTexture mTextures; - - bool mIsInitialise; - bool mManualRender; - size_t mCountBatch; - - // ADDED - Ogre::GpuProgram* mVertexProgramNoTexture; - Ogre::GpuProgram* mVertexProgramOneTexture; - Ogre::GpuProgram* mFragmentProgramNoTexture; - Ogre::GpuProgram* mFragmentProgramOneTexture; - -public: - ShaderBasedRenderManager& getInstance() - { - return *getInstancePtr(); - } - ShaderBasedRenderManager* getInstancePtr() - { - return static_cast(RenderManager::getInstancePtr()); - } - - ShaderBasedRenderManager() : - mUpdate(false), - mSceneManager(nullptr), - mWindow(nullptr), - mActiveViewport(0), - mRenderSystem(nullptr), - mIsInitialise(false), - mManualRender(false), - mCountBatch(0), - mVertexProgramNoTexture(NULL), - mFragmentProgramNoTexture(NULL), - mVertexProgramOneTexture(NULL), - mFragmentProgramOneTexture(NULL) - { - mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; - } - - void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) - { - MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice"); - MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName()); - - mColorBlendMode.blendType = Ogre::LBT_COLOUR; - mColorBlendMode.source1 = Ogre::LBS_TEXTURE; - mColorBlendMode.source2 = Ogre::LBS_DIFFUSE; - mColorBlendMode.operation = Ogre::LBX_MODULATE; - - mAlphaBlendMode.blendType = Ogre::LBT_ALPHA; - mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE; - mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE; - mAlphaBlendMode.operation = Ogre::LBX_MODULATE; - - mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; - mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; - - mSceneManager = nullptr; - mWindow = nullptr; - mUpdate = false; - mRenderSystem = nullptr; - mActiveViewport = 0; - - Ogre::Root* root = Ogre::Root::getSingletonPtr(); - if (root != nullptr) - setRenderSystem(root->getRenderSystem()); - setRenderWindow(_window); - setSceneManager(_scene); - - - MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized"); - mIsInitialise = true; - } - - void shutdown() - { - MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised"); - MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName()); - - destroyAllResources(); - - setSceneManager(nullptr); - setRenderWindow(nullptr); - setRenderSystem(nullptr); - - MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown"); - mIsInitialise = false; - } - - void setRenderSystem(Ogre::RenderSystem* _render) - { - // отписываемся - if (mRenderSystem != nullptr) - { - mRenderSystem->removeListener(this); - mRenderSystem = nullptr; - } - - mRenderSystem = _render; - - // подписываемся на рендер евент - if (mRenderSystem != nullptr) - { - mRenderSystem->addListener(this); - - // формат цвета в вершинах - Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType(); - if (vertex_type == Ogre::VET_COLOUR_ARGB) - mVertexFormat = VertexColourType::ColourARGB; - else if (vertex_type == Ogre::VET_COLOUR_ABGR) - mVertexFormat = VertexColourType::ColourABGR; - - updateRenderInfo(); - } - } - - Ogre::RenderSystem* getRenderSystem() - { - return mRenderSystem; - } - - void setRenderWindow(Ogre::RenderWindow* _window) - { - // отписываемся - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); - mWindow = nullptr; - } - - mWindow = _window; - - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); - windowResized(mWindow); - } - } - - void setSceneManager(Ogre::SceneManager* _scene) - { - if (nullptr != mSceneManager) - { - mSceneManager->removeRenderQueueListener(this); - mSceneManager = nullptr; - } - - mSceneManager = _scene; - - if (nullptr != mSceneManager) - { - mSceneManager->addRenderQueueListener(this); - } - } - - void setActiveViewport(unsigned short _num) - { - mActiveViewport = _num; - - if (mWindow != nullptr) - { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); - - // рассылка обновлений - windowResized(mWindow); - } - } - - void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) - { - Gui* gui = Gui::getInstancePtr(); - if (gui == nullptr) - return; - - if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId) - return; - - Ogre::Viewport* viewport = mSceneManager->getCurrentViewport(); - if (nullptr == viewport - || !viewport->getOverlaysEnabled()) - return; - - if (mWindow->getNumViewports() <= mActiveViewport - || viewport != mWindow->getViewport(mActiveViewport)) - return; - - mCountBatch = 0; - - static Timer timer; - static unsigned long last_time = timer.getMilliseconds(); - unsigned long now_time = timer.getMilliseconds(); - unsigned long time = now_time - last_time; - - onFrameEvent((float)((double)(time) / (double)1000)); - - last_time = now_time; - - //begin(); - setManualRender(true); - onRenderToTarget(this, mUpdate); - //end(); - - // сбрасываем флаг - mUpdate = false; - } - - void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) - { - } - - void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters) - { - if (eventName == "DeviceLost") - { - } - else if (eventName == "DeviceRestored") - { - // обновить всех - mUpdate = true; - } - } - - IVertexBuffer* createVertexBuffer() - { - return new OgreVertexBuffer(); - } - - void destroyVertexBuffer(IVertexBuffer* _buffer) - { - delete _buffer; - } - - // для оповещений об изменении окна рендера - void windowResized(Ogre::RenderWindow* _window) - { - if (_window->getNumViewports() > mActiveViewport) - { - Ogre::Viewport* port = _window->getViewport(mActiveViewport); -#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 - Ogre::OrientationMode orient = port->getOrientationMode(); - if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270) - mViewSize.set(port->getActualHeight(), port->getActualWidth()); - else - mViewSize.set(port->getActualWidth(), port->getActualHeight()); -#else - mViewSize.set(port->getActualWidth(), port->getActualHeight()); -#endif - - // обновить всех - mUpdate = true; - - updateRenderInfo(); - - onResizeView(mViewSize); - } - } - - void updateRenderInfo() - { - if (mRenderSystem != nullptr) - { - mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue(); - mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width); - mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height); - mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); - mInfo.pixScaleX = 1.0f / float(mViewSize.width); - mInfo.pixScaleY = 1.0f / float(mViewSize.height); - } - } - - void initShaders() - { - // ADDED - sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); - mVertexProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getVertexProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); - mVertexProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getVertexProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); - mFragmentProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getFragmentProgram()->_getBindingDelegate(); - - mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); - sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); - mFragmentProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) - ->getFragmentProgram()->_getBindingDelegate(); - } - - void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count) - { - if (getManualRender()) - { - begin(); - setManualRender(false); - } - - // ADDED - if (!mVertexProgramNoTexture) - initShaders(); - - if (_texture) - { - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture); - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture); - } - else - { - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture); - Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture); - } - - if (_texture) - { - OgreTexture* texture = static_cast(_texture); - Ogre::TexturePtr texture_ptr = texture->getOgreTexture(); - if (!texture_ptr.isNull()) - { - mRenderSystem->_setTexture(0, true, texture_ptr); - mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); - } - } - - OgreVertexBuffer* buffer = static_cast(_buffer); - Ogre::RenderOperation* operation = buffer->getRenderOperation(); - operation->vertexData->vertexCount = _count; - - mRenderSystem->_render(*operation); - - ++ mCountBatch; - } - - void begin() - { - // set-up matrices - mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); - mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); - -#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 - Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode(); - mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z)); -#else - mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); -#endif - - // initialise render settings - mRenderSystem->setLightingEnabled(false); - mRenderSystem->_setDepthBufferParams(false, false); - mRenderSystem->_setDepthBias(0, 0); - mRenderSystem->_setCullingMode(Ogre::CULL_NONE); - mRenderSystem->_setFog(Ogre::FOG_NONE); - mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); - mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM); - mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM); - mRenderSystem->setShadingType(Ogre::SO_GOURAUD); - - // initialise texture settings - mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE); - mRenderSystem->_setTextureCoordSet(0, 0); - mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); - mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode); - mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY); -#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0) - mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0); -#else - mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false); -#endif - mRenderSystem->_setTextureBlendMode(0, mColorBlendMode); - mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode); - mRenderSystem->_disableTextureUnitsFrom(1); - - // enable alpha blending - mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); - - // always use wireframe - mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); - } - - void end() - { - } - - ITexture* createTexture(const std::string& _name) - { - MapTexture::const_iterator item = mTextures.find(_name); - MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist"); - - OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup()); - mTextures[_name] = texture; - return texture; - } - - void destroyTexture(ITexture* _texture) - { - if (_texture == nullptr) return; - - MapTexture::iterator item = mTextures.find(_texture->getName()); - MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found"); - - mTextures.erase(item); - delete _texture; - } - - ITexture* getTexture(const std::string& _name) - { - MapTexture::const_iterator item = mTextures.find(_name); - if (item == mTextures.end()) - { - Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name); - if (!texture.isNull()) - { - ITexture* result = createTexture(_name); - static_cast(result)->setOgreTexture(texture); - return result; - } - return nullptr; - } - return item->second; - } - - bool isFormatSupported(PixelFormat _format, TextureUsage _usage) - { - return Ogre::TextureManager::getSingleton().isFormatSupported( - Ogre::TEX_TYPE_2D, - OgreTexture::convertFormat(_format), - OgreTexture::convertUsage(_usage)); - } - - void destroyAllResources() - { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - delete item->second; - } - mTextures.clear(); - } - -#if MYGUI_DEBUG_MODE == 1 - bool checkTexture(ITexture* _texture) - { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - if (item->second == _texture) - return true; - } - return false; - } -#endif - - const IntSize& getViewSize() const - { - return mViewSize; - } - - VertexColourType getVertexFormat() - { - return mVertexFormat; - } - - const RenderTargetInfo& getInfo() - { - return mInfo; - } - - size_t getActiveViewport() - { - return mActiveViewport; - } - - Ogre::RenderWindow* getRenderWindow() - { - return mWindow; - } - - bool getManualRender() - { - return mManualRender; - } - - void setManualRender(bool _value) - { - mManualRender = _value; - } - - size_t getBatchCount() const - { - return mCountBatch; - } -}; - -/// \brief Helper class holding data that required during -/// MyGUI log creation -class LogFacility -{ - ConsoleLogListener mConsole; - CustomLogListener mFile; - LevelLogFilter mFilter; - LogSource mSource; - -public: - - LogFacility(const std::string &output, bool console) - : mFile(output) - { - mConsole.setEnabled(console); - mFilter.setLoggingLevel(LogLevel::Info); - - mSource.addLogListener(&mFile); - mSource.addLogListener(&mConsole); - mSource.setLogFilter(&mFilter); - - mSource.open(); - } - - LogSource *getSource() { return &mSource; } -}; - -} - -void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) -{ - assert(wnd); - assert(mgr); - - mSceneMgr = mgr; - mShaderRenderManager = NULL; - mRenderManager = NULL; - - using namespace MyGUI; - - // Enable/disable MyGUI logging to stdout. (Logging to MyGUI.log is - // still enabled.) In order to do this we have to initialize the log - // manager before the main gui system itself, otherwise the main - // object will get the chance to spit out a few messages before we - // can able to disable it. - - std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); - if(!logDir.empty()) - theLogFile.insert(0, logDir); - - // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. - mLogManager = new LogManager(); - if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) - mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); - else - mRenderManager = new MyGUI::OgreRenderManager(); - mDataManager = new MyGUI::FixedOgreDataManager(); - - // Do not use default log since it don't support Unicode path on Windows. - // Instead, manually create log source using LogFacility and pass it. - mLogFacility = new MyGUI::LogFacility(theLogFile, logging); - LogManager::getInstance().addLogSource(mLogFacility->getSource()); - - if (mShaderRenderManager) - mShaderRenderManager->initialise(wnd, mgr); - else - mRenderManager->initialise(wnd, mgr); - mDataManager->initialise("General"); - - // Create GUI - mGui = new Gui(); - mGui->initialise(""); -} - -void MyGUIManager::windowResized() -{ -#ifndef ANDROID - mRenderManager->setActiveViewport(0); -#endif -} - -void MyGUIManager::shutdown() -{ - mGui->shutdown (); - delete mGui; - if(mRenderManager) - { - mRenderManager->shutdown(); - delete mRenderManager; - mRenderManager = NULL; - } - if(mShaderRenderManager) - { - mShaderRenderManager->shutdown(); - delete mShaderRenderManager; - mShaderRenderManager = NULL; - } - if(mDataManager) - { - mDataManager->shutdown(); - delete mDataManager; - mDataManager = NULL; - } - if (mLogManager) - { - delete mLogManager; - mLogManager = NULL; - } - delete mLogFacility; - - mGui = NULL; -} diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp deleted file mode 100644 index 28eb6419b1..0000000000 --- a/libs/openengine/gui/manager.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef OENGINE_MYGUI_MANAGER_H -#define OENGINE_MYGUI_MANAGER_H - -#include - -namespace MyGUI -{ - class Gui; - class LogManager; - class OgreDataManager; - class OgreRenderManager; - class ShaderBasedRenderManager; - class LogFacility; -} - -namespace Ogre -{ - class RenderWindow; - class SceneManager; -} - -namespace OEngine { -namespace GUI -{ - class MyGUIManager - { - MyGUI::Gui *mGui; - MyGUI::LogManager* mLogManager; - MyGUI::LogFacility* mLogFacility; - MyGUI::OgreDataManager* mDataManager; - MyGUI::OgreRenderManager* mRenderManager; - MyGUI::ShaderBasedRenderManager* mShaderRenderManager; - Ogre::SceneManager* mSceneMgr; - - - public: - MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) - { - setup(wnd,mgr,logging, logDir); - } - ~MyGUIManager() - { - shutdown(); - } - - void windowResized(); - - void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); - void shutdown(); - }; -} -} -#endif From 15164e20f7c9c7eb5a65a30903390f269251539a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Apr 2015 23:30:30 +0200 Subject: [PATCH 0166/1812] Cleanup fix --- apps/openmw/engine.cpp | 21 +++++++++++---------- apps/openmw/engine.hpp | 2 +- apps/openmw/mwgui/myguirendermanager.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++++ 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7698c31461..7dac03c342 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -314,9 +314,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); // not handling fullscreen yet, we should figure this out when adding SDL to the mix - mViewer.setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); + mViewer->setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); osg::ref_ptr rootNode (new osg::Group); - mViewer.setSceneData(rootNode); + mViewer->setSceneData(rootNode); mVFS.reset(new VFS::Manager(mFSStrict)); @@ -355,7 +355,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; rootNode->addChild(guiRoot); - MWGui::WindowManager* window = new MWGui::WindowManager(&mViewer, guiRoot, mResourceSystem->getTextureManager(), + MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -371,7 +371,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), + mEnvironment.setWorld( new MWWorld::World (*mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); @@ -433,7 +433,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { assert (!mContentFiles.empty()); - //assert (!mOgre); + + mViewer = new osgViewer::Viewer; Settings::Manager settings; std::string settingspath; @@ -474,12 +475,12 @@ void OMW::Engine::go() } // Start the main rendering loop - mViewer.setCameraManipulator(new osgGA::TrackballManipulator); - mViewer.addEventHandler(new osgViewer::StatsHandler); + mViewer->setCameraManipulator(new osgGA::TrackballManipulator); + mViewer->addEventHandler(new osgViewer::StatsHandler); - mViewer.realize(); + mViewer->realize(); osg::Timer frameTimer; - while (!mViewer.done()) + while (!mViewer->done()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); @@ -491,7 +492,7 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->advanceTime( dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - mViewer.frame(/*simulationTime*/); + mViewer->frame(/*simulationTime*/); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8c73920bda..be405c6007 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -69,7 +69,7 @@ namespace OMW Files::PathContainer mDataDirs; std::vector mArchives; boost::filesystem::path mResDir; - osgViewer::Viewer mViewer; + osg::ref_ptr mViewer; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 53a194c733..55e78cb0c3 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -561,7 +561,7 @@ void RenderManager::setViewSize(int width, int height) mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); mInfo.pixScaleX = 1.0f / float(mViewSize.width); mInfo.pixScaleY = 1.0f / float(mViewSize.height); -std::cout << "setviewsize " << width << " " << height << std::endl; + onResizeView(mViewSize); mUpdate = true; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 63d74b355a..86d065e39c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -173,8 +173,8 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - Platform* platform = new Platform(viewer, guiRoot, textureManager); - platform->initialise(resourcePath, logpath); + mGuiPlatform = new Platform(viewer, guiRoot, textureManager); + mGuiPlatform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); @@ -411,6 +411,8 @@ namespace MWGui //delete mCursorManager; cleanupGarbage(); + + delete mGuiPlatform; } void WindowManager::cleanupGarbage() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a98fbf7b8e..54b69be407 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -107,6 +107,8 @@ namespace MWGui class DebugWindow; class JailScreen; + class Platform; + class WindowManager : public MWBase::WindowManager { public: @@ -365,6 +367,8 @@ namespace MWGui virtual void cycleWeapon(bool next); private: + Platform* mGuiPlatform; + bool mConsoleOnlyScripts; std::map mTrackedWindows; From a3417a9c49d4aa4b5be70719002870052ff2768d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 01:20:07 +0200 Subject: [PATCH 0167/1812] CharacterController compiles --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 4 ++- apps/openmw/mwmechanics/character.cpp | 44 +++++++++++++++------------ apps/openmw/mwrender/animation.cpp | 6 ++++ apps/openmw/mwrender/animation.hpp | 17 +++++++++++ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3349a1afe8..acca23f8eb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning -# character actors objects + character actors objects ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c6df241546..bab022d94f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -252,7 +252,7 @@ namespace MWMechanics .search("VFX_Soul_Trap"); if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(mCreature.getRefData().getPosition().pos)); + "", mCreature.getRefData().getPosition().asVec3()); MWBase::Environment::get().getSoundManager()->playSound3D(mCreature, "conjuration hit", 1.f, 1.f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); @@ -274,6 +274,7 @@ namespace MWMechanics void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance) { + /* static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get() .find("fMaxHeadTrackDistance")->getFloat(); static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get() @@ -306,6 +307,7 @@ namespace MWMechanics sqrHeadTrackDistance = sqrDist; headTrackTarget = targetActor; } + */ } void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ffde59aee6..c989e3f456 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,7 +27,7 @@ #include "creaturestats.hpp" #include "security.hpp" -#include +#include #include @@ -222,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] + int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -654,7 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim { /* Accumulate along X/Y only for now, until we can figure out how we should * handle knockout and death which moves the character down. */ - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + mAnimation->setAccumulation(osg::Vec3f(1.0f, 1.0f, 0.0f)); if (cls.hasInventoryStore(mPtr)) { @@ -685,7 +685,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim else { /* Don't accumulate with non-actors. */ - mAnimation->setAccumulation(Ogre::Vector3(0.0f)); + mAnimation->setAccumulation(osg::Vec3f(0.f, 0.f, 0.f)); mIdleState = CharState_Idle; } @@ -710,12 +710,14 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::updateIdleStormState() { bool inStormDirection = false; + /* if (MWBase::Environment::get().getWorld()->isInStorm()) { Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); inStormDirection = stormDirection.angleBetween(characterDirection) > Ogre::Degree(120); } + */ if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; @@ -831,7 +833,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] + int roll = Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1030,12 +1032,12 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->getNode("Left Hand")) + if (mAnimation->hasNode("Left Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->getNode("Right Hand")) + if (mAnimation->hasNode("Right Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); @@ -1127,7 +1129,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); + attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) @@ -1690,26 +1692,26 @@ void CharacterController::update(float duration) world->queueMovement(mPtr, Ogre::Vector3(0.0f)); } - Ogre::Vector3 moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); + osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); if(duration > 0.0f) moved /= duration; else - moved = Ogre::Vector3(0.0f); + moved = osg::Vec3f(0.f, 0.f, 0.f); // Ensure we're moving in generally the right direction... if(mMovementSpeed > 0.f) { float l = moved.length(); - if((movement.x < 0.0f && movement.x < moved.x*2.0f) || - (movement.x > 0.0f && movement.x > moved.x*2.0f)) - moved.x = movement.x; - if((movement.y < 0.0f && movement.y < moved.y*2.0f) || - (movement.y > 0.0f && movement.y > moved.y*2.0f)) - moved.y = movement.y; - if((movement.z < 0.0f && movement.z < moved.z*2.0f) || - (movement.z > 0.0f && movement.z > moved.z*2.0f)) - moved.z = movement.z; + if((movement.x < 0.0f && movement.x < moved.x()*2.0f) || + (movement.x > 0.0f && movement.x > moved.x()*2.0f)) + moved.x() = movement.x; + if((movement.y < 0.0f && movement.y < moved.y()*2.0f) || + (movement.y > 0.0f && movement.y > moved.y()*2.0f)) + moved.y() = movement.y; + if((movement.z < 0.0f && movement.z < moved.z()*2.0f) || + (movement.z > 0.0f && movement.z > moved.z()*2.0f)) + moved.z() = movement.z; // but keep the original speed float newLength = moved.length(); if (newLength > 0) @@ -1721,7 +1723,7 @@ void CharacterController::update(float duration) // Update movement if(mMovementAnimationControlled && mPtr.getClass().isActor()) - world->queueMovement(mPtr, moved); + world->queueMovement(mPtr, Ogre::Vector3(moved.x(), moved.y(), moved.z())); mSkipAnim = false; @@ -1904,6 +1906,7 @@ void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) void CharacterController::updateHeadTracking(float duration) { + /* Ogre::Node* head = mAnimation->getNode("Bip01 Head"); if (!head) return; @@ -1946,6 +1949,7 @@ void CharacterController::updateHeadTracking(float duration) mAnimation->setHeadPitch(xAngle); mAnimation->setHeadYaw(zAngle); + */ } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 27e54b2284..4a1ec3f2f3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1050,6 +1050,12 @@ namespace MWRender } } + bool Animation::hasNode(const std::string &name) + { + std::string lowerName = Misc::StringUtils::lowerCase(name); + return (mNodeMap.find(lowerName) != mNodeMap.end()); + } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { // FIXME: hold a pointer instead of searching every frame diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d5b2de81b5..9aa15520ff 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -338,6 +338,23 @@ public: /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); + /// Is there a node with the specified name? + /// @note The matching is case-insensitive. + bool hasNode(const std::string& name); + + virtual void showWeapons(bool showWeapon) {} + virtual void showCarriedLeft(bool show) {} + virtual void setWeaponGroup(const std::string& group) {} + virtual void setVampire(bool vampire) {} + virtual void setAlpha(float alpha) {} + virtual void setPitchFactor(float factor) {} + virtual void attachArrow() {} + virtual void enableHeadAnimation(bool enable) {} + // TODO: move outside of this class + /// Makes this object glow, by placing a Light in its center. + /// @param effect Controls the radius and intensity of the light. + virtual void setLightEffect(float effect) {} + private: Animation(const Animation&); void operator=(Animation&); From 372a54bbc70f3e20e1044059f3f743c0114fc149 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 01:28:01 +0200 Subject: [PATCH 0168/1812] Dead code removal --- apps/openmw/engine.hpp | 1 - components/CMakeLists.txt | 4 --- components/nif/niffile.hpp | 1 + components/nifcache/nifcache.cpp | 40 ------------------------- components/nifcache/nifcache.hpp | 50 -------------------------------- components/nifosg/controller.hpp | 2 -- components/nifosg/nifloader.hpp | 2 -- 7 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 components/nifcache/nifcache.cpp delete mode 100644 components/nifcache/nifcache.hpp diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index be405c6007..f3b3a8fbf6 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -7,7 +7,6 @@ #include #include #include -#include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ece1148cb2..cc913912f1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,10 +50,6 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifcache -# nifcache -# ) - #add_component_dir (nifbullet # bulletnifloader # ) diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ae5aca5acc..6fbef31ca6 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -94,6 +94,7 @@ public: /// Get the name of the file std::string getFilename(){ return filename; } }; +typedef boost::shared_ptr NIFFilePtr; diff --git a/components/nifcache/nifcache.cpp b/components/nifcache/nifcache.cpp deleted file mode 100644 index 342251dbc8..0000000000 --- a/components/nifcache/nifcache.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "nifcache.hpp" - -namespace Nif -{ - -Cache* Cache::sThis = 0; - -Cache& Cache::getInstance() -{ - assert (sThis); - return *sThis; -} - -Cache* Cache::getInstancePtr() -{ - return sThis; -} - -Cache::Cache() -{ - assert (!sThis); - sThis = this; -} - -NIFFilePtr Cache::load(const std::string &filename) -{ - // TODO: normalize file path to make sure we're not loading the same file twice - - LoadedMap::iterator it = mLoadedMap.find(filename); - if (it != mLoadedMap.end()) - return it->second; - else - { - NIFFilePtr file(new Nif::NIFFile(filename)); - mLoadedMap[filename] = file; - return file; - } -} - -} diff --git a/components/nifcache/nifcache.hpp b/components/nifcache/nifcache.hpp deleted file mode 100644 index 173b918653..0000000000 --- a/components/nifcache/nifcache.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OPENMW_COMPONENTS_NIFCACHE_H -#define OPENMW_COMPONENTS_NIFCACHE_H - -#include - -#include - -#include - -namespace Nif -{ - - typedef boost::shared_ptr NIFFilePtr; - - /// @brief A basic resource manager for NIF files - class Cache - { - public: - Cache(); - - /// Queue this file for background loading. A worker thread will start loading the file. - /// To get the loaded NIFFilePtr, use the load method, which will wait until the worker thread is finished - /// and then return the loaded file. - //void loadInBackground (const std::string& file); - - /// Read and parse the given file. May retrieve from cache if this file has been used previously. - /// @note If the file is currently loading in the background, this function will block until - /// the background loading finishes, then return the background loaded file. - /// @note Returns a SharedPtr to the file and the file will stay loaded as long as the user holds on to this pointer. - /// When all external SharedPtrs to a file are released, the cache may decide to unload the file. - NIFFilePtr load (const std::string& filename); - - /// Return instance of this class. - static Cache& getInstance(); - static Cache* getInstancePtr(); - - private: - static Cache* sThis; - - Cache(const Cache&); - Cache& operator =(const Cache&); - - typedef std::map LoadedMap; - - LoadedMap mLoadedMap; - }; - -} - -#endif diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d32c9f977a..4ebd4f41d2 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index f2f3c25349..bf1dbe6b58 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -3,8 +3,6 @@ #include -#include // NIFFilePtr - #include #include From 2db097f80e3b494856055f8c2e8cf72d692f5176 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:10:37 +0200 Subject: [PATCH 0169/1812] Fix nested callbacks bug --- apps/openmw/mwrender/animation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4a1ec3f2f3..c5479e3f79 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -549,9 +549,16 @@ namespace MWRender { osg::Node* node = it->first; node->removeUpdateCallback(it->second); + + // Should be no longer needed with OSG 3.4 + it->second->setNestedCallback(NULL); } if (mResetAccumRootCallback && mAccumRoot) + { mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); + // Should be no longer needed with OSG 3.4 + mResetAccumRootCallback->setNestedCallback(NULL); + } mAnimSourceControllers.clear(); mAccumCtrl = NULL; @@ -589,6 +596,7 @@ namespace MWRender { mAccumCtrl = it->second; + // make sure reset is last in the chain of callbacks if (!mResetAccumRootCallback) { mResetAccumRootCallback = new ResetAccumRootCallback; From 0ff7b2ff11313987019759e583d28a7f1481f109 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:19:17 +0200 Subject: [PATCH 0170/1812] MechanicsManager, frame update --- apps/openmw/engine.cpp | 24 +------ apps/openmw/engine.hpp | 7 +- apps/openmw/main.cpp | 2 + apps/openmw/mwmechanics/actor.cpp | 8 +-- apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/character.cpp | 1 - .../mwmechanics/mechanicsmanagerimp.cpp | 70 ++++++++----------- .../mwmechanics/mechanicsmanagerimp.hpp | 8 +-- apps/openmw/mwrender/objects.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 5 ++ apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwworld/physicssystem.cpp | 14 ++-- apps/openmw/mwworld/scene.cpp | 32 ++++----- apps/openmw/mwworld/scene.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 31 ++++---- 15 files changed, 95 insertions(+), 117 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dac03c342..582172bffd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -69,23 +69,10 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) -{ - if (MWBase::Environment::get().getStateManager()->getState()!= - MWBase::StateManager::State_NoGame) - { - bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode(); - MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused); - MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame); - } - return true; -} - -bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) +void OMW::Engine::frame(float frametime) { try { - float frametime = evt.timeSinceLastFrame; mEnvironment.setFrameDuration (frametime); // update input @@ -173,8 +160,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } - - return true; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -486,12 +471,7 @@ void OMW::Engine::go() frameTimer.setStartTick(); //dt = std::min(dt, 0.2f); - // frameRenderingQueued(dt); - MWBase::Environment::get().getWorld()->update(dt, false); - - MWBase::Environment::get().getWorld()->advanceTime( - dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - + frame(dt); mViewer->frame(/*simulationTime*/); } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index f3b3a8fbf6..b47a7bb766 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -1,8 +1,6 @@ #ifndef ENGINE_H #define ENGINE_H -#include - #include #include #include @@ -58,7 +56,7 @@ namespace Files namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW - class Engine : private Ogre::FrameListener + class Engine { std::auto_ptr mVFS; std::auto_ptr mResourceSystem; @@ -104,8 +102,7 @@ namespace OMW void executeLocalScripts(); - virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); - virtual bool frameStarted (const Ogre::FrameEvent& evt); + void frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 070136dfd7..792a2674e5 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -12,6 +12,8 @@ #include #include +#include + #if defined(_WIN32) // For OutputDebugString #define WIN32_LEAN_AND_MEAN diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index 3161bb4130..675bd160a3 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -1,23 +1,23 @@ #include "actor.hpp" -//#include "character.hpp" +#include "character.hpp" namespace MWMechanics { Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) { - //mCharacterController.reset(new CharacterController(ptr, animation)); + mCharacterController.reset(new CharacterController(ptr, animation)); } void Actor::updatePtr(const MWWorld::Ptr &newPtr) { - //mCharacterController->updatePtr(newPtr); + mCharacterController->updatePtr(newPtr); } CharacterController* Actor::getCharacterController() { - return 0;//mCharacterController.get(); + return mCharacterController.get(); } AiState& Actor::getAiState() diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bab022d94f..bb59d46c09 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1014,6 +1014,8 @@ namespace MWMechanics removeActor(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if (!anim) + return; mActors.insert(std::make_pair(ptr, new Actor(ptr, anim))); if (updateImmediately) mActors[ptr]->getCharacterController()->update(0); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c989e3f456..98a420ba67 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,7 +20,6 @@ #include "character.hpp" #include -#include #include "movement.hpp" #include "npcstats.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0e3220cf89..7e6e296707 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -294,27 +294,22 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { - /* if(ptr.getClass().isActor()) mActors.addActor(ptr); else mObjects.addObject(ptr); - */ } void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - /* if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); mObjects.removeObject(ptr); - */ } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - /* if(old == mWatched) mWatched = ptr; @@ -322,16 +317,13 @@ namespace MWMechanics mActors.updateActor(old, ptr); else mObjects.updateObject(old, ptr); - */ } void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { - /* mActors.dropActors(cellStore, mWatched); mObjects.dropObjects(cellStore); - */ } @@ -472,24 +464,24 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - //mActors.removeActor(ptr); - //mActors.addActor(ptr, true); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + mActors.removeActor(ptr); + mActors.addActor(ptr, true); } - //mActors.update(duration, paused); - //mObjects.update(duration, paused); + mActors.update(duration, paused); + mObjects.update(duration, paused); } void MechanicsManager::rest(bool sleep) { - //mActors.restoreDynamicStats (sleep); - //mActors.fastForwardAi(); + mActors.restoreDynamicStats (sleep); + mActors.fastForwardAi(); } int MechanicsManager::getHoursToRest() const { - return 0;//mActors.getHoursToRest(mWatched); + return mActors.getHoursToRest(mWatched); } void MechanicsManager::setPlayerName (const std::string& name) @@ -679,7 +671,7 @@ namespace MWMechanics int MechanicsManager::countDeaths (const std::string& id) const { - return 0;//mActors.countDeaths (id); + return mActors.countDeaths (id); } void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, @@ -835,39 +827,35 @@ namespace MWMechanics void MechanicsManager::forceStateUpdate(const MWWorld::Ptr &ptr) { - //if(ptr.getClass().isActor()) - //mActors.forceStateUpdate(ptr); + if(ptr.getClass().isActor()) + mActors.forceStateUpdate(ptr); } void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - /* if(ptr.getClass().isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else mObjects.playAnimationGroup(ptr, groupName, mode, number); - */ } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - /* if(ptr.getClass().isActor()) mActors.skipAnimation(ptr); else mObjects.skipAnimation(ptr); - */ } bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) { - //if(ptr.getClass().isActor()) - // return mActors.checkAnimationPlaying(ptr, groupName); - //else + if(ptr.getClass().isActor()) + return mActors.checkAnimationPlaying(ptr, groupName); + else return false; } void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) { - //mActors.updateMagicEffects(ptr); + mActors.updateMagicEffects(ptr); } bool MechanicsManager::toggleAI() @@ -1062,7 +1050,7 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - //mActors.getObjectsInRange(from, radius, neighbors); + mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1151,7 +1139,7 @@ namespace MWMechanics Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); - //mActors.getObjectsInRange(from, radius, neighbors); + mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) @@ -1406,7 +1394,6 @@ namespace MWMechanics // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { - /* for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) @@ -1419,7 +1406,6 @@ namespace MWMechanics } } } - */ } } @@ -1430,27 +1416,27 @@ namespace MWMechanics void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - //mActors.getObjectsInRange(position, radius, objects); - //mObjects.getObjectsInRange(position, radius, objects); + mActors.getObjectsInRange(position, radius, objects); + mObjects.getObjectsInRange(position, radius, objects); } void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) { - //mActors.getObjectsInRange(position, radius, objects); + mActors.getObjectsInRange(position, radius, objects); } std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) { - return std::list();//mActors.getActorsFollowing(actor); + return mActors.getActorsFollowing(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { - return std::list(); //mActors.getActorsFollowingIndices(actor); + return mActors.getActorsFollowingIndices(actor); } std::list MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) { - return std::list();// mActors.getActorsFighting(actor); + return mActors.getActorsFighting(actor); } int MechanicsManager::countSavedGameRecords() const @@ -1461,7 +1447,7 @@ namespace MWMechanics void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { - //mActors.write(writer, listener); + mActors.write(writer, listener); ESM::StolenItems items; items.mStolenItems = mStolenItems; @@ -1478,13 +1464,13 @@ namespace MWMechanics items.load(reader); mStolenItems = items.mStolenItems; } - //else - //mActors.readRecord(reader, type); + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { - //mActors.clear(); + mActors.clear(); mStolenItems.clear(); } @@ -1530,6 +1516,6 @@ namespace MWMechanics bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const { - return 0;//mActors.isReadyToBlock(ptr); + return mActors.isReadyToBlock(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 30cc207f74..d08334ae8c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,8 +7,8 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -//#include "objects.hpp" -//#include "actors.hpp" +#include "objects.hpp" +#include "actors.hpp" namespace Ogre { @@ -32,8 +32,8 @@ namespace MWMechanics bool mRaceSelected; bool mAI;///< is AI active? - //Objects mObjects; - //Actors mActors; + Objects mObjects; + Actors mActors; typedef std::pair Owner; // < Owner id, bool isFaction > typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index be21b2bec0..f77865634b 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -197,9 +197,7 @@ void Objects::removeCell(const MWWorld::CellStore* store) void Objects::update(float dt) { - PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();++it) - it->second->runAnimation(dt); + } void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 32afc73c2d..d68620f8ad 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -248,4 +248,9 @@ namespace MWRender notifyWorldSpaceChanged(); } + MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) + { + return mObjects->getAnimation(ptr); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c47317608e..005100701e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -78,6 +78,8 @@ namespace MWRender void update(float dt, bool paused); + MWRender::Animation* getAnimation(const MWWorld::Ptr& ptr); + private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 623a795762..a1b37a2757 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -503,15 +503,15 @@ namespace MWWorld { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + //mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() { - if (mWaterCollisionObject.get()) - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - delete mEngine; - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); + //if (mWaterCollisionObject.get()) + // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + //delete mEngine; + //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() @@ -674,19 +674,23 @@ namespace MWWorld void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { + /* Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); mEngine->createAndAdjustRigidBody( mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); + */ } void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { + /* Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); + */ } void PhysicsSystem::removeObject (const std::string& handle) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 191a8ffeff..e61e5d84e8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -31,7 +31,7 @@ namespace { - void addObject(const MWWorld::Ptr& ptr, //MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); @@ -39,10 +39,10 @@ namespace if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); - //ptr.getClass().insertObject (ptr, model, physics); + ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -65,7 +65,7 @@ namespace } } - void updateObjectScale(const MWWorld::Ptr& ptr, /*MWWorld::PhysicsSystem& physics,*/ + void updateObjectScale(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -82,20 +82,20 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - //MWWorld::PhysicsSystem& mPhysics; + MWWorld::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - /*MWWorld::PhysicsSystem& physics, */MWRender::RenderingManager& rendering); + MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, /*MWWorld::PhysicsSystem& physics,*/ + Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), - //mPhysics (physics), + mPhysics (physics), mRendering (rendering) {} @@ -113,9 +113,9 @@ namespace { try { - addObject(ptr, /*mPhysics, */mRendering); - updateObjectLocalRotation(ptr, /*mPhysics,*/ mRendering); - updateObjectScale(ptr, /*mPhysics,*/ mRendering); + addObject(ptr, mPhysics, mRendering); + updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) @@ -137,12 +137,12 @@ namespace MWWorld void Scene::updateObjectLocalRotation (const Ptr& ptr) { - ::updateObjectLocalRotation(ptr, /* *mPhysics,*/ mRendering); + ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); } void Scene::updateObjectScale(const Ptr &ptr) { - ::updateObjectScale(ptr, /* *mPhysics,*/ mRendering); + ::updateObjectScale(ptr, *mPhysics, mRendering); } void Scene::getGridCenter(int &cellX, int &cellY) @@ -447,7 +447,7 @@ namespace MWWorld //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), /*mPhysics(physics),*/ mRendering(rendering), mNeedMapUpdate(false) + : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { } @@ -557,7 +557,7 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, /* *mPhysics, */mRendering); + InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); cell.forEach (functor); } @@ -565,7 +565,7 @@ namespace MWWorld { try { - addObject(ptr, /* *mPhysics, */mRendering); + addObject(ptr, *mPhysics, mRendering); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ea1a56d636..26590c796d 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -63,7 +63,7 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - //PhysicsSystem *mPhysics; + PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b1946d1c5..77028aaffa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,6 +54,7 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" +#include "physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -160,7 +161,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - //mPhysics = new PhysicsSystem(renderer); + mPhysics = new PhysicsSystem(); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -199,7 +200,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWorldScene = new Scene(*mRendering, NULL/*mPhysics*/); + mWorldScene = new Scene(*mRendering, mPhysics); } void World::startNewGame (bool bypass) @@ -480,7 +481,7 @@ namespace MWWorld delete mWeatherManager; delete mWorldScene; delete mRendering; - //delete mPhysics; + delete mPhysics; delete mPlayer; } @@ -2000,7 +2001,7 @@ namespace MWWorld && isLevitationEnabled()) return true; - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(ptr.getRefData().getHandle()); + const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); if(!actor || !actor->getCollisionMode()) return true; @@ -2040,7 +2041,7 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { pos.z += heightRatio*2*actor->getHalfExtents().z; @@ -2069,8 +2070,8 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - RefData &refdata = ptr.getRefData(); - OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + //RefData &refdata = ptr.getRefData(); + OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2142,15 +2143,17 @@ namespace MWWorld CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr player = mPlayer->getPlayer(); - RefData &refdata = player.getRefData(); - Ogre::Vector3 playerPos(refdata.getPosition().pos); + //RefData &refdata = player.getRefData(); + //Ogre::Vector3 playerPos(refdata.getPosition().pos); + /* const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if (!physactor) throw std::runtime_error("can't find player"); if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; + */ if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; @@ -2160,7 +2163,7 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - return 0;//return mRendering->getAnimation(ptr); + return mRendering->getAnimation(ptr); } void World::frameStarted (float dt, bool paused) @@ -2295,7 +2298,7 @@ namespace MWWorld float World::getWindSpeed() { if (isCellExterior() || isCellQuasiExterior()) - return 0;//mWeatherManager->getWindSpeed(); + return mWeatherManager->getWindSpeed(); else return 0.f; } @@ -2303,7 +2306,7 @@ namespace MWWorld bool World::isInStorm() const { if (isCellExterior() || isCellQuasiExterior()) - return 0;//mWeatherManager->isInStorm(); + return mWeatherManager->isInStorm(); else return false; } @@ -2311,7 +2314,7 @@ namespace MWWorld Ogre::Vector3 World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) - return Ogre::Vector3();//mWeatherManager->getStormDirection(); + return mWeatherManager->getStormDirection(); else return Ogre::Vector3(0,1,0); } @@ -2800,7 +2803,7 @@ namespace MWWorld { MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); if (cell->isExterior()) - return 0;//mWeatherManager->isDark(); + return mWeatherManager->isDark(); else { uint32_t ambient = cell->getCell()->mAmbi.mAmbient; From 7809caf9dc69ec6d3ad361c0066ca232c75cfe4c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 15:53:11 +0200 Subject: [PATCH 0171/1812] Dead code removal --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwbase/world.hpp | 1 - apps/openmw/mwgui/myguirendermanager.cpp | 4 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ------ apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 5 ----- apps/openmw/mwworld/worldimp.hpp | 1 - 7 files changed, 1 insertion(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fdd51ef446..d5960779c9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -303,8 +303,6 @@ namespace MWBase virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; - virtual void frameStarted(float dt) = 0; - virtual void changePointer (const std::string& name) = 0; virtual void setEnemy (const MWWorld::Ptr& enemy) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 0c1874ce6d..00d4d8536a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -460,7 +460,6 @@ namespace MWBase virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here - virtual void frameStarted (float dt, bool paused) = 0; virtual void screenshot (Ogre::Image& image, int w, int h) = 0; /// Find default position inside exterior cell specified by name diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 55e78cb0c3..c066ba3085 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -460,15 +460,13 @@ void RenderManager::initialise() state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - state->setRenderBinDetails(11, "RenderBin"); state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); mGuiRoot = camera; - mSceneRoot->addChild(mGuiRoot.get()); + //mSceneRoot->addChild(mGuiRoot.get()); mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 86d065e39c..ce1314c6fd 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1501,12 +1501,6 @@ namespace MWGui updateVisible(); } - void WindowManager::frameStarted (float dt) - { - mInventoryWindow->doRenderUpdate (); - mCharGen->doRenderUpdate(); - } - void WindowManager::updatePlayer() { mInventoryWindow->updatePlayer(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 54b69be407..738690bbc7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -309,8 +309,6 @@ namespace MWGui virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); - virtual void frameStarted(float dt); - virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77028aaffa..2c92ad93bf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2166,11 +2166,6 @@ namespace MWWorld return mRendering->getAnimation(ptr); } - void World::frameStarted (float dt, bool paused) - { - //mRendering->frameStarted(dt, paused); - } - void World::screenshot(Ogre::Image &image, int w, int h) { //mRendering->screenshot(image, w, h); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5f79f52dcf..e9655b12e8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -564,7 +564,6 @@ namespace MWWorld virtual void reattachPlayerCamera(); /// \todo this does not belong here - virtual void frameStarted (float dt, bool paused); virtual void screenshot (Ogre::Image& image, int w, int h); /// Find center of exterior cell above land surface From b4a06bd78d361983e29c190264c1ea557ad779cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Apr 2015 19:32:07 +0200 Subject: [PATCH 0172/1812] Improve skinning performance --- components/sceneutil/riggeometry.cpp | 82 +++++++++++++++++++++------- components/sceneutil/riggeometry.hpp | 11 +++- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ab9abcddab..9205ef379e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -114,19 +114,60 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return false; } + typedef std::map > Vertex2BoneMap; + Vertex2BoneMap vertex2BoneMap; for (std::map::const_iterator it = mInfluenceMap->mMap.begin(); it != mInfluenceMap->mMap.end(); ++it) { - Bone* b = mSkeleton->getBone(it->first); - if (!b) + Bone* bone = mSkeleton->getBone(it->first); + if (!bone) { std::cerr << "RigGeometry did not find bone " << it->first << std::endl; + continue; } - mResolvedInfluenceMap[b] = it->second; + const BoneInfluence& bi = it->second; + + const std::map& weights = it->second.mWeights; + for (std::map::const_iterator weightIt = weights.begin(); weightIt != weights.end(); ++weightIt) + { + std::vector& vec = vertex2BoneMap[weightIt->first]; + + BoneWeight b = std::make_pair(std::make_pair(bone, bi.mInvBindMatrix), weightIt->second); + + vec.push_back(b); + } } + + for (Vertex2BoneMap::iterator it = vertex2BoneMap.begin(); it != vertex2BoneMap.end(); it++) + { + mBone2VertexMap[it->second].push_back(it->first); + } + return true; } +void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) +{ + osg::Matrixf m = invBindMatrix * matrix; + float* ptr = m.ptr(); + float* ptrresult = result.ptr(); + ptrresult[0] += ptr[0] * weight; + ptrresult[1] += ptr[1] * weight; + ptrresult[2] += ptr[2] * weight; + + ptrresult[4] += ptr[4] * weight; + ptrresult[5] += ptr[5] * weight; + ptrresult[6] += ptr[6] * weight; + + ptrresult[8] += ptr[8] * weight; + ptrresult[9] += ptr[9] * weight; + ptrresult[10] += ptr[10] * weight; + + ptrresult[12] += ptr[12] * weight; + ptrresult[13] += ptr[13] * weight; + ptrresult[14] += ptr[14] * weight; +} + void RigGeometry::update(osg::NodeVisitor* nv) { if (!mSkeleton) @@ -158,29 +199,28 @@ void RigGeometry::update(osg::NodeVisitor* nv) osg::Vec3Array* positionDst = static_cast(getVertexArray()); osg::Vec3Array* normalDst = static_cast(getNormalArray()); - for (unsigned int i=0; isize(); ++i) - (*positionDst)[i] = osg::Vec3f(0,0,0); - for (unsigned int i=0; isize(); ++i) - (*normalDst)[i] = osg::Vec3f(0,0,0); - - for (ResolvedInfluenceMap::const_iterator it = mResolvedInfluenceMap.begin(); it != mResolvedInfluenceMap.end(); ++it) + for (Bone2VertexMap::const_iterator it = mBone2VertexMap.begin(); it != mBone2VertexMap.end(); ++it) { - const BoneInfluence& bi = it->second; - Bone* bone = it->first; + osg::Matrixf resultMat (0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1); - // Here we could cache the (weighted) matrix for each combination of bone weights - - osg::Matrixf finalMatrix = bi.mInvBindMatrix * bone->mMatrixInSkeletonSpace * geomToSkel; - - for (std::map::const_iterator weightIt = bi.mWeights.begin(); weightIt != bi.mWeights.end(); ++weightIt) + for (std::vector::const_iterator weightIt = it->first.begin(); weightIt != it->first.end(); ++weightIt) { - unsigned short vertex = weightIt->first; + Bone* bone = weightIt->first.first; + const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; + const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; + accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); + } + resultMat = resultMat * geomToSkel; - osg::Vec3f a = (*positionSrc)[vertex]; - - (*positionDst)[vertex] += finalMatrix.preMult(a) * weight; - (*normalDst)[vertex] += osg::Matrix::transform3x3((*normalSrc)[vertex], finalMatrix) * weight; + for (std::vector::const_iterator vertexIt = it->second.begin(); vertexIt != it->second.end(); ++vertexIt) + { + unsigned short vertex = *vertexIt; + (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); + (*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat); } } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index c77ff7c726..f8458cdfa4 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -47,8 +47,15 @@ namespace SceneUtil osg::ref_ptr mInfluenceMap; - typedef std::map ResolvedInfluenceMap; - ResolvedInfluenceMap mResolvedInfluenceMap; + typedef std::pair BoneBindMatrixPair; + + typedef std::pair BoneWeight; + + typedef std::vector VertexList; + + typedef std::map, VertexList> Bone2VertexMap; + + Bone2VertexMap mBone2VertexMap; bool initFromParentSkeleton(osg::NodeVisitor* nv); }; From 8971a200f7ef882729170f04d3d2e486f079ce2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Apr 2015 14:34:14 +0200 Subject: [PATCH 0173/1812] Sky fix --- apps/openmw/mwrender/sky.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0529b9a7ba..97055ecae3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -554,6 +554,7 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); mCreated = true; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2c92ad93bf..4e737fc07c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2401,7 +2401,7 @@ namespace MWWorld void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { - OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor) physicActor->enableCollisionBody(enable); } From 63b69db617c66c33f303195f8504f34976a9f471 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Apr 2015 15:41:34 +0200 Subject: [PATCH 0174/1812] Port skeleton based bounding boxes to the new skinning system Not sure if going to keep this, there's a noticable performance impact. --- components/nifosg/nifloader.cpp | 33 +---------- components/sceneutil/riggeometry.cpp | 82 +++++++++++++++++++++++----- components/sceneutil/riggeometry.hpp | 9 +++ 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 38ead09252..936f266dd1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1043,24 +1043,6 @@ namespace NifOsg return morphGeom; } - class BoundingBoxCallback : public osg::NodeCallback - { - public: - virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) - { - osg::BoundingBox bb = mDrawable->getBound(); - - static_cast(node)->setMatrix( - osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), bb.zMax()-bb.zMin()) * - osg::Matrix::translate(bb.center()) ); - - traverse(node, nv); - } - - osg::Drawable* mDrawable; - }; - - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1091,25 +1073,12 @@ namespace NifOsg influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); + influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - // Compute the bounding box - osg::BoundingBox boundingBox; - - osg::Matrix worldTrans = getWorldTransform(triShape); - for(size_t i = 0;i < bones.length();i++) - { - osg::BoundingSphere boneSphere (data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); - osg::Matrix boneWorldTrans(getWorldTransform(bones[i].getPtr())); - osg::Matrix mat = boneWorldTrans * worldTrans.inverse(worldTrans); - SceneUtil::transformBoundingSphere(mat, boneSphere); - boundingBox.expandBy(boneSphere); - } - rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(boundingBox)); - geode->addDrawable(rig); // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 9205ef379e..19e5b0ae63 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,14 +6,34 @@ #include #include +#include #include "skeleton.hpp" - -#include +#include "util.hpp" namespace SceneUtil { +class UpdateRigBounds : public osg::Drawable::UpdateCallback +{ +public: + UpdateRigBounds() + { + } + + UpdateRigBounds(const UpdateRigBounds& copy, const osg::CopyOp& copyop) + : osg::Drawable::UpdateCallback(copy, copyop) + { + } + + void update(osg::NodeVisitor* nv, osg::Drawable* drw) + { + RigGeometry* rig = static_cast(drw); + + rig->updateBounds(nv); + } +}; + // TODO: make threadsafe for multiple cull threads class UpdateRigGeometry : public osg::Drawable::CullCallback { @@ -40,6 +60,7 @@ public: RigGeometry::RigGeometry() { setCullCallback(new UpdateRigGeometry); + setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); } @@ -125,6 +146,8 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) continue; } + mBoneSphereMap[bone] = it->second.mBoundSphere; + const BoneInfluence& bi = it->second; const std::map& weights = it->second.mWeights; @@ -178,19 +201,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) mSkeleton->updateBoneMatrices(nv); - osg::NodePath path; - bool foundSkel = false; - for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) - { - if (!foundSkel) - { - if (*it == mSkeleton) - foundSkel = true; - } - else - path.push_back(*it); - } - osg::Matrixf geomToSkel = osg::computeWorldToLocal(path); + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); @@ -228,6 +239,47 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); } +void RigGeometry::updateBounds(osg::NodeVisitor *nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + mSkeleton->updateBoneMatrices(nv); + + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + osg::BoundingBox box; + for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) + { + Bone* bone = it->first; + osg::BoundingSpheref bs = it->second; + transformBoundingSphere(bone->mMatrixInSkeletonSpace * geomToSkel, bs); + box.expandBy(bs); + } + + setInitialBound(box); +} + +osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) +{ + osg::NodePath path; + bool foundSkel = false; + for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) + { + if (!foundSkel) + { + if (*it == mSkeleton) + foundSkel = true; + } + else + path.push_back(*it); + } + return osg::computeWorldToLocal(path); + +} + void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) { mInfluenceMap = influenceMap; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index f8458cdfa4..e82f6254a4 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -24,6 +24,7 @@ namespace SceneUtil struct BoneInfluence { osg::Matrixf mInvBindMatrix; + osg::BoundingSpheref mBoundSphere; // std::map mWeights; }; @@ -40,6 +41,8 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); + // Called automatically by our UpdateCallback + void updateBounds(osg::NodeVisitor* nv); private: osg::ref_ptr mSourceGeometry; @@ -57,7 +60,13 @@ namespace SceneUtil Bone2VertexMap mBone2VertexMap; + typedef std::map BoneSphereMap; + + BoneSphereMap mBoneSphereMap; + bool initFromParentSkeleton(osg::NodeVisitor* nv); + + osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); }; } From a27446c8fbc8900273852c9f8ca7da8e69fc7f10 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Apr 2015 16:02:29 +0200 Subject: [PATCH 0175/1812] Remove unused headers --- apps/openmw/mwgui/myguiplatform.hpp | 5 +---- apps/openmw/mwgui/myguirendermanager.cpp | 4 ++++ apps/openmw/mwgui/myguirendermanager.hpp | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/apps/openmw/mwgui/myguiplatform.hpp index 4c3e701439..a2256e9703 100644 --- a/apps/openmw/mwgui/myguiplatform.hpp +++ b/apps/openmw/mwgui/myguiplatform.hpp @@ -2,9 +2,6 @@ #define OPENMW_MWGUI_MYGUIPLATFORM_H #include "MyGUI_Prerequest.h" -#include "MyGUI_DummyRenderManager.h" -#include "MyGUI_DummyDataManager.h" -#include "MyGUI_DummyDiagnostic.h" #include "MyGUI_LogManager.h" #include "myguirendermanager.hpp" @@ -36,7 +33,7 @@ namespace MWGui mLogManager = nullptr; } - void initialise(const std::string& resourcePath, const std::string& _logName = MYGUI_PLATFORM_LOG_FILENAME) + void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") { if (!_logName.empty()) MyGUI::LogManager::getInstance().createDefaultSource(_logName); diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index c066ba3085..06e404d884 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -476,6 +476,10 @@ void RenderManager::initialise() mIsInitialise = true; } +void RenderManager::shutdown() +{ +} + MyGUI::IVertexBuffer* RenderManager::createVertexBuffer() { return new OSGVertexBuffer(); diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/apps/openmw/mwgui/myguirendermanager.hpp index 64a5fe07b1..513edb5b72 100644 --- a/apps/openmw/mwgui/myguirendermanager.hpp +++ b/apps/openmw/mwgui/myguirendermanager.hpp @@ -53,6 +53,7 @@ public: virtual ~RenderManager(); void initialise(); + void shutdown(); static RenderManager& getInstance() { return *getInstancePtr(); } static RenderManager* getInstancePtr() From 48a6d7c1a0bc9b0867f98e5387c31326397bd751 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Apr 2015 16:31:32 +0200 Subject: [PATCH 0176/1812] Remove mygui platform libraries from cmake --- CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 2 -- cmake/FindMyGUI.cmake | 24 ++---------------------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8a2458b1b..d2a245366f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,7 +241,6 @@ include_directories("." ${LIBS_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} - ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} ) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index acca23f8eb..a36dd4e2ae 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -139,7 +139,6 @@ target_link_libraries(openmw ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} - ${MYGUI_PLATFORM_LIBRARIES} ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" @@ -153,7 +152,6 @@ if (ANDROID) android log dl - MyGUI.OgrePlatform MyGUIEngineStatic Plugin_StrangeButtonStatic cpufeatures diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index b5c4e8ade7..b52d94f980 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -27,7 +27,6 @@ IF (WIN32) #Windows STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}" ) find_path ( MYGUI_INCLUDE_DIRS MyGUI.h "${MYGUISDK}/MyGUIEngine/include" NO_DEFAULT_PATH ) - find_path ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h "${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" NO_DEFAULT_PATH ) SET ( MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib ) @@ -35,27 +34,15 @@ IF (WIN32) #Windows set(LIB_SUFFIX "Static") endif ( MYGUI_STATIC ) - find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - find_library ( MYGUI_LIBRARIES_DBG NAMES MyGUIEngine${LIB_SUFFIX}_d.lib MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) - - find_library ( MYGUI_PLATFORM_LIBRARIES_REL NAMES MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - find_library ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) + find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + find_library ( MYGUI_LIBRARIES_DBG NAMES MyGUIEngine${LIB_SUFFIX}_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) make_library_set ( MYGUI_LIBRARIES ) - make_library_set ( MYGUI_PLATFORM_LIBRARIES ) MESSAGE ("${MYGUI_LIBRARIES}") - MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") #findpkg_finish ( "MYGUI" ) ENDIF (MYGUISDK) - IF (OGRESOURCE) - MESSAGE(STATUS "Using MyGUI in OGRE dependencies") - STRING(REGEX REPLACE "[\\]" "/" OGRESDK "${OGRESOURCE}" ) - SET(MYGUI_INCLUDE_DIRS ${OGRESOURCE}/OgreMain/include/MYGUI) - SET(MYGUI_LIB_DIR ${OGRESOURCE}/lib) - SET(MYGUI_LIBRARIES debug Debug/MyGUIEngine_d optimized Release/MyGUIEngine) - ENDIF (OGRESOURCE) ELSE (WIN32) #Unix CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) FIND_PACKAGE(PkgConfig) @@ -67,11 +54,9 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -81,7 +66,6 @@ ELSE (WIN32) #Unix FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -92,11 +76,9 @@ ELSE (WIN32) #Unix SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") ELSE (MYGUI_INCLUDE_DIRS) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.DummyPlatform") SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") @@ -108,14 +90,12 @@ ENDIF (WIN32) 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}) SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS} CACHE PATH "") SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") -SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "") SET(MYGUI_LIB_DIR ${MYGUI_LIB_DIR} CACHE PATH "") IF (NOT APPLE OR NOT MYGUI_STATIC) # we need explicit freetype libs only on OS X for static build, for other cases just make it TRUE From 83c6ba97c01a9a335ecde520db3f830cee0c1023 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 29 Apr 2015 23:48:08 +0200 Subject: [PATCH 0177/1812] Disable skinning updates for actors beyond the AI processing distance --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwrender/animation.cpp | 8 ++++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ components/sceneutil/riggeometry.cpp | 12 ++++++++++++ components/sceneutil/riggeometry.hpp | 3 +++ components/sceneutil/skeleton.cpp | 14 ++++++++++++-- components/sceneutil/skeleton.hpp | 8 ++++++++ 9 files changed, 61 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bb59d46c09..3333511d3f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1085,12 +1085,15 @@ namespace MWMechanics // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { + bool inProcessingRange = Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + <= sqrProcessingDistance; + + iter->second->getCharacterController()->setActive(inProcessingRange); + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); - if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && - Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) - <= sqrProcessingDistance) + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) { if (timerUpdateAITargets == 0) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 98a420ba67..adcfb57a47 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1898,6 +1898,11 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +void CharacterController::setActive(bool active) +{ + mAnimation->setActive(active); +} + void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) { mHeadTrackTarget = target; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index da74b2a33f..987a0d29a5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -228,6 +228,9 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + /// @see Animation::setActive + void setActive(bool active); + /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::Ptr& target); }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c5479e3f79..245095492b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -214,6 +214,14 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + void Animation::setActive(bool active) + { + if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) + { + skel->setActive(active); + } + } + void Animation::updatePtr(const MWWorld::Ptr &ptr) { mPtr = ptr; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 9aa15520ff..c85f874038 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -242,6 +242,10 @@ public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + /// Set active flag on the object skeleton, if one exists. + /// @see SceneUtil::Skeleton::setActive + void setActive(bool active); + osg::Group* getOrCreateObjectRoot(); osg::Group* getObjectRoot(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 19e5b0ae63..7f30aff74d 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -58,6 +58,8 @@ public: }; RigGeometry::RigGeometry() + : mFirstFrame(true) + , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); @@ -67,6 +69,8 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mInfluenceMap(copy.mInfluenceMap) + , mFirstFrame(copy.mFirstFrame) + , mBoundsFirstFrame(copy.mBoundsFirstFrame) { setSourceGeometry(copy.mSourceGeometry); } @@ -199,6 +203,10 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); @@ -247,6 +255,10 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) return; } + if (!mSkeleton->getActive() && !mBoundsFirstFrame) + return; + mBoundsFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e82f6254a4..ea4245aa8b 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -64,6 +64,9 @@ namespace SceneUtil BoneSphereMap mBoneSphereMap; + bool mFirstFrame; + bool mBoundsFirstFrame; + bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index c1ab36136b..f105977bad 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -35,6 +35,7 @@ Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(true) { } @@ -44,12 +45,11 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(copy.mActive) { } - - Bone* Skeleton::getBone(const std::string &name) { if (!mBoneCacheInit) @@ -123,6 +123,16 @@ void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) } } +void Skeleton::setActive(bool active) +{ + mActive = active; +} + +bool Skeleton::getActive() const +{ + return mActive; +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d710ac61b6..1987fd4e8f 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -47,6 +47,12 @@ namespace SceneUtil /// Request an update of bone matrices. May be a no-op if already updated in this frame. void updateBoneMatrices(osg::NodeVisitor* nv); + /// Set the skinning active flag. Inactive skeletons will not have their child rigs updated. + /// You should set this flag to false if you know that bones are not currently moving. + void setActive(bool active); + + bool getActive() const; + private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. // As far as the scene graph goes we support multiple root bones. @@ -58,6 +64,8 @@ namespace SceneUtil bool mNeedToUpdateBoneMatrices; + bool mActive; + unsigned int mLastFrameNumber; }; From a98dc78cc568ee9fd984bc0f113de441a2615497 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 15:46:16 +0200 Subject: [PATCH 0178/1812] Bounds fix --- components/sceneutil/riggeometry.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 7f30aff74d..df5f65029e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -271,7 +271,9 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) box.expandBy(bs); } - setInitialBound(box); + _boundingBox = box; + for (unsigned int i=0; idirtyBound(); } osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) From 15bdb7db01b58bea6ad20048eb45838c107b71b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 17:17:13 +0200 Subject: [PATCH 0179/1812] transformBoundingSphere optimization --- components/sceneutil/util.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index a41c6b74b3..52f9c9e54e 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -20,17 +20,18 @@ void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bs bsphere._center = bsphere._center*matrix; xdash -= bsphere._center; - osg::BoundingSphere::value_type len_xdash = xdash.length(); + osg::BoundingSphere::value_type sqrlen_xdash = xdash.length2(); ydash -= bsphere._center; - osg::BoundingSphere::value_type len_ydash = ydash.length(); + osg::BoundingSphere::value_type sqrlen_ydash = ydash.length2(); zdash -= bsphere._center; - osg::BoundingSphere::value_type len_zdash = zdash.length(); + osg::BoundingSphere::value_type sqrlen_zdash = zdash.length2(); - bsphere._radius = len_xdash; - if (bsphere._radius Date: Thu, 30 Apr 2015 23:17:06 +0200 Subject: [PATCH 0180/1812] Uninitialized basenode fix --- apps/openmw/mwworld/refdata.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 7e83fda5e0..82bb06b8d8 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -37,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) + : mBaseNode(0), mBase(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) { for (int i=0; i<3; ++i) { @@ -48,7 +48,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), + : mBaseNode(0), mBase(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false), // Loading from ESM/ESP files -> assume unchanged mDeleted(false) @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), + : mBaseNode (0), mBase(0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true), // Loading from a savegame -> assume changed mDeleted(false) @@ -69,7 +69,7 @@ namespace MWWorld } RefData::RefData (const RefData& refData) - : mBaseNode(0), mCustomData (0) + : mBaseNode(0), mBase(0), mCustomData (0) { try { From 62847f0489d4adf099bef35dbd8c9a4f78e969b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Apr 2015 23:21:25 +0200 Subject: [PATCH 0181/1812] Use node masks to separate Scene and GUI --- apps/openmw/engine.cpp | 3 +++ apps/openmw/mwgui/myguirendermanager.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 9 +++++++-- apps/openmw/mwrender/sky.cpp | 6 +++++- apps/openmw/mwrender/vismask.hpp | 7 ++++++- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 582172bffd..e2e09bdec2 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -41,6 +41,8 @@ #include "mwworld/player.hpp" #include "mwworld/worldimp.hpp" +#include "mwrender/vismask.hpp" + #include "mwclass/classes.hpp" #include "mwdialogue/dialoguemanagerimp.hpp" @@ -339,6 +341,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; + guiRoot->setNodeMask(MWRender::Mask_GUI); rootNode->addChild(guiRoot); MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index 06e404d884..f218d9ff09 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -466,7 +466,7 @@ void RenderManager::initialise() camera->addChild(geode.get()); mGuiRoot = camera; - //mSceneRoot->addChild(mGuiRoot.get()); + mSceneRoot->addChild(mGuiRoot.get()); mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d68620f8ad..8689935d0c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -23,6 +23,7 @@ #include "sky.hpp" #include "effectmanager.hpp" +#include "vismask.hpp" namespace MWRender { @@ -87,8 +88,6 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); - mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); - mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); mViewer.setLightingMode(osgViewer::View::NO_LIGHT); @@ -105,6 +104,10 @@ namespace MWRender lightRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + lightRoot->setNodeMask(Mask_Scene); + + mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); + source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); mStateUpdater = new StateUpdater; @@ -128,6 +131,8 @@ namespace MWRender zNear = 5.f; zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + + mViewer.getCamera()->setCullMask(mViewer.getCamera()->getCullMask() & (~Mask_GUI)); } RenderingManager::~RenderingManager() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 97055ecae3..4fd5b7e631 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -554,7 +554,6 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); mCreated = true; } @@ -562,6 +561,11 @@ void SkyManager::create() SkyManager::~SkyManager() { clearRain(); + if (mRootNode) + { + mRootNode->getParent(0)->removeChild(mRootNode); + mRootNode = NULL; + } } int SkyManager::getMasserPhase() const diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 4a064b60f3..48845c78c3 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -9,7 +9,12 @@ namespace MWRender { Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors - Mask_Effect = 0x2 + // child of Scene + Mask_Effect = 0x2, + + // top level masks + Mask_Scene = 0x10, + Mask_GUI = 0x20 }; } From db7fe1952dcf8033628b7a4bca7f9430a9590d50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 00:59:41 +0200 Subject: [PATCH 0182/1812] Move MyGUI texture to a separate file --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/myguirendermanager.cpp | 182 +---------------------- apps/openmw/mwgui/myguitexture.cpp | 164 ++++++++++++++++++++ apps/openmw/mwgui/myguitexture.hpp | 64 ++++++++ 4 files changed, 231 insertions(+), 181 deletions(-) create mode 100644 apps/openmw/mwgui/myguitexture.cpp create mode 100644 apps/openmw/mwgui/myguitexture.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a36dd4e2ae..680ea9c86c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager + draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager myguitexture ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/apps/openmw/mwgui/myguirendermanager.cpp index f218d9ff09..e5160bb5b9 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/apps/openmw/mwgui/myguirendermanager.cpp @@ -19,6 +19,8 @@ #include +#include "myguitexture.hpp" + #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) @@ -217,186 +219,6 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -class OSGTexture : public MyGUI::ITexture { - std::string mName; - Resource::TextureManager* mTextureManager; - - osg::ref_ptr mLockedImage; - osg::ref_ptr mTexture; - MyGUI::PixelFormat mFormat; - MyGUI::TextureUsage mUsage; - size_t mNumElemBytes; - -public: - OSGTexture(const std::string &name, Resource::TextureManager* textureManager); - virtual ~OSGTexture(); - - virtual const std::string& getName() const { return mName; } - - virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); - virtual void loadFromFile(const std::string &fname); - virtual void saveToFile(const std::string &fname); - - virtual void destroy(); - - virtual void* lock(MyGUI::TextureUsage access); - virtual void unlock(); - virtual bool isLocked(); - - virtual int getWidth(); - virtual int getHeight(); - - virtual MyGUI::PixelFormat getFormat() { return mFormat; } - virtual MyGUI::TextureUsage getUsage() { return mUsage; } - virtual size_t getNumElemBytes() { return mNumElemBytes; } - - virtual MyGUI::IRenderTarget *getRenderTarget(); - -/*internal:*/ - osg::Texture2D *getTexture() const { return mTexture.get(); } -}; - -OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) - : mName(name) - , mTextureManager(textureManager) - , mFormat(MyGUI::PixelFormat::Unknow) - , mUsage(MyGUI::TextureUsage::Default) - , mNumElemBytes(0) -{ -} - -OSGTexture::~OSGTexture() -{ -} - -void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) -{ - GLenum glfmt = GL_NONE; - size_t numelems = 0; - switch(format.getValue()) - { - case MyGUI::PixelFormat::L8: - glfmt = GL_LUMINANCE; - numelems = 1; - break; - case MyGUI::PixelFormat::L8A8: - glfmt = GL_LUMINANCE_ALPHA; - numelems = 2; - break; - case MyGUI::PixelFormat::R8G8B8: - glfmt = GL_RGB; - numelems = 3; - break; - case MyGUI::PixelFormat::R8G8B8A8: - glfmt = GL_RGBA; - numelems = 4; - break; - } - if(glfmt == GL_NONE) - throw std::runtime_error("Texture format not supported"); - - mTexture = new osg::Texture2D(); - mTexture->setTextureSize(width, height); - mTexture->setSourceFormat(glfmt); - mTexture->setSourceType(GL_UNSIGNED_BYTE); - - mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - - mFormat = format; - mUsage = usage; - mNumElemBytes = numelems; -} - -void OSGTexture::destroy() -{ - mTexture = nullptr; - mFormat = MyGUI::PixelFormat::Unknow; - mUsage = MyGUI::TextureUsage::Default; - mNumElemBytes = 0; -} - -void OSGTexture::loadFromFile(const std::string &fname) -{ - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); - - // FIXME - mFormat = MyGUI::PixelFormat::R8G8B8; - mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; - mNumElemBytes = 3; // FIXME -} - -void OSGTexture::saveToFile(const std::string &fname) -{ - std::cerr << "Would save image to file " << fname << std::endl; -} - - -int OSGTexture::getWidth() -{ - if(!mTexture.valid()) - return 0; - osg::Image *image = mTexture->getImage(); - if(image) return image->s(); - return mTexture->getTextureWidth(); -} - -int OSGTexture::getHeight() -{ - if(!mTexture.valid()) - return 0; - osg::Image *image = mTexture->getImage(); - if(image) return image->t(); - return mTexture->getTextureHeight(); -} - - -void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) -{ - MYGUI_PLATFORM_ASSERT(mTexture.valid(), "Texture is not created"); - MYGUI_PLATFORM_ASSERT(!mLockedImage.valid(), "Texture already locked"); - - mLockedImage = mTexture->getImage(); - if(!mLockedImage.valid()) - { - mLockedImage = new osg::Image(); - mLockedImage->allocateImage( - mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), - mTexture->getSourceFormat(), mTexture->getSourceType() - ); - } - return mLockedImage->data(); -} - -void OSGTexture::unlock() -{ - MYGUI_PLATFORM_ASSERT(mLockedImage.valid(), "Texture not locked"); - - // Tell the texture it can get rid of the image for static textures (since - // they aren't expected to update much at all). - mTexture->setImage(mLockedImage.get()); - mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); - mTexture->dirtyTextureObject(); - - mLockedImage = nullptr; -} - -bool OSGTexture::isLocked() -{ - return mLockedImage.valid(); -} - - -// FIXME: Render-to-texture not currently implemented. -MyGUI::IRenderTarget* OSGTexture::getRenderTarget() -{ - return nullptr; -} - -// --------------------------------------------------------------------------- - RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) : mViewer(viewer) , mSceneRoot(sceneroot) diff --git a/apps/openmw/mwgui/myguitexture.cpp b/apps/openmw/mwgui/myguitexture.cpp new file mode 100644 index 0000000000..d61e396f1e --- /dev/null +++ b/apps/openmw/mwgui/myguitexture.cpp @@ -0,0 +1,164 @@ +#include "myguitexture.hpp" + +#include +#include + +#include + +#include + +namespace MWGui +{ + + OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) + : mName(name) + , mTextureManager(textureManager) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) + { + } + + OSGTexture::OSGTexture(osg::Texture2D *texture) + : mTextureManager(NULL) + , mTexture(texture) + , mFormat(MyGUI::PixelFormat::Unknow) + , mUsage(MyGUI::TextureUsage::Default) + , mNumElemBytes(0) + { + } + + OSGTexture::~OSGTexture() + { + } + + void OSGTexture::createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format) + { + GLenum glfmt = GL_NONE; + size_t numelems = 0; + switch(format.getValue()) + { + case MyGUI::PixelFormat::L8: + glfmt = GL_LUMINANCE; + numelems = 1; + break; + case MyGUI::PixelFormat::L8A8: + glfmt = GL_LUMINANCE_ALPHA; + numelems = 2; + break; + case MyGUI::PixelFormat::R8G8B8: + glfmt = GL_RGB; + numelems = 3; + break; + case MyGUI::PixelFormat::R8G8B8A8: + glfmt = GL_RGBA; + numelems = 4; + break; + } + if(glfmt == GL_NONE) + throw std::runtime_error("Texture format not supported"); + + mTexture = new osg::Texture2D(); + mTexture->setTextureSize(width, height); + mTexture->setSourceFormat(glfmt); + mTexture->setSourceType(GL_UNSIGNED_BYTE); + + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + mFormat = format; + mUsage = usage; + mNumElemBytes = numelems; + } + + void OSGTexture::destroy() + { + mTexture = nullptr; + mFormat = MyGUI::PixelFormat::Unknow; + mUsage = MyGUI::TextureUsage::Default; + mNumElemBytes = 0; + } + + void OSGTexture::loadFromFile(const std::string &fname) + { + if (!mTextureManager) + throw std::runtime_error("No texturemanager set"); + + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + + // FIXME + mFormat = MyGUI::PixelFormat::R8G8B8; + mUsage = MyGUI::TextureUsage::Static | MyGUI::TextureUsage::Write; + mNumElemBytes = 3; // FIXME + } + + void OSGTexture::saveToFile(const std::string &fname) + { + std::cerr << "Would save image to file " << fname << std::endl; + } + + int OSGTexture::getWidth() + { + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->s(); + return mTexture->getTextureWidth(); + } + + int OSGTexture::getHeight() + { + if(!mTexture.valid()) + return 0; + osg::Image *image = mTexture->getImage(); + if(image) return image->t(); + return mTexture->getTextureHeight(); + } + + void *OSGTexture::lock(MyGUI::TextureUsage /*access*/) + { + if (!mTexture.valid()) + throw std::runtime_error("Texture is not created"); + if (mLockedImage.valid()) + throw std::runtime_error("Texture already locked"); + + mLockedImage = mTexture->getImage(); + if(!mLockedImage.valid()) + { + mLockedImage = new osg::Image(); + mLockedImage->allocateImage( + mTexture->getTextureWidth(), mTexture->getTextureHeight(), mTexture->getTextureDepth(), + mTexture->getSourceFormat(), mTexture->getSourceType() + ); + } + return mLockedImage->data(); + } + + void OSGTexture::unlock() + { + if (!mLockedImage.valid()) + throw std::runtime_error("Texture not locked"); + + // Tell the texture it can get rid of the image for static textures (since + // they aren't expected to update much at all). + mTexture->setImage(mLockedImage.get()); + mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + mTexture->dirtyTextureObject(); + + mLockedImage = nullptr; + } + + bool OSGTexture::isLocked() + { + return mLockedImage.valid(); + } + + // Render-to-texture not currently implemented. + MyGUI::IRenderTarget* OSGTexture::getRenderTarget() + { + return nullptr; + } + +} diff --git a/apps/openmw/mwgui/myguitexture.hpp b/apps/openmw/mwgui/myguitexture.hpp new file mode 100644 index 0000000000..5ae34a3d6c --- /dev/null +++ b/apps/openmw/mwgui/myguitexture.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_MWGUI_MYGUITEXTURE_H +#define OPENMW_MWGUI_MYGUITEXTURE_H + +#include + +#include + +namespace osg +{ + class Image; + class Texture2D; +} + +namespace Resource +{ + class TextureManager; +} + +namespace MWGui +{ + + class OSGTexture : public MyGUI::ITexture { + std::string mName; + Resource::TextureManager* mTextureManager; + + osg::ref_ptr mLockedImage; + osg::ref_ptr mTexture; + MyGUI::PixelFormat mFormat; + MyGUI::TextureUsage mUsage; + size_t mNumElemBytes; + + public: + OSGTexture(const std::string &name, Resource::TextureManager* textureManager); + OSGTexture(osg::Texture2D* texture); + virtual ~OSGTexture(); + + virtual const std::string& getName() const { return mName; } + + virtual void createManual(int width, int height, MyGUI::TextureUsage usage, MyGUI::PixelFormat format); + virtual void loadFromFile(const std::string &fname); + virtual void saveToFile(const std::string &fname); + + virtual void destroy(); + + virtual void* lock(MyGUI::TextureUsage access); + virtual void unlock(); + virtual bool isLocked(); + + virtual int getWidth(); + virtual int getHeight(); + + virtual MyGUI::PixelFormat getFormat() { return mFormat; } + virtual MyGUI::TextureUsage getUsage() { return mUsage; } + virtual size_t getNumElemBytes() { return mNumElemBytes; } + + virtual MyGUI::IRenderTarget *getRenderTarget(); + + /*internal:*/ + osg::Texture2D *getTexture() const { return mTexture.get(); } + }; + +} + +#endif From a59940a2c734858332fba99ed8ba94366d23406d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 01:15:25 +0200 Subject: [PATCH 0183/1812] Move MyGUI platform to components --- apps/openmw/CMakeLists.txt | 6 +---- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 10 ++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 27 ++++++------------- apps/openmw/mwsound/soundmanagerimp.cpp | 2 ++ apps/openmw/mwworld/scene.hpp | 7 ----- apps/openmw/mwworld/worldimp.hpp | 6 ----- components/CMakeLists.txt | 8 ++++++ .../myguiplatform}/myguidatamanager.cpp | 2 +- .../myguiplatform}/myguidatamanager.hpp | 6 ++--- .../myguiplatform}/myguiplatform.cpp | 0 .../myguiplatform}/myguiplatform.hpp | 6 ++--- .../myguiplatform}/myguirendermanager.cpp | 14 +++++----- .../myguiplatform}/myguirendermanager.hpp | 6 ++--- .../myguiplatform}/myguitexture.cpp | 2 +- .../myguiplatform}/myguitexture.hpp | 6 ++--- components/widgets/imagebutton.hpp | 4 +-- components/widgets/list.hpp | 4 +-- 18 files changed, 51 insertions(+), 67 deletions(-) rename {apps/openmw/mwgui => components/myguiplatform}/myguidatamanager.cpp (98%) rename {apps/openmw/mwgui => components/myguiplatform}/myguidatamanager.hpp (89%) rename {apps/openmw/mwgui => components/myguiplatform}/myguiplatform.cpp (100%) rename {apps/openmw/mwgui => components/myguiplatform}/myguiplatform.hpp (92%) rename {apps/openmw/mwgui => components/myguiplatform}/myguirendermanager.cpp (97%) rename {apps/openmw/mwgui => components/myguiplatform}/myguirendermanager.hpp (95%) rename {apps/openmw/mwgui => components/myguiplatform}/myguitexture.cpp (99%) rename {apps/openmw/mwgui => components/myguiplatform}/myguitexture.hpp (92%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 680ea9c86c..f352547e0c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen myguiplatform myguirendermanager myguidatamanager myguitexture + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue @@ -107,9 +107,6 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -# for MyGUI platform -find_package(OpenGL REQUIRED) - if (NOT ANDROID) add_executable(openmw ${OPENMW_FILES} @@ -139,7 +136,6 @@ target_link_libraries(openmw ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} - ${OPENGL_gl_LIBRARY} "osg-ffmpeg-videoplayer" "oics" components diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e2e09bdec2..488c945015 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -343,7 +343,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) osg::ref_ptr guiRoot = new osg::Group; guiRoot->setNodeMask(MWRender::Mask_GUI); rootNode->addChild(guiRoot); - MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem->getTextureManager(), + MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ce1314c6fd..cac4939edf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -26,8 +26,12 @@ #include +#include + #include +#include + #include #include @@ -91,13 +95,11 @@ #include "controllers.hpp" #include "jailscreen.hpp" -#include "myguiplatform.hpp" - namespace MWGui { WindowManager::WindowManager( - osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager + osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -173,7 +175,7 @@ namespace MWGui , mCurrentModals() , mFallbackMap(fallbackMap) { - mGuiPlatform = new Platform(viewer, guiRoot, textureManager); + mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); mGuiPlatform->initialise(resourcePath, logpath); MyGUI::Gui* gui = new MyGUI::Gui; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 738690bbc7..894c81ec91 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -38,20 +38,6 @@ namespace Translation class Storage; } -namespace OEngine -{ - namespace GUI - { - class Layout; - class MyGUIManager; - } - - namespace Render - { - class OgreRenderer; - } -} - namespace osg { class Group; @@ -63,7 +49,7 @@ namespace osgViewer namespace Resource { - class TextureManager; + class ResourceSystem; } namespace SFO @@ -71,6 +57,11 @@ namespace SFO class CursorManager; } +namespace osgMyGUI +{ + class Platform; +} + namespace MWGui { class WindowBase; @@ -107,15 +98,13 @@ namespace MWGui class DebugWindow; class JailScreen; - class Platform; - class WindowManager : public MWBase::WindowManager { public: typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, + WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); virtual ~WindowManager(); @@ -365,7 +354,7 @@ namespace MWGui virtual void cycleWeapon(bool next); private: - Platform* mGuiPlatform; + osgMyGUI::Platform* mGuiPlatform; bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a5e18dd490..775e3da199 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -223,6 +223,8 @@ namespace MWSound { if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) filelist.push_back(found->first); + else + break; ++found; } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 26590c796d..f7ef9b2764 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -33,15 +33,9 @@ namespace Loading class Listener; } -namespace Render -{ - class OgreRenderer; -} - namespace MWRender { class SkyManager; - class CellRender; class RenderingManager; } @@ -59,7 +53,6 @@ namespace MWWorld private: - //OEngine::Render::OgreRenderer& mRenderer; CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e9655b12e8..447bb13006 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -53,15 +53,9 @@ namespace Files class Collections; } -namespace Render -{ - class OgreRenderer; -} - namespace MWRender { class SkyManager; - class CellRender; class Animation; class Camera; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cc913912f1..563a772686 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,6 +20,8 @@ else (GIT_CHECKOUT) configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) endif (GIT_CHECKOUT) +find_package(OpenGL REQUIRED) + # source files add_component_dir (settings @@ -116,6 +118,10 @@ add_component_dir (ogreinit ogreinit ogreplugin ) +add_component_dir (myguiplatform + myguirendermanager myguidatamanager myguiplatform myguitexture + ) + add_component_dir (widgets box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) @@ -170,6 +176,8 @@ target_link_libraries(components ${OGRE_LIBRARIES} ${OENGINE_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} ) if (GIT_CHECKOUT) diff --git a/apps/openmw/mwgui/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp similarity index 98% rename from apps/openmw/mwgui/myguidatamanager.cpp rename to components/myguiplatform/myguidatamanager.cpp index 5ba54b0092..69bc3878df 100644 --- a/apps/openmw/mwgui/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -7,7 +7,7 @@ #include -namespace MWGui +namespace osgMyGUI { void DataManager::setResourcePath(const std::string &path) diff --git a/apps/openmw/mwgui/myguidatamanager.hpp b/components/myguiplatform/myguidatamanager.hpp similarity index 89% rename from apps/openmw/mwgui/myguidatamanager.hpp rename to components/myguiplatform/myguidatamanager.hpp index eaf60f8b9d..5002f0fb75 100644 --- a/apps/openmw/mwgui/myguidatamanager.hpp +++ b/components/myguiplatform/myguidatamanager.hpp @@ -1,9 +1,9 @@ -#ifndef OPENMW_MWGUI_MYGUIDATAMANAGER_H -#define OPENMW_MWGUI_MYGUIDATAMANAGER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIDATAMANAGER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIDATAMANAGER_H #include -namespace MWGui +namespace osgMyGUI { diff --git a/apps/openmw/mwgui/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp similarity index 100% rename from apps/openmw/mwgui/myguiplatform.cpp rename to components/myguiplatform/myguiplatform.cpp diff --git a/apps/openmw/mwgui/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp similarity index 92% rename from apps/openmw/mwgui/myguiplatform.hpp rename to components/myguiplatform/myguiplatform.hpp index a2256e9703..5079b23b0a 100644 --- a/apps/openmw/mwgui/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUIPLATFORM_H -#define OPENMW_MWGUI_MYGUIPLATFORM_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H #include "MyGUI_Prerequest.h" #include "MyGUI_LogManager.h" @@ -7,7 +7,7 @@ #include "myguirendermanager.hpp" #include "myguidatamanager.hpp" -namespace MWGui +namespace osgMyGUI { class Platform diff --git a/apps/openmw/mwgui/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp similarity index 97% rename from apps/openmw/mwgui/myguirendermanager.cpp rename to components/myguiplatform/myguirendermanager.cpp index e5160bb5b9..3ebbd957a8 100644 --- a/apps/openmw/mwgui/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -48,24 +48,24 @@ namespace // Proxy to forward a Drawable's draw call to RenderManager::drawFrame class Renderable : public osg::Drawable { - MWGui::RenderManager *mParent; + osgMyGUI::RenderManager *mParent; virtual void drawImplementation(osg::RenderInfo &renderInfo) const { mParent->drawFrame(renderInfo); } public: - Renderable(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + Renderable(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) { } - META_Object(MWGui, Renderable) + META_Object(osgMyGUI, Renderable) }; // Proxy to forward an OSG resize event to RenderManager::setViewSize class ResizeHandler : public osgGA::GUIEventHandler { - MWGui::RenderManager *mParent; + osgMyGUI::RenderManager *mParent; virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { @@ -79,19 +79,19 @@ class ResizeHandler : public osgGA::GUIEventHandler { } public: - ResizeHandler(MWGui::RenderManager *parent=nullptr) : mParent(parent) { } + ResizeHandler(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) , mParent(copy.mParent) { } - META_Object(MWGui, ResizeHandler) + META_Object(osgMyGUI, ResizeHandler) }; } -namespace MWGui +namespace osgMyGUI { class OSGVertexBuffer : public MyGUI::IVertexBuffer diff --git a/apps/openmw/mwgui/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp similarity index 95% rename from apps/openmw/mwgui/myguirendermanager.hpp rename to components/myguiplatform/myguirendermanager.hpp index 513edb5b72..05d0f9a5a0 100644 --- a/apps/openmw/mwgui/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUIRENDERMANAGER_H -#define OPENMW_MWGUI_MYGUIRENDERMANAGER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIRENDERMANAGER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIRENDERMANAGER_H #include @@ -22,7 +22,7 @@ namespace osg class RenderInfo; } -namespace MWGui +namespace osgMyGUI { class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget diff --git a/apps/openmw/mwgui/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp similarity index 99% rename from apps/openmw/mwgui/myguitexture.cpp rename to components/myguiplatform/myguitexture.cpp index d61e396f1e..7de7ebfb0c 100644 --- a/apps/openmw/mwgui/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -7,7 +7,7 @@ #include -namespace MWGui +namespace osgMyGUI { OSGTexture::OSGTexture(const std::string &name, Resource::TextureManager* textureManager) diff --git a/apps/openmw/mwgui/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp similarity index 92% rename from apps/openmw/mwgui/myguitexture.hpp rename to components/myguiplatform/myguitexture.hpp index 5ae34a3d6c..de385e94d6 100644 --- a/apps/openmw/mwgui/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_MWGUI_MYGUITEXTURE_H -#define OPENMW_MWGUI_MYGUITEXTURE_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUITEXTURE_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUITEXTURE_H #include @@ -16,7 +16,7 @@ namespace Resource class TextureManager; } -namespace MWGui +namespace osgMyGUI { class OSGTexture : public MyGUI::ITexture { diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index bed6a27940..10150c6b1e 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -1,5 +1,5 @@ -#ifndef MWGUI_IMAGEBUTTON_H -#define MWGUI_IMAGEBUTTON_H +#ifndef OPENMW_COMPONENTS_WIDGETS_IMAGEBUTTON_H +#define OPENMW_COMPONENTS_WIDGETS_IMAGEBUTTON_H #include diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 72c8a733c1..6ee2ef3f2b 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -1,5 +1,5 @@ -#ifndef MWGUI_LIST_HPP -#define MWGUI_LIST_HPP +#ifndef OPENMW_COMPONENTS_WIDGETS_LIST_HPP +#define OPENMW_COMPONENTS_WIDGETS_LIST_HPP #include From 6afb0e43ef3b3781d852eeb1f16b8c9130a599f8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 01:41:33 +0200 Subject: [PATCH 0184/1812] Port FontLoader - requires MyGUI patch from https://github.com/MyGUI/mygui/pull/69 --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.hpp | 7 ++ components/fontloader/fontloader.cpp | 115 +++++++++++++++++-------- components/fontloader/fontloader.hpp | 28 +++++- 4 files changed, 111 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cac4939edf..ce9735f9d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -184,8 +184,8 @@ namespace MWGui MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Load fonts - Gui::FontLoader fontLoader (encoding); - fontLoader.loadAllFonts(exportFonts); + mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS())); + mFontLoader->loadAllFonts(exportFonts); //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 894c81ec91..16dab08a96 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -62,6 +62,11 @@ namespace osgMyGUI class Platform; } +namespace Gui +{ + class FontLoader; +} + namespace MWGui { class WindowBase; @@ -356,6 +361,8 @@ namespace MWGui private: osgMyGUI::Platform* mGuiPlatform; + std::auto_ptr mFontLoader; + bool mConsoleOnlyScripts; std::map mTrackedWindows; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 1b61aea90f..e579de18f8 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -2,8 +2,10 @@ #include -#include -#include +#include +#include + +#include #include #include @@ -11,9 +13,12 @@ #include #include +#include #include +#include + namespace { unsigned long utf8ToUnicode(const std::string& utf8) @@ -123,12 +128,12 @@ namespace return encoder.getUtf8(std::string(1, c)); } - void fail (Ogre::DataStreamPtr file, const std::string& fileName, const std::string& message) + void fail (Files::IStreamPtr file, const std::string& fileName, const std::string& message) { std::stringstream error; error << "Font loading error: " << message; error << "\n File: " << fileName; - error << "\n Offset: 0x" << std::hex << file->tell(); + error << "\n Offset: 0x" << std::hex << file->tellg(); throw std::runtime_error(error.str()); } @@ -137,7 +142,8 @@ namespace namespace Gui { - FontLoader::FontLoader(ToUTF8::FromType encoding) + FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs) + : mVFS(vfs) { if (encoding == ToUTF8::WINDOWS_1252) mEncoding = ToUTF8::CP437; @@ -145,19 +151,38 @@ namespace Gui mEncoding = encoding; } + FontLoader::~FontLoader() + { + for (std::vector::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + delete *it; + mTextures.clear(); + + for (std::vector::iterator it = mFonts.begin(); it != mFonts.end(); ++it) + MyGUI::ResourceManager::getInstance().removeByName((*it)->getResourceName()); + mFonts.clear(); + } + void FontLoader::loadAllFonts(bool exportToFile) { - /* - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Fonts/"; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) { - Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt"); - for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource) + const std::string& name = found->first; + if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) { - loadFont(*resource, exportToFile); + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".fnt") == 0) + loadFont(name, exportToFile); } + else + break; + ++found; } - */ } @@ -183,54 +208,62 @@ namespace Gui void FontLoader::loadFont(const std::string &fileName, bool exportToFile) { - Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName); + Files::IStreamPtr file = mVFS->get(fileName); float fontSize; - if (file->read(&fontSize, sizeof(fontSize)) < sizeof(fontSize)) + file->read((char*)&fontSize, sizeof(fontSize)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); int one; - if (file->read(&one, sizeof(int)) < sizeof(int)) + file->read((char*)&one, sizeof(one)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); if (one != 1) fail(file, fileName, "Unexpected value"); - if (file->read(&one, sizeof(int)) < sizeof(int)) + file->read((char*)&one, sizeof(one)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); if (one != 1) fail(file, fileName, "Unexpected value"); char name_[284]; - if (file->read(name_, sizeof(name_)) < sizeof(name_)) + file->read(name_, sizeof(name_)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); std::string name(name_); GlyphInfo data[256]; - if (file->read(data, sizeof(data)) < sizeof(data)) + file->read((char*)data, sizeof(data)); + if (!file->good()) fail(file, fileName, "File too small to be a valid font"); - file->close(); + + file.reset(); // Create the font texture std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex"; - Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename); + + Files::IStreamPtr bitmapFile = mVFS->get(bitmapFilename); int width, height; - if (bitmapFile->read(&width, sizeof(int)) < sizeof(int)) - fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + bitmapFile->read((char*)&width, sizeof(int)); + bitmapFile->read((char*)&height, sizeof(int)); - if (bitmapFile->read(&height, sizeof(int)) < sizeof(int)) + if (!bitmapFile->good()) fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); if (width <= 0 || height <= 0) fail(bitmapFile, bitmapFilename, "Width and height must be positive"); - std::vector textureData; + std::vector textureData; textureData.resize(width*height*4); - if (bitmapFile->read(&textureData[0], width*height*4) < (size_t)(width*height*4)) - fail(bitmapFile, bitmapFilename, "Bitmap does not contain the specified number of pixels"); - bitmapFile->close(); + bitmapFile->read(&textureData[0], width*height*4); + if (!bitmapFile->good()) + fail(bitmapFile, bitmapFilename, "File too small to be a valid bitmap"); + bitmapFile.reset(); std::string resourceName; if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) @@ -239,24 +272,31 @@ namespace Gui resourceName = "Century Gothic"; else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) resourceName = "Daedric"; - else - return; // no point in loading it, since there is no way of using additional fonts std::string textureName = name; - Ogre::Image image; - image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - width, height, 0, Ogre::PF_BYTE_RGBA); - texture->loadImage(image); + + osg::ref_ptr image = new osg::Image; + + unsigned char* bytes = (unsigned char*)calloc(width*height*4, sizeof(unsigned char)); + memcpy(bytes, &textureData[0], textureData.size()); + image->setImage(width, height, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(image); if (exportToFile) - image.save(resourceName + ".png"); + { + std::cout << "Writing " << resourceName + ".png" << std::endl; + osgDB::writeImageFile(*image, resourceName + ".png"); + } // Register the font with MyGUI MyGUI::ResourceManualFont* font = static_cast( MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + mFonts.push_back(font); + osgMyGUI::OSGTexture* myguiTex = new osgMyGUI::OSGTexture(texture); + mTextures.push_back(myguiTex); + font->setTexture(myguiTex); // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 MyGUI::xml::Document xmlDocument; @@ -390,6 +430,7 @@ namespace Gui if (exportToFile) { + std::cout << "Writing " << resourceName + ".xml" << std::endl; xmlDocument.createDeclaration(); xmlDocument.save(resourceName + ".xml"); } diff --git a/components/fontloader/fontloader.hpp b/components/fontloader/fontloader.hpp index a41506dbb4..b92815f136 100644 --- a/components/fontloader/fontloader.hpp +++ b/components/fontloader/fontloader.hpp @@ -1,26 +1,46 @@ -#ifndef MWGUI_FONTLOADER_H -#define MWGUI_FONTLOADER_H +#ifndef OPENMW_COMPONENTS_FONTLOADER_H +#define OPENMW_COMPONENTS_FONTLOADER_H #include +namespace VFS +{ + class Manager; +} + +namespace MyGUI +{ + class ITexture; + class ResourceManualFont; +} + namespace Gui { - /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre + /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and OSG + /// @note The FontLoader needs to remain in scope as long as you want to use the loaded fonts. class FontLoader { public: - FontLoader (ToUTF8::FromType encoding); + FontLoader (ToUTF8::FromType encoding, const VFS::Manager* vfs); + ~FontLoader(); /// @param exportToFile export the converted fonts (Images and XML with glyph metrics) to files? void loadAllFonts (bool exportToFile); private: ToUTF8::FromType mEncoding; + const VFS::Manager* mVFS; + + std::vector mTextures; + std::vector mFonts; /// @param exportToFile export the converted font (Image and XML with glyph metrics) to files? void loadFont (const std::string& fileName, bool exportToFile); + + FontLoader(const FontLoader&); + void operator=(const FontLoader&); }; } From 9f74be8fcb3308797a0ceed3e93db9990f890b48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 02:04:24 +0200 Subject: [PATCH 0185/1812] Add back the custom MyGUI log facility for utf8 paths on windows --- components/CMakeLists.txt | 2 +- .../myguiplatform/myguiloglistener.cpp | 6 +- components/myguiplatform/myguiloglistener.hpp | 69 +++++++++++++++++++ components/myguiplatform/myguiplatform.hpp | 22 ++++-- libs/openengine/CMakeLists.txt | 2 - libs/openengine/gui/loglistener.hpp | 37 ---------- 6 files changed, 88 insertions(+), 50 deletions(-) rename libs/openengine/gui/loglistener.cpp => components/myguiplatform/myguiloglistener.cpp (78%) create mode 100644 components/myguiplatform/myguiloglistener.hpp delete mode 100644 libs/openengine/gui/loglistener.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 563a772686..ac7eef16af 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -119,7 +119,7 @@ add_component_dir (ogreinit ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener ) add_component_dir (widgets diff --git a/libs/openengine/gui/loglistener.cpp b/components/myguiplatform/myguiloglistener.cpp similarity index 78% rename from libs/openengine/gui/loglistener.cpp rename to components/myguiplatform/myguiloglistener.cpp index da36b90a2f..b36e0d852c 100644 --- a/libs/openengine/gui/loglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -1,11 +1,11 @@ -#include "loglistener.hpp" +#include "myguiloglistener.hpp" #include #include #include -namespace MyGUI +namespace osgMyGUI { void CustomLogListener::open() { @@ -24,7 +24,7 @@ namespace MyGUI mStream.flush(); } - void CustomLogListener::log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) + void CustomLogListener::log(const std::string& _section, MyGUI::LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) { if (mStream.is_open()) { diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp new file mode 100644 index 0000000000..3da4d3c525 --- /dev/null +++ b/components/myguiplatform/myguiloglistener.hpp @@ -0,0 +1,69 @@ +#ifndef OPENENGINE_MYGUI_LOGLISTENER_H +#define OPENENGINE_MYGUI_LOGLISTENER_H + +#include +#include + +#include +#include +#include +#include + +namespace osgMyGUI +{ + + /// \brief Custom MyGUI::ILogListener interface implementation + /// being able to portably handle UTF-8 encoded path. + /// \todo try patching MyGUI to make this easier + class CustomLogListener : public MyGUI::ILogListener + { + public: + CustomLogListener(const std::string &name) + : mFileName(name) + {} + + ~CustomLogListener() {} + + virtual void open(); + virtual void close(); + virtual void flush(); + + virtual void log(const std::string& _section, MyGUI::LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line); + + const std::string& getFileName() const { return mFileName; } + + private: + boost::filesystem::ofstream mStream; + std::string mFileName; + }; + + /// \brief Helper class holding data that required during + /// MyGUI log creation + class LogFacility + { + MyGUI::ConsoleLogListener mConsole; + CustomLogListener mFile; + MyGUI::LevelLogFilter mFilter; + MyGUI::LogSource mSource; + + public: + + LogFacility(const std::string &output, bool console) + : mFile(output) + { + mConsole.setEnabled(console); + mFilter.setLoggingLevel(MyGUI::LogLevel::Info); + + mSource.addLogListener(&mFile); + mSource.addLogListener(&mConsole); + mSource.setLogFilter(&mFilter); + + mSource.open(); + } + + MyGUI::LogSource *getSource() { return &mSource; } + }; + +} + +#endif diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 5079b23b0a..c0c9e0ce4f 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -6,6 +6,7 @@ #include "myguirendermanager.hpp" #include "myguidatamanager.hpp" +#include "myguiloglistener.hpp" namespace osgMyGUI { @@ -13,10 +14,11 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) : - mLogManager(nullptr), - mRenderManager(nullptr), - mDataManager(nullptr) + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) + : mRenderManager(nullptr) + , mDataManager(nullptr) + , mLogManager(nullptr) + , mLogFacility(nullptr) { mLogManager = new MyGUI::LogManager(); mRenderManager = new RenderManager(viewer, guiRoot, textureManager); @@ -31,12 +33,17 @@ namespace osgMyGUI mDataManager = nullptr; delete mLogManager; mLogManager = nullptr; + delete mLogFacility; + mLogFacility = nullptr; } void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") { - if (!_logName.empty()) - MyGUI::LogManager::getInstance().createDefaultSource(_logName); + if (!_logName.empty() && !mLogFacility) + { + mLogFacility = new LogFacility(_logName, false); + mLogManager->addLogSource(mLogFacility->getSource()); + } mDataManager->setResourcePath(resourcePath); @@ -46,7 +53,7 @@ namespace osgMyGUI void shutdown() { - //mRenderManager->shutdown(); + mRenderManager->shutdown(); mDataManager->shutdown(); } @@ -64,6 +71,7 @@ namespace osgMyGUI RenderManager* mRenderManager; DataManager* mDataManager; MyGUI::LogManager* mLogManager; + LogFacility* mLogFacility; }; } diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 07ac60bc6b..fa3df08208 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,6 +1,4 @@ set(OENGINE_GUI - gui/loglistener.cpp - #gui/manager.cpp gui/layout.cpp ) diff --git a/libs/openengine/gui/loglistener.hpp b/libs/openengine/gui/loglistener.hpp deleted file mode 100644 index 47978ba447..0000000000 --- a/libs/openengine/gui/loglistener.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef OPENENGINE_MYGUI_LOGLISTENER_H -#define OPENENGINE_MYGUI_LOGLISTENER_H - -#include -#include - -#include - -namespace MyGUI -{ - /// \brief Custom MyGUI::ILogListener interface implementation - /// being able to portably handle UTF-8 encoded path. - class CustomLogListener : public ILogListener - { - public: - CustomLogListener(const std::string &name) - : mFileName(name) - {} - - ~CustomLogListener() {} - - virtual void open(); - virtual void close(); - virtual void flush(); - - virtual void log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line); - - const std::string& getFileName() const { return mFileName; } - - private: - boost::filesystem::ofstream mStream; - std::string mFileName; - }; - -} - -#endif From 223e3a53f58d92e69d56a6d2b29196e84fcdad1a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 02:09:57 +0200 Subject: [PATCH 0186/1812] Move OEngine::Gui::Layout to MWGui --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 12 +++--------- apps/openmw/mwgui/hud.hpp | 2 +- .../openengine/gui => apps/openmw/mwgui}/layout.cpp | 5 +---- .../openengine/gui => apps/openmw/mwgui}/layout.hpp | 9 ++++----- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/mainmenu.hpp | 4 ++-- apps/openmw/mwgui/messagebox.hpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowbase.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- libs/openengine/CMakeLists.txt | 6 +----- 13 files changed, 26 insertions(+), 40 deletions(-) rename {libs/openengine/gui => apps/openmw/mwgui}/layout.cpp (98%) rename {libs/openengine/gui => apps/openmw/mwgui}/layout.hpp (94%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f352547e0c..f049f03870 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwrender # ) add_openmw_dir (mwgui - textinput widgets race class birth review windowmanagerimp console dialogue + layout textinput widgets race class birth review windowmanagerimp console dialogue windowbase statswindow messagebox journalwindow charactercreation mapwindow windowpinnablebase tooltips scrollwindow bookwindow formatting inventorywindow container hud countdialog tradewindow settingswindow diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d5960779c9..743577812a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -26,14 +26,6 @@ namespace MyGUI class UString; } -namespace OEngine -{ - namespace GUI - { - class Layout; - } -} - namespace ESM { struct Class; @@ -58,6 +50,8 @@ namespace MWWorld namespace MWGui { + class Layout; + class Console; class SpellWindow; class TradeWindow; @@ -241,7 +235,7 @@ namespace MWBase virtual void addVisitedLocation(const std::string& name, int x, int y) = 0; /// Hides dialog and schedules dialog to be deleted. - virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; + virtual void removeDialog(MWGui::Layout* dialog) = 0; ///Gracefully attempts to exit the topmost GUI mode /** No guarentee of actually closing the window **/ diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 263c087740..e717e094eb 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,7 +16,7 @@ namespace MWGui class SpellIcons; class ItemWidget; - class HUD : public OEngine::GUI::Layout, public LocalMapBase + class HUD : public Layout, public LocalMapBase { public: HUD(CustomMarkerCollection& customMarkers, int fpsLevel, DragAndDrop* dragAndDrop); diff --git a/libs/openengine/gui/layout.cpp b/apps/openmw/mwgui/layout.cpp similarity index 98% rename from libs/openengine/gui/layout.cpp rename to apps/openmw/mwgui/layout.cpp index cd94387f95..6bdb1a9f4d 100644 --- a/libs/openengine/gui/layout.cpp +++ b/apps/openmw/mwgui/layout.cpp @@ -6,9 +6,7 @@ #include #include -namespace OEngine -{ -namespace GUI +namespace MWGui { void Layout::initialise(const std::string& _layout, MyGUI::Widget* _parent) { @@ -78,4 +76,3 @@ namespace GUI } } -} diff --git a/libs/openengine/gui/layout.hpp b/apps/openmw/mwgui/layout.hpp similarity index 94% rename from libs/openengine/gui/layout.hpp rename to apps/openmw/mwgui/layout.hpp index b0515ccbb0..0e7cf3faa7 100644 --- a/libs/openengine/gui/layout.hpp +++ b/apps/openmw/mwgui/layout.hpp @@ -1,12 +1,11 @@ -#ifndef OENGINE_MYGUI_LAYOUT_H -#define OENGINE_MYGUI_LAYOUT_H +#ifndef OPENMW_MWGUI_LAYOUT_H +#define OPENMW_MWGUI_LAYOUT_H #include #include #include -namespace OEngine { -namespace GUI +namespace MWGui { /** The Layout class is an utility class used to load MyGUI layouts from xml files, and to manipulate member widgets. @@ -60,5 +59,5 @@ namespace GUI std::string mLayoutName; MyGUI::VectorWidgetPtr mListWindowRoot; }; -}} +} #endif diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 0a8667d808..d563eacc80 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -30,7 +30,7 @@ namespace MWGui { MainMenu::MainMenu(int w, int h) - : OEngine::GUI::Layout("openmw_mainmenu.layout") + : Layout("openmw_mainmenu.layout") , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) , mBackground(NULL) @@ -80,7 +80,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - OEngine::GUI::Layout::setVisible (visible); + Layout::setVisible (visible); } void MainMenu::onNewGameConfirmed() diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index cd2050d0ff..9089ed1d59 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_GAME_MWGUI_MAINMENU_H #define OPENMW_GAME_MWGUI_MAINMENU_H -#include +#include "layout.hpp" namespace Gui { @@ -15,7 +15,7 @@ namespace MWGui class SaveGameDialog; class VideoWidget; - class MainMenu : public OEngine::GUI::Layout + class MainMenu : public Layout { int mWidth; int mHeight; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 48a92c844b..59d1a0b064 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -51,7 +51,7 @@ namespace MWGui int mLastButtonPressed; }; - class MessageBox : public OEngine::GUI::Layout + class MessageBox : public Layout { public: MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 71b4a560f5..0ddd313dfd 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -2,7 +2,7 @@ #ifndef MWGUI_TOOLTIPS_H #define MWGUI_TOOLTIPS_H -#include +#include "layout.hpp" #include "../mwworld/ptr.hpp" #include "widgets.hpp" @@ -45,7 +45,7 @@ namespace MWGui bool wordWrap; }; - class ToolTips : public OEngine::GUI::Layout + class ToolTips : public Layout { public: ToolTips(); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index bf74c8bf0f..195b6c384d 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WINDOW_BASE_H #define MWGUI_WINDOW_BASE_H -#include +#include "layout.hpp" namespace MWBase { @@ -13,7 +13,7 @@ namespace MWGui class WindowManager; class DragAndDrop; - class WindowBase: public OEngine::GUI::Layout + class WindowBase: public Layout { public: WindowBase(const std::string& parLayout); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ce9735f9d8..cf7475d5c0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -422,7 +422,7 @@ namespace MWGui // Delete any dialogs which are no longer in use if (!mGarbageDialogs.empty()) { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) { delete *it; } @@ -722,7 +722,7 @@ namespace MWGui mStatsWindow->updateSkillArea(); } - void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) + void WindowManager::removeDialog(Layout*dialog) { if (!dialog) return; @@ -1566,7 +1566,7 @@ namespace MWGui return mCursorVisible; } - void WindowManager::trackWindow(OEngine::GUI::Layout *layout, const std::string &name) + void WindowManager::trackWindow(Layout *layout, const std::string &name) { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width), diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 16dab08a96..ec99364c7b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -242,7 +242,7 @@ namespace MWGui virtual void addVisitedLocation(const std::string& name, int x, int y); ///Hides dialog and schedules dialog to be deleted. - virtual void removeDialog(OEngine::GUI::Layout* dialog); + virtual void removeDialog(Layout* dialog); ///Gracefully attempts to exit the topmost GUI mode virtual void exitCurrentGuiMode(); @@ -366,7 +366,7 @@ namespace MWGui bool mConsoleOnlyScripts; std::map mTrackedWindows; - void trackWindow(OEngine::GUI::Layout* layout, const std::string& name); + void trackWindow(Layout* layout, const std::string& name); void onWindowChangeCoord(MyGUI::Window* _sender); std::string mSelectedSpell; @@ -448,7 +448,7 @@ namespace MWGui SFO::CursorManager* mCursorManager; - std::vector mGarbageDialogs; + std::vector mGarbageDialogs; void cleanupGarbage(); GuiWindow mShown; // Currently shown windows in inventory mode diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index fa3df08208..b135d0fc6a 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -1,7 +1,3 @@ -set(OENGINE_GUI - gui/layout.cpp -) - set(OENGINE_BULLET bullet/BtOgre.cpp bullet/BtOgreExtras.h @@ -15,7 +11,7 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_ALL ${OENGINE_GUI} ${OENGINE_BULLET}) +set(OENGINE_ALL ${OENGINE_BULLET}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) From b0804734e577d58c7b514b9df8893d2d187e6b7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 03:03:44 +0200 Subject: [PATCH 0187/1812] Port VideoWidget --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/videowidget.cpp | 41 ++++++++++++++----- apps/openmw/mwgui/videowidget.hpp | 16 ++++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 37 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 8 ++-- 6 files changed, 65 insertions(+), 40 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 488c945015..0abb43cfde 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -468,7 +468,7 @@ void OMW::Engine::go() mViewer->realize(); osg::Timer frameTimer; - while (!mViewer->done()) + while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 28771f14fd..13fabfeed5 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,51 +1,70 @@ #include "videowidget.hpp" -//#include +#include #include -//#include "../mwsound/movieaudiofactory.hpp" +#include + +#include +#include + +#include "../mwsound/movieaudiofactory.hpp" namespace MWGui { VideoWidget::VideoWidget() + : mVFS(NULL) { - //mPlayer.reset(new Video::VideoPlayer()); + mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } +void VideoWidget::setVFS(const VFS::Manager *vfs) +{ + mVFS = vfs; +} + void VideoWidget::playVideo(const std::string &video) { - //mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - //mPlayer->playVideo(video); + mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - //setImageTexture(mPlayer->getTextureName()); + mPlayer->playVideo(mVFS->get(video)); + + osg::ref_ptr texture = mPlayer->getVideoTexture(); + if (!texture) + return; + + mTexture.reset(new osgMyGUI::OSGTexture(texture)); + + setRenderItemTexture(mTexture.get()); + getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } int VideoWidget::getVideoWidth() { - return 0;//mPlayer->getVideoWidth(); + return mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return 0;//mPlayer->getVideoHeight(); + return mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return 0;//mPlayer->update(); + return mPlayer->update(); } void VideoWidget::stop() { - //mPlayer->close(); + mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return 0;//mPlayer->hasAudioStream(); + return mPlayer->hasAudioStream(); } void VideoWidget::autoResize(bool stretch) diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 75aa6e98aa..6b265628e6 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -1,26 +1,34 @@ #ifndef OPENMW_MWGUI_VIDEOWIDGET_H #define OPENMW_MWGUI_VIDEOWIDGET_H -#include +#include namespace Video { class VideoPlayer; } +namespace VFS +{ + class Manager; +} + namespace MWGui { /** * Widget that plays a video. */ - class VideoWidget : public MyGUI::ImageBox + class VideoWidget : public MyGUI::Widget { public: MYGUI_RTTI_DERIVED(VideoWidget) VideoWidget(); + /// Set the VFS (virtual file system) to find the videos on. + void setVFS(const VFS::Manager* vfs); + void playVideo (const std::string& video); int getVideoWidth(); @@ -42,7 +50,9 @@ namespace MWGui void autoResize (bool stretch); private: - //std::auto_ptr mPlayer; + const VFS::Manager* mVFS; + std::auto_ptr mTexture; + std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf7475d5c0..7ce8d62001 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -3,9 +3,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -38,6 +36,8 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwrender/vismask.hpp" + #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" @@ -102,7 +102,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) - : mConsoleOnlyScripts(consoleOnlyScripts) + : mViewer(viewer) + , mConsoleOnlyScripts(consoleOnlyScripts) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -236,6 +237,7 @@ namespace MWGui mVideoWidget = mVideoBackground->createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default); mVideoWidget->setNeedMouseFocus(true); mVideoWidget->setNeedKeyFocus(true); + mVideoWidget->setVFS(resourceSystem->getVFS()); // Removes default MyGUI system clipboard implementation, which supports windows only MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); @@ -1127,8 +1129,8 @@ namespace MWGui mGuiModes.push_back(mode); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1683,7 +1685,6 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { - return; mVideoWidget->playVideo("video\\" + name); mVideoWidget->eventKeyButtonPressed.clear(); @@ -1695,16 +1696,10 @@ namespace MWGui } // Turn off all rendering except for the GUI - /* - mRendering->getScene()->clearSpecialCaseRenderQueues(); - // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work? - for(int i = 0;i < Ogre::RENDER_QUEUE_MAX;++i) - { - if(i > 0 && i < 96) - mRendering->getScene()->addSpecialCaseRenderQueue(i); - } - mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - */ + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); @@ -1722,9 +1717,9 @@ namespace MWGui while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - MWBase::Environment::get().getInputManager()->update(0, true, false); + //MWBase::Environment::get().getInputManager()->update(0, true, false); - //mRendering->getWindow()->update(); + mViewer->frame(); } mVideoWidget->stop(); @@ -1733,8 +1728,8 @@ namespace MWGui setCursorVisible(cursorWasVisible); // Restore normal rendering - //mRendering->getScene()->clearSpecialCaseRenderQueues(); - //mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); mVideoBackground->setVisible(false); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ec99364c7b..3a6f3b0242 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -360,6 +360,7 @@ namespace MWGui private: osgMyGUI::Platform* mGuiPlatform; + osgViewer::Viewer* mViewer; std::auto_ptr mFontLoader; diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 8dedeaf648..1336e45a36 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -65,16 +65,16 @@ osg::ref_ptr VideoPlayer::getVideoTexture() int VideoPlayer::getVideoWidth() { int width=0; - if (mState && mState->mTexture.get()) - width = mState->mTexture->getTextureWidth(); + if (mState && mState->mTexture.get() && mState->mTexture->getImage()) + width = mState->mTexture->getImage()->s(); return width; } int VideoPlayer::getVideoHeight() { int height=0; - if (mState && mState->mTexture.get()) - height = mState->mTexture->getTextureHeight(); + if (mState && mState->mTexture.get() && mState->mTexture->getImage()) + height = mState->mTexture->getImage()->t(); return height; } From bd8f0248f00c537bca974f3998eae44fafb30b56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:21:50 +0200 Subject: [PATCH 0188/1812] Player rendering --- .../mwmechanics/mechanicsmanagerimp.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/objects.cpp | 12 -------- apps/openmw/mwrender/renderingmanager.cpp | 29 +++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 11 ++++++- apps/openmw/mwworld/worldimp.cpp | 15 ++++++---- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7e6e296707..077f67b5ef 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1318,6 +1318,8 @@ namespace MWMechanics bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { + return false; + if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 245095492b..1f749ab4e1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -866,6 +866,8 @@ namespace MWRender NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); + + mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f77865634b..a06b751cc7 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -10,9 +10,6 @@ #include #include -// light -#include - #include #include @@ -112,9 +109,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - if (!allowLight) { RemoveParticlesVisitor visitor; @@ -137,9 +131,6 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -149,9 +140,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - if (anim->getObjectRoot()) - anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); - mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8689935d0c..d07c98ed7d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -23,6 +23,7 @@ #include "sky.hpp" #include "effectmanager.hpp" +#include "npcanimation.hpp" #include "vismask.hpp" namespace MWRender @@ -82,6 +83,7 @@ namespace MWRender , mResourceSystem(resourceSystem) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; + mLightRoot = lightRoot; lightRoot->setStartLight(1); mRootNode->addChild(lightRoot); @@ -258,4 +260,31 @@ namespace MWRender return mObjects->getAnimation(ptr); } + MWRender::Animation* RenderingManager::getPlayerAnimation() + { + return mPlayerAnimation.get(); + } + + void RenderingManager::setupPlayer(const MWWorld::Ptr &player) + { + if (!mPlayerNode) + { + mPlayerNode = new osg::PositionAttitudeTransform; + mLightRoot->addChild(mPlayerNode); + } + + player.getRefData().setBaseNode(mPlayerNode); + + //attachCameraTo(player); + } + + void RenderingManager::renderPlayer(const MWWorld::Ptr &player) + { + mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); + + //mCamera->setAnimation(mPlayerAnimation); + //mWater->removeEmitter(ptr); + //mWater->addEmitter(ptr); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 005100701e..71c70b9907 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -11,6 +11,7 @@ namespace osg { class Group; + class PositionAttitudeTransform; } namespace Resource @@ -35,6 +36,7 @@ namespace MWRender class EffectManager; class SkyManager; + class NpcAnimation; class RenderingManager : public MWRender::RenderingInterface { @@ -78,11 +80,16 @@ namespace MWRender void update(float dt, bool paused); - MWRender::Animation* getAnimation(const MWWorld::Ptr& ptr); + Animation* getAnimation(const MWWorld::Ptr& ptr); + Animation* getPlayerAnimation(); + + void setupPlayer(const MWWorld::Ptr& player); + void renderPlayer(const MWWorld::Ptr& player); private: osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; + osg::ref_ptr mLightRoot; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mSunLight; @@ -90,6 +97,8 @@ namespace MWRender std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; + std::auto_ptr mPlayerAnimation; + osg::ref_ptr mPlayerNode; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4e737fc07c..8cb9f4d509 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1563,7 +1563,8 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - //mRendering->renderPlayer(mPlayer->getPlayer()); + mRendering->renderPlayer(getPlayerPtr()); + scaleObject(getPlayerPtr(), 1.f); // apply race height } return ret; } @@ -2120,18 +2121,20 @@ namespace MWWorld mPlayer->set(player); } - //Ptr ptr = mPlayer->getPlayer(); - //mRendering->setupPlayer(ptr); + Ptr ptr = mPlayer->getPlayer(); + mRendering->setupPlayer(ptr); } void World::renderPlayer() { - //mRendering->renderPlayer(mPlayer->getPlayer()); + mRendering->renderPlayer(getPlayerPtr()); + + scaleObject(getPlayerPtr(), 1.f); // apply race height // At this point the Animation object is live, and the CharacterController associated with it must be created. // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate // so we should make sure not to use a "stale" controller for that. - MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); + MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); //model = Misc::ResourceHelpers::correctActorModelPath(model); @@ -2163,6 +2166,8 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { + if (ptr == getPlayerPtr()) + return mRendering->getPlayerAnimation(); return mRendering->getAnimation(ptr); } From 82c4d01b377d0d21ac5923d93fd9126dcbef9c17 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:37:24 +0200 Subject: [PATCH 0189/1812] Add back resource handling workarounds to the gui code --- apps/openmw/mwbase/windowmanager.hpp | 5 +++++ apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/formatting.cpp | 6 +++++- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/itemwidget.cpp | 6 +++++- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++-- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 20 +++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++++ components/misc/resourcehelpers.hpp | 5 ++++- 13 files changed, 53 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 743577812a..59407fbeb0 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -353,6 +353,11 @@ namespace MWBase virtual void cycleSpell(bool next) = 0; /// Cycle to next or previous weapon virtual void cycleWeapon(bool next) = 0; + + // In WindowManager for now since there isn't a VFS singleton + virtual std::string correctIconPath(const std::string& path) = 0; + virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; + virtual std::string correctTexturePath(const std::string& path) = 0; }; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 475428f335..dd20999e05 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -183,7 +183,7 @@ namespace MWGui const ESM::BirthSign *birth = store.get().find(mCurrentBirthId); - //mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(birth->mTexture)); + mBirthImage->setImageTexture(MWBase::Environment::get().getWindowManager()->correctTexturePath(birth->mTexture)); std::vector abilities, powers, spells; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index d96255c859..461d8e32e1 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,6 +6,10 @@ #include #include +// correctBookartPath +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + #include #include @@ -463,7 +467,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image;// = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); + std::string image = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 2323d39e71..9c8fa48a1d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -448,7 +448,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - //icon = Misc::ResourceHelpers::correctIconPath(icon); + icon = MWBase::Environment::get().getWindowManager()->correctIconPath(icon); mSpellImage->setItem(MWWorld::Ptr()); mSpellImage->setIcon(icon); diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 1da2ab8797..645a722774 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -6,6 +6,10 @@ #include +// correctIconPath +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/class.hpp" namespace @@ -77,7 +81,7 @@ namespace MWGui void ItemWidget::setIcon(const MWWorld::Ptr &ptr) { - //setIcon(Misc::ResourceHelpers::correctIconPath(ptr.getClass().getInventoryIcon(ptr))); + setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(ptr.getClass().getInventoryIcon(ptr))); } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3fddbc84b5..0c462c67d0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -245,7 +245,7 @@ namespace MWGui std::string path = effect->mIcon; int slashPos = path.rfind('\\'); path.insert(slashPos+1, "b_"); - //path = Misc::ResourceHelpers::correctIconPath(path); + path = MWBase::Environment::get().getWindowManager()->correctIconPath(path); button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); button->setIcon(path); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 80806941c1..e0a1493c2a 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -180,7 +180,7 @@ namespace MWGui void EditEffectDialog::setMagicEffect (const ESM::MagicEffect *effect) { - //mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + mEffectImage->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); mEffectName->setCaptionWithReplacing("#{"+ESM::MagicEffect::effectIdToString (effect->mIndex)+"}"); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 8770bab382..c263166262 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -145,7 +145,7 @@ namespace MWGui ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); mWidgetMap[it->first] = image; - //image->setImageTexture(Misc::ResourceHelpers::correctIconPath(effect->mIcon)); + image->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); std::string name = ESM::MagicEffect::effectIdToString (it->first); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8b63ab5413..f91c173707 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -388,7 +388,7 @@ namespace MWGui const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); - std::string realImage;// = Misc::ResourceHelpers::correctIconPath(image); + std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); @@ -686,7 +686,7 @@ namespace MWGui widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - widget->setUserString("ImageTexture_BirthSignImage", "");//Misc::ResourceHelpers::correctTexturePath(sign->mTexture)); + widget->setUserString("ImageTexture_BirthSignImage", MWBase::Environment::get().getWindowManager()->correctTexturePath(sign->mTexture)); std::string text; text += sign->mName; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 888955391d..996cc528dd 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -474,7 +474,7 @@ namespace MWGui mTextWidget->setCaptionWithReplacing(spellLine); mRequestedWidth = mTextWidget->getTextSize().width + 24; - //mImageWidget->setImageTexture(Misc::ResourceHelpers::correctIconPath(magicEffect->mIcon)); + mImageWidget->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(magicEffect->mIcon)); } MWSpellEffect::~MWSpellEffect() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7ce8d62001..096838f81a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" @@ -102,7 +104,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) - : mViewer(viewer) + : mResourceSystem(resourceSystem) + , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) , mHud(NULL) , mMap(NULL) @@ -1917,4 +1920,19 @@ namespace MWGui mScrollWindow->open(item, showTakeButton); } + std::string WindowManager::correctIconPath(const std::string& path) + { + return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); + } + + std::string WindowManager::correctBookartPath(const std::string& path, int width, int height) + { + return Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + } + + std::string WindowManager::correctTexturePath(const std::string& path) + { + return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a6f3b0242..765a181562 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -358,7 +358,14 @@ namespace MWGui /// Cycle to next or previous weapon virtual void cycleWeapon(bool next); + // In WindowManager for now since there isn't a VFS singleton + virtual std::string correctIconPath(const std::string& path); + virtual std::string correctBookartPath(const std::string& path, int width, int height); + virtual std::string correctTexturePath(const std::string& path); + private: + Resource::ResourceSystem* mResourceSystem; + osgMyGUI::Platform* mGuiPlatform; osgViewer::Viewer* mViewer; diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 1763f77773..fa50cce228 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -10,6 +10,9 @@ namespace VFS namespace Misc { + // Workarounds for messy resource handling in vanilla morrowind + // The below functions are provided on a opt-in basis, instead of built into the VFS, + // so we have the opportunity to use proper resource handling for content created in OpenMW-CS. namespace ResourceHelpers { bool changeExtensionToDds(std::string &path); @@ -18,7 +21,7 @@ namespace Misc std::string correctIconPath(const std::string &resPath, const VFS::Manager* vfs); std::string correctBookartPath(const std::string &resPath, const VFS::Manager* vfs); std::string correctBookartPath(const std::string &resPath, int width, int height, const VFS::Manager* vfs); - /// Uses "xfoo.nif" instead of "foo.nif" if available + /// Use "xfoo.nif" instead of "foo.nif" if available std::string correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs); } } From a592c1a1c2319574159686bc314b86aea0bb6a99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 18:42:44 +0200 Subject: [PATCH 0190/1812] Remove unused resources --- files/CMakeLists.txt | 49 -- files/materials/atmosphere.shader | 39 -- files/materials/atmosphere.shaderset | 15 - files/materials/clouds.shader | 55 --- files/materials/clouds.shaderset | 15 - files/materials/core.h | 181 -------- files/materials/moon.shader | 51 --- files/materials/moon.shaderset | 15 - files/materials/mygui.mat | 25 -- files/materials/mygui.shader | 45 -- files/materials/mygui.shaderset | 15 - files/materials/objects.mat | 147 ------ files/materials/objects.shader | 591 ------------------------- files/materials/objects.shaderset | 15 - files/materials/openmw.configuration | 20 - files/materials/quad.mat | 22 - files/materials/quad.shader | 25 -- files/materials/quad.shaderset | 15 - files/materials/ripples.particle | 26 -- files/materials/selection.mat | 9 - files/materials/selection.shader | 24 - files/materials/selection.shaderset | 15 - files/materials/shadowcaster.mat | 35 -- files/materials/shadowcaster.shader | 55 --- files/materials/shadowcaster.shaderset | 15 - files/materials/shadows.h | 51 --- files/materials/sky.mat | 140 ------ files/materials/stars.shader | 48 -- files/materials/stars.shaderset | 15 - files/materials/sun.shader | 41 -- files/materials/sun.shaderset | 15 - files/materials/terrain.shader | 507 --------------------- files/materials/terrain.shaderset | 15 - files/materials/underwater.h | 121 ----- files/materials/water.mat | 101 ----- files/materials/water.shader | 354 --------------- files/materials/water.shaderset | 15 - files/water/circle.png | Bin 753 -> 0 bytes files/water/water_nm.png | Bin 24405 -> 0 bytes 39 files changed, 2942 deletions(-) delete mode 100644 files/materials/atmosphere.shader delete mode 100644 files/materials/atmosphere.shaderset delete mode 100644 files/materials/clouds.shader delete mode 100644 files/materials/clouds.shaderset delete mode 100644 files/materials/core.h delete mode 100644 files/materials/moon.shader delete mode 100644 files/materials/moon.shaderset delete mode 100644 files/materials/mygui.mat delete mode 100644 files/materials/mygui.shader delete mode 100644 files/materials/mygui.shaderset delete mode 100644 files/materials/objects.mat delete mode 100644 files/materials/objects.shader delete mode 100644 files/materials/objects.shaderset delete mode 100644 files/materials/openmw.configuration delete mode 100644 files/materials/quad.mat delete mode 100644 files/materials/quad.shader delete mode 100644 files/materials/quad.shaderset delete mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/selection.mat delete mode 100644 files/materials/selection.shader delete mode 100644 files/materials/selection.shaderset delete mode 100644 files/materials/shadowcaster.mat delete mode 100644 files/materials/shadowcaster.shader delete mode 100644 files/materials/shadowcaster.shaderset delete mode 100644 files/materials/shadows.h delete mode 100644 files/materials/sky.mat delete mode 100644 files/materials/stars.shader delete mode 100644 files/materials/stars.shaderset delete mode 100644 files/materials/sun.shader delete mode 100644 files/materials/sun.shaderset delete mode 100644 files/materials/terrain.shader delete mode 100644 files/materials/terrain.shaderset delete mode 100644 files/materials/underwater.h delete mode 100644 files/materials/water.mat delete mode 100644 files/materials/water.shader delete mode 100644 files/materials/water.shaderset delete mode 100644 files/water/circle.png delete mode 100644 files/water/water_nm.png diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index da3451d93e..e69de29bb2 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,49 +0,0 @@ -project(resources) - -set(WATER_FILES - water_nm.png - circle.png -) - -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 - 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 - selection.mat - selection.shader - selection.shaderset - mygui.mat - mygui.shader - mygui.shaderset - ripples.particle -) - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader deleted file mode 100644 index 3eaa73b1ca..0000000000 --- a/files/materials/atmosphere.shader +++ /dev/null @@ -1,39 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) - shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - - shOutput(float, alphaFade) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shInputPosition)); - alphaFade = shInputPosition.z < 150.0 ? 0.0 : 1.0; - } - -#else - - SH_BEGIN_PROGRAM - shInput(float, alphaFade) - shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) - shUniform(float4, horizonColour) @shSharedParameter(horizonColour, horizonColour) - - SH_START_PROGRAM - { - shOutputColour(0) = alphaFade * atmosphereColour + (1.0 - alphaFade) * horizonColour; - } - -#endif diff --git a/files/materials/atmosphere.shaderset b/files/materials/atmosphere.shaderset deleted file mode 100644 index 54108dbba6..0000000000 --- a/files/materials/atmosphere.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 5902d2fdcc..0000000000 --- a/files/materials/clouds.shader +++ /dev/null @@ -1,55 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldview) @shAutoConstant(worldview, worldview_matrix) - shUniform(float4x4, proj) @shAutoConstant(proj, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - shOutput(float, alphaFade) - - SH_START_PROGRAM - { - float4x4 worldviewFixed = worldview; - -#if !SH_GLSL && !SH_GLSLES - worldviewFixed[0][3] = 0.0; - worldviewFixed[1][3] = 0.0; - worldviewFixed[2][3] = 0.0; -#else - worldviewFixed[3][0] = 0.0; - worldviewFixed[3][1] = 0.0; - worldviewFixed[3][2] = 0.0; -#endif - - shOutputPosition = shMatrixMult(proj, shMatrixMult(worldviewFixed, shInputPosition)); - UV = uv0; - alphaFade = (shInputPosition.z <= 200.0) ? ((shInputPosition.z <= 100.0) ? 0.0 : 0.25) : 1.0; - } - -#else - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shInput(float, alphaFade) - - 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.0-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; - - shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); - } - -#endif diff --git a/files/materials/clouds.shaderset b/files/materials/clouds.shaderset deleted file mode 100644 index 5fffb5658d..0000000000 --- a/files/materials/clouds.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index e6cde4bdae..0000000000 --- a/files/materials/core.h +++ /dev/null @@ -1,181 +0,0 @@ -#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 - - #define shFract(val) frac(val) - - #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 || SH_GLSLES == 1 - - #define shFract(val) fract(val) - -#if SH_GLSLES == 1 - @version 100 -#else - @version 120 -#endif - -#if SH_GLSLES == 1 -precision mediump int; -precision mediump float; -#endif - - #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 deleted file mode 100644 index 151b94180f..0000000000 --- a/files/materials/moon.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, world) @shAutoConstant(world, world_matrix) - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) -shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); - UV = uv0; - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shSampler2D(alphaMap) - shInput(float2, UV) - 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 phaseTex = shSample(diffuseMap, UV); - float4 fullCircleTex = shSample(alphaMap, UV); - - shOutputColour(0).a = max(phaseTex.a, fullCircleTex.a) * materialDiffuse.a; - - shOutputColour(0).xyz = fullCircleTex.xyz * atmosphereColour.xyz; - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, phaseTex.xyz, phaseTex.a); - shOutputColour(0).xyz *= materialEmissive.xyz; - } - -#endif diff --git a/files/materials/moon.shaderset b/files/materials/moon.shaderset deleted file mode 100644 index 659481a961..0000000000 --- a/files/materials/moon.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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/mygui.mat b/files/materials/mygui.mat deleted file mode 100644 index 78cba3f897..0000000000 --- a/files/materials/mygui.mat +++ /dev/null @@ -1,25 +0,0 @@ -material MyGUI/NoTexture -{ - pass - { - vertex_program mygui_vertex - fragment_program mygui_fragment - shader_properties - { - has_texture false - } - } -} - -material MyGUI/OneTexture -{ - pass - { - vertex_program mygui_vertex - fragment_program mygui_fragment - shader_properties - { - has_texture true - } - } -} diff --git a/files/materials/mygui.shader b/files/materials/mygui.shader deleted file mode 100644 index 4d12eba90e..0000000000 --- a/files/materials/mygui.shader +++ /dev/null @@ -1,45 +0,0 @@ -#include "core.h" - -#define TEXTURE @shPropertyBool(has_texture) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM -#if TEXTURE - shVertexInput(float2, uv0) - shOutput(float2, UV) -#endif - shColourInput(float4) - shOutput(float4, colourPassthrough) - - SH_START_PROGRAM - { - shOutputPosition = float4(shInputPosition.xyz, 1.0); -#if TEXTURE - UV.xy = uv0; -#endif - colourPassthrough = colour; - } - -#else - - - SH_BEGIN_PROGRAM - -#if TEXTURE - shSampler2D(diffuseMap) - shInput(float2, UV) -#endif - - shInput(float4, colourPassthrough) - - SH_START_PROGRAM - { -#if TEXTURE - shOutputColour(0) = shSample(diffuseMap, UV.xy) * colourPassthrough; -#else - shOutputColour(0) = colourPassthrough; -#endif - } - -#endif diff --git a/files/materials/mygui.shaderset b/files/materials/mygui.shaderset deleted file mode 100644 index 980cd4caf4..0000000000 --- a/files/materials/mygui.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set mygui_vertex -{ - source mygui.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_3_0 vs_2_0 -} - -shader_set mygui_fragment -{ - source mygui.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/objects.mat b/files/materials/objects.mat deleted file mode 100644 index 7d3085b0f2..0000000000 --- a/files/materials/objects.mat +++ /dev/null @@ -1,147 +0,0 @@ -material openmw_objects_base -{ - diffuse 1.0 1.0 1.0 1.0 - specular 0 0 0 0 1 - ambient 1.0 1.0 1.0 - emissive 0.0 0.0 0.0 - vertmode 0 - diffuseMap black.png - normalMap - emissiveMap - specMap - darkMap - use_emissive_map false - use_detail_map false - use_diffuse_map false - use_dark_map false - emissiveMapUVSet 0 - detailMapUVSet 0 - diffuseMapUVSet 0 - darkMapUVSet 0 - use_parallax false - - scene_blend default - depth_write default - depth_check default - alpha_rejection default - transparent_sorting default - polygon_mode default - env_map false - env_map_color 1 1 1 - - alphaTestMode 0 - alphaTestValue 0 - - pass - { - vertex_program openmw_objects_vertex - fragment_program openmw_objects_fragment - - shader_properties - { - vertexcolor_mode $vertmode - normalMap $normalMap - emissiveMapUVSet $emissiveMapUVSet - detailMapUVSet $detailMapUVSet - diffuseMapUVSet $diffuseMapUVSet - darkMapUVSet $darkMapUVSet - emissiveMap $emissiveMap - detailMap $detailMap - diffuseMap $diffuseMap - specMap $specMap - darkMap $darkMap - env_map $env_map - env_map_color $env_map_color - use_parallax $use_parallax - alphaTestMode $alphaTestMode - alphaTestValue $alphaTestValue - } - - diffuse $diffuse - specular $specular - ambient $ambient - emissive $emissive - scene_blend $scene_blend - alpha_rejection $alpha_rejection - depth_write $depth_write - depth_check $depth_check - transparent_sorting $transparent_sorting - polygon_mode $polygon_mode - cull_hardware $cullmode - - texture_unit diffuseMap - { - direct_texture $diffuseMap - create_in_ffp $use_diffuse_map - tex_coord_set $diffuseMapUVSet - tex_address_mode $diffuseMapClampMode - } - - texture_unit normalMap - { - direct_texture $normalMap - // force automips here for now - num_mipmaps 4 - } - - texture_unit darkMap - { - create_in_ffp $use_dark_map - colour_op_ex modulate src_current src_texture - alpha_op_ex modulate src_current src_texture - direct_texture $darkMap - tex_coord_set $darkMapUVSet - tex_address_mode $darkMapClampMode - } - - texture_unit detailMap - { - create_in_ffp $use_detail_map - colour_op_ex modulate_x2 src_current src_texture - direct_texture $detailMap - tex_coord_set $detailMapUVSet - tex_address_mode $detailMapClampMode - } - - texture_unit emissiveMap - { - create_in_ffp $use_emissive_map - colour_op add - direct_texture $emissiveMap - tex_coord_set $emissiveMapUVSet - tex_address_mode $emissiveMapClampMode - } - - texture_unit envMap - { - create_in_ffp $env_map - env_map spherical - anim_texture2 textures\magicitem\caust.dds 32 2 - colour_op add - } - - texture_unit specMap - { - direct_texture $specMap - } - - 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 - } - } -} diff --git a/files/materials/objects.shader b/files/materials/objects.shader deleted file mode 100644 index 5c74b11393..0000000000 --- a/files/materials/objects.shader +++ /dev/null @@ -1,591 +0,0 @@ -#include "core.h" - - -#define FOG @shGlobalSettingBool(fog) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM - #include "shadows.h" -#endif - -#if FOG || SHADOWS_PSSM -#define NEED_DEPTH -#endif - -#define SPECULAR 1 - -#define NORMAL_MAP @shPropertyHasValue(normalMap) -#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) -#define DETAIL_MAP @shPropertyHasValue(detailMap) -#define DIFFUSE_MAP @shPropertyHasValue(diffuseMap) -#define DARK_MAP @shPropertyHasValue(darkMap) -#define SPEC_MAP @shPropertyHasValue(specMap) && SPECULAR - -#define ALPHATEST_MODE @shPropertyString(alphaTestMode) - -#define PARALLAX @shPropertyBool(use_parallax) -#define PARALLAX_SCALE 0.04 -#define PARALLAX_BIAS -0.02 - -// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more -#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet) || @shPropertyString(diffuseMapUVSet) || @shPropertyString(darkMapUVSet)) - -// if normal mapping is enabled, we force pixel lighting -#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) - -#define UNDERWATER @shGlobalSettingBool(render_refraction) - -#define VERTEXCOLOR_MODE @shPropertyString(vertexcolor_mode) - -#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) - -#define ENV_MAP @shPropertyBool(env_map) - -#define NEED_NORMAL (!VERTEX_LIGHTING || ENV_MAP) || SPECULAR - -#ifdef SH_VERTEX_SHADER - - // ------------------------------------- VERTEX --------------------------------------- - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - - shUniform(float4x4, textureMatrix0) @shAutoConstant(textureMatrix0, texture_matrix, 0) - -#if (VIEWPROJ_FIX) || (SHADOWS) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - -#if VIEWPROJ_FIX - shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) - shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) -#endif - - shVertexInput(float2, uv0) -#if SECOND_UV_SET - shVertexInput(float2, uv1) -#endif - shOutput(float4, UV) - - shNormalInput(float4) - -#if NORMAL_MAP - shTangentInput(float4) - shOutput(float3, tangentPassthrough) -#endif - -#if NEED_NORMAL - shOutput(float3, normalPassthrough) -#endif - - // Depth in w - shOutput(float4, objSpacePositionPassthrough) - -#if VERTEXCOLOR_MODE != 0 - shColourInput(float4) -#endif - -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - shOutput(float4, colourPassthrough) -#endif - -#if ENV_MAP || VERTEX_LIGHTING - shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) -#endif - -#if VERTEX_LIGHTING - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -#if VERTEXCOLOR_MODE != 2 - shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) -#endif - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) -#if VERTEXCOLOR_MODE != 1 - shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) -#endif - -#endif - -#if SHADOWS - shOutput(float4, lightSpacePos0) - shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) -#endif - -#if SHADOWS_PSSM - @shForeach(3) - shOutput(float4, lightSpacePos@shIterator) - shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) - @shEndForeach -#if !VIEWPROJ_FIX - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif -#endif - -#if VERTEX_LIGHTING - shOutput(float4, lightResult) - shOutput(float3, directionalResult) -#endif - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - - UV.xy = shMatrixMult (textureMatrix0, float4(uv0,0,1)).xy; -#if SECOND_UV_SET - UV.zw = uv1; -#endif - -#if ENV_MAP || VERTEX_LIGHTING - float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); -#endif - -#if ENV_MAP - float3 viewVec = normalize( shMatrixMult(worldView, shInputPosition).xyz); - - float3 r = reflect( viewVec, viewNormal ); - float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); - UV.z = r.x/m + 0.5; - UV.w = r.y/m + 0.5; -#endif - -#if NORMAL_MAP - tangentPassthrough = tangent.xyz; -#endif -#if NEED_NORMAL - normalPassthrough = normal.xyz; -#endif -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - colourPassthrough = colour; -#endif - -#ifdef NEED_DEPTH - - -#if VIEWPROJ_FIX - float4x4 vpFixed = vpMatrix; -#if !SH_GLSL && !SH_GLSLES - vpFixed[2] = vpRow2Fix; -#else - vpFixed[0][2] = vpRow2Fix.x; - vpFixed[1][2] = vpRow2Fix.y; - vpFixed[2][2] = vpRow2Fix.z; - vpFixed[3][2] = vpRow2Fix.w; -#endif - - float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); - - objSpacePositionPassthrough.w = shMatrixMult(fixedWVP, shInputPosition).z; -#else - objSpacePositionPassthrough.w = shOutputPosition.z; -#endif - -#endif - - objSpacePositionPassthrough.xyz = shInputPosition.xyz; - -#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 - - -#if VERTEX_LIGHTING - float3 viewPos = shMatrixMult(worldView, shInputPosition).xyz; - - float3 lightDir; - float d; - lightResult = float4(0,0,0,1); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#else - lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#endif - -#if @shIterator == 0 - directionalResult = lightResult.xyz; -#endif - - @shEndForeach - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += lightAmbient.xyz * colour.xyz + materialEmissive.xyz; - lightResult.a *= colour.a; -#endif -#if VERTEXCOLOR_MODE == 1 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colour.xyz; -#endif -#if VERTEXCOLOR_MODE == 0 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; -#endif - - lightResult.a *= materialDiffuse.a; - -#endif - } - -#else -#if NORMAL_MAP && SH_GLSLES - mat3 transpose( mat3 m); -#endif - // ----------------------------------- FRAGMENT ------------------------------------------ - -#if UNDERWATER - #include "underwater.h" -#endif - - SH_BEGIN_PROGRAM -#if DIFFUSE_MAP - shSampler2D(diffuseMap) -#endif - -#if NORMAL_MAP - shSampler2D(normalMap) -#endif - -#if DARK_MAP - shSampler2D(darkMap) -#endif - -#if DETAIL_MAP - shSampler2D(detailMap) -#endif - -#if EMISSIVE_MAP - shSampler2D(emissiveMap) -#endif - -#if ENV_MAP - shSampler2D(envMap) - shUniform(float3, env_map_color) @shUniformProperty3f(env_map_color, env_map_color) -#endif - -#if SPEC_MAP - shSampler2D(specMap) -#endif - -#if ENV_MAP || SPECULAR || PARALLAX - shUniform(float3, cameraPosObjSpace) @shAutoConstant(cameraPosObjSpace, camera_position_object_space) -#endif -#if SPECULAR - shUniform(float3, lightSpec0) @shAutoConstant(lightSpec0, light_specular_colour, 0) - shUniform(float3, lightPosObjSpace0) @shAutoConstant(lightPosObjSpace0, light_position_object_space, 0) - shUniform(float, matShininess) @shAutoConstant(matShininess, surface_shininess) - shUniform(float3, matSpec) @shAutoConstant(matSpec, surface_specular_colour) -#endif - - shInput(float4, UV) - -#if NORMAL_MAP - shInput(float3, tangentPassthrough) -#endif -#if NEED_NORMAL - shInput(float3, normalPassthrough) -#endif - - shInput(float4, objSpacePositionPassthrough) - -#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING - shInput(float4, colourPassthrough) -#endif - -#if FOG - shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) -#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) || (FOG) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) -#endif - -#if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) - shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) -#endif - -#if VERTEX_LIGHTING - shInput(float4, lightResult) - shInput(float3, directionalResult) -#else - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) - shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) - #if VERTEXCOLOR_MODE != 2 - shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) - #endif - shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) - #if VERTEXCOLOR_MODE != 1 - shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - #endif -#endif - -#if ALPHATEST_MODE != 0 - shUniform(float, alphaTestValue) @shUniformProperty1f(alphaTestValue, alphaTestValue) -#endif - - SH_START_PROGRAM - { - float4 newUV = UV; - -#ifdef NEED_DEPTH - float depthPassthrough = objSpacePositionPassthrough.w; -#endif - -#if NEED_NORMAL - float3 normal = normalPassthrough; -#endif - -#if NORMAL_MAP - float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); - float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - - #if SH_GLSL || SH_GLSLES - tbn = transpose(tbn); - #endif - - float4 normalTex = shSample(normalMap, UV.xy); - - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); -#endif - -#if ENV_MAP || SPECULAR || PARALLAX - float3 eyeDir = normalize(cameraPosObjSpace.xyz - objSpacePositionPassthrough.xyz); -#endif - -#if PARALLAX - float3 TSeyeDir = normalize(shMatrixMult(tbn, eyeDir)); - - newUV += (TSeyeDir.xyxy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS )).xyxy; -#endif - -#if DIFFUSE_MAP - #if @shPropertyString(diffuseMapUVSet) - float4 diffuse = shSample(diffuseMap, newUV.zw); - #else - float4 diffuse = shSample(diffuseMap, newUV.xy); - #endif -#else - float4 diffuse = float4(1,1,1,1); -#endif - -#if ALPHATEST_MODE == 1 - if (diffuse.a >= alphaTestValue) - discard; -#elif ALPHATEST_MODE == 2 - if (diffuse.a != alphaTestValue) - discard; -#elif ALPHATEST_MODE == 3 - if (diffuse.a > alphaTestValue) - discard; -#elif ALPHATEST_MODE == 4 - if (diffuse.a <= alphaTestValue) - discard; -#elif ALPHATEST_MODE == 5 - if (diffuse.a == alphaTestValue) - discard; -#elif ALPHATEST_MODE == 6 - if (diffuse.a < alphaTestValue) - discard; -#elif ALPHATEST_MODE == 7 - discard; -#endif - - -#if DETAIL_MAP -#if @shPropertyString(detailMapUVSet) - diffuse *= shSample(detailMap, newUV.zw)*2; -#else - diffuse *= shSample(detailMap, newUV.xy)*2; -#endif -#endif - -#if DARK_MAP -#if @shPropertyString(darkMapUVSet) - diffuse *= shSample(darkMap, newUV.zw); -#else - diffuse *= shSample(darkMap, newUV.xy); -#endif -#endif - - shOutputColour(0) = diffuse; - -#if !VERTEX_LIGHTING - float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough.xyz,1)).xyz; - float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); - - float3 lightDir; - float d; - float4 lightResult = float4(0,0,0,1); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += colourPassthrough.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#else - lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(viewNormal.xyz, lightDir), 0.0); -#endif - -#if @shIterator == 0 - float3 directionalResult = lightResult.xyz; -#endif - - @shEndForeach - - -#if VERTEXCOLOR_MODE == 2 - lightResult.xyz += lightAmbient.xyz * colourPassthrough.xyz + materialEmissive.xyz; - lightResult.a *= colourPassthrough.a; -#endif -#if VERTEXCOLOR_MODE == 1 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colourPassthrough.xyz; -#endif -#if VERTEXCOLOR_MODE == 0 - lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; -#endif - - lightResult.a *= materialDiffuse.a; -#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.0-((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 - - - -#if (UNDERWATER) || (FOG) - float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough.xyz,1)).xyz; -#endif - -#if UNDERWATER - float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0.0,0.0,1.0), waterLevel); -#endif - -#if SHADOWS || SHADOWS_PSSM - shOutputColour(0) *= (lightResult - float4(directionalResult * (1.0-shadow),0.0)); -#else - shOutputColour(0) *= lightResult; -#endif - -#if EMISSIVE_MAP - #if @shPropertyString(emissiveMapUVSet) - shOutputColour(0).xyz += shSample(emissiveMap, newUV.zw).xyz; - #else - shOutputColour(0).xyz += shSample(emissiveMap, newUV.xy).xyz; - #endif -#endif - -#if ENV_MAP - // Everything looks better with fresnel - float facing = 1.0 - max(abs(dot(-eyeDir, normal)), 0.0); - float envFactor = shSaturate(0.25 + 0.75 * pow(facing, 1.0)); - - shOutputColour(0).xyz += shSample(envMap, UV.zw).xyz * envFactor * env_map_color; -#endif - -#if SPECULAR - float3 light0Dir = normalize(lightPosObjSpace0.xyz); - - float NdotL = max(dot(normal, light0Dir), 0.0); - float3 halfVec = normalize (light0Dir + eyeDir); - - float shininess = matShininess; -#if SPEC_MAP - float4 specTex = shSample(specMap, UV.xy); - shininess *= (specTex.a); -#endif - - float3 specular = pow(max(dot(normal, halfVec), 0.0), shininess) * lightSpec0 * matSpec; -#if SPEC_MAP - specular *= specTex.xyz; -#else - specular *= diffuse.a; -#endif - - shOutputColour(0).xyz += specular * shadow; -#endif - -#if FOG - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - - -#if UNDERWATER - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); -#else - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); -#endif - -#endif - - // prevent negative colour output (for example with negative lights) - shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); - } -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m){ - return mat3( - m[0][0],m[1][0],m[2][0], - m[0][1],m[1][1],m[2][1], - m[0][2],m[1][2],m[2][2] - ); - } -#endif - -#endif diff --git a/files/materials/objects.shaderset b/files/materials/objects.shaderset deleted file mode 100644 index 028c15ce8a..0000000000 --- a/files/materials/objects.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index b953a91311..0000000000 --- a/files/materials/openmw.configuration +++ /dev/null @@ -1,20 +0,0 @@ -configuration water_reflection -{ - shadows false - shadows_pssm false - viewproj_fix true -} - -configuration water_refraction -{ - viewproj_fix true - render_refraction true -} - -configuration local_map -{ - fog false - shadows false - shadows_pssm false - simple_water true -} diff --git a/files/materials/quad.mat b/files/materials/quad.mat deleted file mode 100644 index 77a2c0c340..0000000000 --- a/files/materials/quad.mat +++ /dev/null @@ -1,22 +0,0 @@ -material quad -{ - depth_write on - - pass - { - vertex_program transform_vertex - fragment_program quad_fragment - - depth_write $depth_write - - texture_unit SceneBuffer - { - } - } -} - -material quad_noDepthWrite -{ - parent quad - depth_write off -} diff --git a/files/materials/quad.shader b/files/materials/quad.shader deleted file mode 100644 index 4620588c3c..0000000000 --- a/files/materials/quad.shader +++ /dev/null @@ -1,25 +0,0 @@ -#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 deleted file mode 100644 index 71fd82da44..0000000000 --- a/files/materials/quad.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set transform_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 -} diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle deleted file mode 100644 index 58045f6d73..0000000000 --- a/files/materials/ripples.particle +++ /dev/null @@ -1,26 +0,0 @@ -particle_system openmw/Ripples -{ - material openmw/Ripple - particle_width 30 - particle_height 30 - // To make the particles move with the scene node when the waterlevel changes - local_space true - quota 300 - billboard_type perpendicular_common - common_up_vector 0 1 0 - common_direction 0 0 1 - - affector ColourFader - { - alpha -0.33 - } - - affector Scaler - { - rate 120 - } - - affector Rotator - { - } -} diff --git a/files/materials/selection.mat b/files/materials/selection.mat deleted file mode 100644 index 2cb92f8843..0000000000 --- a/files/materials/selection.mat +++ /dev/null @@ -1,9 +0,0 @@ -material SelectionColour -{ - allow_fixed_function false - pass - { - vertex_program selection_vertex - fragment_program selection_fragment - } -} diff --git a/files/materials/selection.shader b/files/materials/selection.shader deleted file mode 100644 index 095a31259d..0000000000 --- a/files/materials/selection.shader +++ /dev/null @@ -1,24 +0,0 @@ -#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(float4, colour) @shAutoConstant(colour, custom, 1) - - SH_START_PROGRAM - { - shOutputColour(0) = colour; - //shOutputColour(0) = float4(1,0,0,1); - } - -#endif diff --git a/files/materials/selection.shaderset b/files/materials/selection.shaderset deleted file mode 100644 index c90826282e..0000000000 --- a/files/materials/selection.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -shader_set selection_vertex -{ - source selection.shader - type vertex - profiles_cg vs_2_0 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set selection_fragment -{ - source selection.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/shadowcaster.mat b/files/materials/shadowcaster.mat deleted file mode 100644 index 5c5c8e088d..0000000000 --- a/files/materials/shadowcaster.mat +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index 8f7911553a..0000000000 --- a/files/materials/shadowcaster.shader +++ /dev/null @@ -1,55 +0,0 @@ -#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.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; - - if (alpha < 0.5) - discard; -#endif - - shOutputColour(0) = float4(finalDepth, finalDepth, finalDepth, 1.0); - } - -#endif diff --git a/files/materials/shadowcaster.shaderset b/files/materials/shadowcaster.shaderset deleted file mode 100644 index 5f4990ed11..0000000000 --- a/files/materials/shadowcaster.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index eba3a3ea74..0000000000 --- a/files/materials/shadows.h +++ /dev/null @@ -1,51 +0,0 @@ - -#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 : 0.0; // top left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1.0 : 0.0; // bottom right - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1.0 : 0.0; // bottom left - c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1.0 : 0.0; // top right - return c / 4.0; -} - - - -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 deleted file mode 100644 index c2e8ddeb09..0000000000 --- a/files/materials/sky.mat +++ /dev/null @@ -1,140 +0,0 @@ -material QueryTotalPixels -{ - allow_fixed_function false - pass - { - vertex_program sun_vertex - fragment_program sun_fragment - cull_hardware none - polygon_mode_overrideable off - depth_check off - depth_write off - colour_write off - } -} - -material QueryVisiblePixels -{ - allow_fixed_function false - pass - { - vertex_program sun_vertex - fragment_program sun_fragment - cull_hardware none - cull_software none - polygon_mode_overrideable off - depth_check on - depth_write off - colour_write off - } -} - -material openmw_moon -{ - allow_fixed_function false - pass - { - vertex_program moon_vertex - fragment_program moon_fragment - cull_hardware none - - polygon_mode_overrideable off - depth_write off - depth_check off - scene_blend alpha_blend - - texture_unit diffuseMap - { - texture_alias $texture - } - - texture_unit alphaMap - { - texture_alias $alphatexture - } - } -} - -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 - - 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 - cull_hardware none - - 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 deleted file mode 100644 index 830be862a4..0000000000 --- a/files/materials/stars.shader +++ /dev/null @@ -1,48 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldview) @shAutoConstant(worldview, worldview_matrix) - shUniform(float4x4, proj) @shAutoConstant(proj, projection_matrix) - - shVertexInput(float2, uv0) - shOutput(float2, UV) - shOutput(float, fade) - - SH_START_PROGRAM - { - float4x4 worldviewFixed = worldview; -#if !SH_GLSL && !SH_GLSLES - worldviewFixed[0][3] = 0.0; - worldviewFixed[1][3] = 0.0; - worldviewFixed[2][3] = 0.0; -#else - worldviewFixed[3][0] = 0.0; - worldviewFixed[3][1] = 0.0; - worldviewFixed[3][2] = 0.0; -#endif - - shOutputPosition = shMatrixMult(proj, shMatrixMult(worldviewFixed, shInputPosition)); - UV = uv0; - - fade = (shInputPosition.z > 50.0) ? 1.0 : 0.0; - } - -#else - - SH_BEGIN_PROGRAM - - 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); - } - -#endif diff --git a/files/materials/stars.shaderset b/files/materials/stars.shaderset deleted file mode 100644 index 0f8803450b..0000000000 --- a/files/materials/stars.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 72e49d1a71..0000000000 --- a/files/materials/sun.shader +++ /dev/null @@ -1,41 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, world) @shAutoConstant(world, world_matrix) - shUniform(float4x4, view) @shAutoConstant(view, view_matrix) -shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - - SH_START_PROGRAM - { - float4x4 viewFixed = view; -#if !SH_GLSL && !SH_GLSLES - viewFixed[0][3] = 0.0; - viewFixed[1][3] = 0.0; - viewFixed[2][3] = 0.0; -#else - viewFixed[3][0] = 0.0; - viewFixed[3][1] = 0.0; - viewFixed[3][2] = 0.0; -#endif - shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); - UV = uv0; - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shInput(float2, UV) - 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); - } - -#endif diff --git a/files/materials/sun.shaderset b/files/materials/sun.shaderset deleted file mode 100644 index 1b9e92a439..0000000000 --- a/files/materials/sun.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index f20fce5063..0000000000 --- a/files/materials/terrain.shader +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "core.h" - -#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) - -#define FOG (@shGlobalSettingBool(fog) && !@shPropertyBool(render_composite_map)) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM -#include "shadows.h" -#endif - -#define NUM_LAYERS @shPropertyString(num_layers) - -#if FOG || SHADOWS_PSSM -#define NEED_DEPTH 1 -#endif - -#define UNDERWATER @shGlobalSettingBool(render_refraction) - -#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) - -#define RENDERCMP @shPropertyBool(render_composite_map) - -#define LIGHTING !RENDERCMP - -#define COMPOSITE_MAP @shPropertyBool(display_composite_map) - -#define NORMAL_MAP @shPropertyBool(normal_map_enabled) -#define PARALLAX @shPropertyBool(parallax_enabled) - -#define VERTEX_LIGHTING (!NORMAL_MAP) - -#define PARALLAX_SCALE 0.04 -#define PARALLAX_BIAS -0.02 - -// This is just for the permutation handler -#define NORMAL_MAPS @shPropertyString(normal_maps) - -#if NEED_DEPTH -@shAllocatePassthrough(1, depth) -#endif - -@shAllocatePassthrough(2, UV) - -@shAllocatePassthrough(3, worldPos) - -#if LIGHTING -@shAllocatePassthrough(3, normalPassthrough) -#if VERTEX_LIGHTING -@shAllocatePassthrough(3, lightResult) -@shAllocatePassthrough(3, directionalResult) -#else -@shAllocatePassthrough(3, colourPassthrough) -#endif - -#if SHADOWS -@shAllocatePassthrough(4, lightSpacePos0) -#endif -#if SHADOWS_PSSM -@shForeach(3) - @shAllocatePassthrough(4, lightSpacePos@shIterator) -@shEndForeach -#endif -#endif - -#ifdef SH_VERTEX_SHADER - - // ------------------------------------- VERTEX --------------------------------------- - - SH_BEGIN_PROGRAM - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) - -#if VIEWPROJ_FIX - shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) -#endif - - shVertexInput(float2, uv0) - -#if LIGHTING - shNormalInput(float4) - shColourInput(float4) - -#if VERTEX_LIGHTING - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -#endif - -#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 - -#endif - - - @shPassthroughVertexOutputs - - SH_START_PROGRAM - { - float4 worldPos = shMatrixMult(worldMatrix, shInputPosition); - - shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); - -#if NEED_DEPTH -#if VIEWPROJ_FIX - float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL && !SH_GLSLES - vpFixed[2] = vpRow2Fix; -#else - vpFixed[0][2] = vpRow2Fix.x; - vpFixed[1][2] = vpRow2Fix.y; - vpFixed[2][2] = vpRow2Fix.z; - vpFixed[3][2] = vpRow2Fix.w; -#endif - - float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); - - float depth = shMatrixMult(fixedWVP, shInputPosition).z; - @shPassthroughAssign(depth, depth); -#else - @shPassthroughAssign(depth, shOutputPosition.z); -#endif - -#endif - - @shPassthroughAssign(UV, uv0); - - @shPassthroughAssign(worldPos, worldPos.xyz); - -#if LIGHTING - @shPassthroughAssign(normalPassthrough, normal.xyz); -#endif -#if LIGHTING && !VERTEX_LIGHTING - @shPassthroughAssign(colourPassthrough, colour.xyz); -#endif - -#if LIGHTING - -#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 - - -#if VERTEX_LIGHTING - // Lighting - float3 lightDir; - float d; - float3 lightResult = float3(0,0,0); - float3 directionalResult = float3(0,0,0); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - - lightResult.xyz += lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normal.xyz, lightDir), 0.0); - -#if @shIterator == 0 - directionalResult = lightResult.xyz; -#endif - @shEndForeach - lightResult.xyz += lightAmbient.xyz; - lightResult.xyz *= colour.xyz; - directionalResult.xyz *= colour.xyz; - - @shPassthroughAssign(lightResult, lightResult); - @shPassthroughAssign(directionalResult, directionalResult); -#endif - -#endif - } - -#else - - // ----------------------------------- FRAGMENT ------------------------------------------ - -#if UNDERWATER - #include "underwater.h" -#endif -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m); -#endif - - SH_BEGIN_PROGRAM - - -#if COMPOSITE_MAP - shSampler2D(compositeMap) -#else - -@shForeach(@shPropertyString(num_blendmaps)) - shSampler2D(blendMap@shIterator) -@shEndForeach - -@shForeach(@shPropertyString(num_layers)) - shSampler2D(diffuseMap@shIterator) -#if @shPropertyBool(use_normal_map_@shIterator) - shSampler2D(normalMap@shIterator) -#endif -@shEndForeach - -#endif - -#if FOG - shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) -#endif - - @shPassthroughFragmentInputs - -#if LIGHTING - -#if !VERTEX_LIGHTING -shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) -shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) -shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) -#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 -#endif - -#if (UNDERWATER) || (FOG) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - -#if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) -#endif - - -// For specular -#if LIGHTING - shUniform(float3, lightSpec0) @shAutoConstant(lightSpec0, light_specular_colour, 0) - shUniform(float3, lightPos0) @shAutoConstant(lightPos0, light_position, 0) -#endif - -shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) - - SH_START_PROGRAM - { - -#if NEED_DEPTH - float depth = @shPassthroughReceive(depth); -#endif - - float2 UV = @shPassthroughReceive(UV); - - float3 worldPos = @shPassthroughReceive(worldPos); - -#if LIGHTING - float3 normal = @shPassthroughReceive(normalPassthrough); -#endif - -#if LIGHTING && !VERTEX_LIGHTING - -#if NORMAL_MAP - // derive the tangent space basis - float3 tangent = float3(1,0, 0); - - float3 binormal = normalize(cross(tangent, normal)); - tangent = normalize(cross(normal, binormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal - - // derive final matrix - float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL || SH_GLSLES - tbn = transpose(tbn); - #endif -#endif - -#endif - -#if UNDERWATER - float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); -#endif - -#if !IS_FIRST_PASS -// Opacity the previous passes should have, i.e. 1 - (opacity of this pass) -float previousAlpha = 1.0; -#endif - - -shOutputColour(0) = float4(1,1,1,1); - -float3 TSnormal = float3(0,0,1); - -#if COMPOSITE_MAP - shOutputColour(0).xyz = shSample(compositeMap, UV).xyz; -#else - - // Layer calculations -// rescale UV to directly map edge vertices to texel centers - this is -// important to get correct blending at cell transitions -// TODO: parameterize texel size -float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5; -@shForeach(@shPropertyString(num_blendmaps)) - float4 blendValues@shIterator = shSaturate(shSample(blendMap@shIterator, blendUV)); -@shEndForeach - - - float4 albedo = float4(0,0,0,1); - - float2 layerUV = float2(UV.x, 1.0-UV.y) * 16.0; // Reverse Y, required to get proper tangents - float2 thisLayerUV; - float4 normalTex; - float4 diffuseTex; - - float3 eyeDir = normalize(cameraPos.xyz - worldPos); -#if PARALLAX - float3 TSeyeDir = normalize(shMatrixMult(tbn, eyeDir)); -#endif - -@shForeach(@shPropertyString(num_layers)) - thisLayerUV = layerUV; -#if @shPropertyBool(use_normal_map_@shIterator) - normalTex = shSample(normalMap@shIterator, thisLayerUV); -#if @shIterator == 0 && IS_FIRST_PASS - TSnormal = normalize(normalTex.xyz * 2.0 - 1.0); -#else - TSnormal = shLerp(TSnormal, normalTex.xyz * 2.0 - 1.0, blendValues@shPropertyString(blendmap_component_@shIterator)); -#endif -#endif - -#if @shPropertyBool(use_parallax_@shIterator) - thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS ); -#endif - - diffuseTex = shSample(diffuseMap@shIterator, layerUV); -#if !@shPropertyBool(use_specular_@shIterator) - diffuseTex.a = 0.0; -#endif - -#if @shIterator == 0 -albedo = diffuseTex; -#else -albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_component_@shIterator)); -#endif - -#if !IS_FIRST_PASS - previousAlpha *= 1.0-blendValues@shPropertyString(blendmap_component_@shIterator); -#endif - - -@shEndForeach - - shOutputColour(0).rgb *= albedo.xyz; - -#endif - -#if LIGHTING - -#if VERTEX_LIGHTING - // Lighting - float3 lightResult = @shPassthroughReceive(lightResult); - float3 directionalResult = @shPassthroughReceive(directionalResult); -#else - -#if NORMAL_MAP - normal = normalize (shMatrixMult( transpose(tbn), TSnormal )); -#endif - - float3 colour = @shPassthroughReceive(colourPassthrough); - float3 lightDir; - float d; - float3 lightResult = float3(0,0,0); - @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (worldPos * lightPosition[@shIterator].w); - d = length(lightDir); - lightDir = normalize(lightDir); - - lightResult.xyz += lightDiffuse[@shIterator].xyz - * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normal.xyz, lightDir), 0.0); -#if @shIterator == 0 - float3 directionalResult = lightResult.xyz; -#endif - @shEndForeach - lightResult.xyz += lightAmbient.xyz; - lightResult.xyz *= colour.xyz; - directionalResult.xyz *= colour.xyz; -#endif - - // 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 - - shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow)); -#endif - -#if LIGHTING && !COMPOSITE_MAP - // Specular - float3 light0Dir = normalize(lightPos0.xyz); - - float NdotL = max(dot(normal, light0Dir), 0.0); - float3 halfVec = normalize (light0Dir + eyeDir); - - float3 specular = pow(max(dot(normal, halfVec), 0.0), 32.0) * lightSpec0; - shOutputColour(0).xyz += specular * (albedo.a) * shadow; -#endif - -#if FOG - float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); - - #if UNDERWATER - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); - #else - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); - #endif -#endif - - // prevent negative colour output (for example with negative lights) - shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if IS_FIRST_PASS - shOutputColour(0).a = 1.0; -#else - shOutputColour(0).a = 1.0-previousAlpha; -#endif - } -#if NORMAL_MAP && SH_GLSLES - mat3 transpose(mat3 m){ - return mat3( - m[0][0],m[1][0],m[2][0], - m[0][1],m[1][1],m[2][1], - m[0][2],m[1][2],m[2][2] - ); - } -#endif -#endif diff --git a/files/materials/terrain.shaderset b/files/materials/terrain.shaderset deleted file mode 100644 index a72f2358fd..0000000000 --- a/files/materials/terrain.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 2f38f65461..0000000000 --- a/files/materials/underwater.h +++ /dev/null @@ -1,121 +0,0 @@ -#define UNDERWATER_COLOUR float3(0.090195, 0.115685, 0.12745) - -#define VISIBILITY 1000.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.z - worldPos.z) / 50.0); - - float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), 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.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; - causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); - - //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.xy, 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.xy+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - float causticB = 1.0-perturb(causticMap,causticPos.xy+(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.0; - - // shore transition - caustics = shLerp (float3(1,1,1), caustics, waterDepth); - - return caustics; -} - diff --git a/files/materials/water.mat b/files/materials/water.mat deleted file mode 100644 index cf03be39e5..0000000000 --- a/files/materials/water.mat +++ /dev/null @@ -1,101 +0,0 @@ -material Water -{ - allow_fixed_function false - - pass - { - emissive 1.0 1.0 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 - - scene_blend alpha_blend - depth_write off - - texture_unit reflectionMap - { - texture_alias WaterReflection - tex_address_mode clamp - } - - texture_unit refractionMap - { - direct_texture WaterRefraction - tex_address_mode clamp - } - - texture_unit depthMap - { - texture_alias SceneDepth - tex_address_mode clamp - } - - texture_unit normalMap - { - texture water_nm.png - } - - texture_unit rippleNormalMap - { - direct_texture RippleNormal - tex_address_mode border - tex_border_colour 0.5 0.5 1.0 - } - - // 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 - } - - 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 - } - } -} - -material openmw/Ripple -{ - // this will be overridden by Water_RippleFrameCount fallback setting - anim_texture2 textures\water\ripple.dds 4 0.25 - pass - { - scene_blend alpha_blend - depth_write off - cull_hardware none - diffuse vertexcolour - emissive 1 1 1 - ambient 0 0 0 - texture_unit diffuseMap - { - create_in_ffp true - anim_texture2 $anim_texture2 - - // to make sure rotating doesn't cause the texture to repeat - tex_address_mode border - tex_border_colour 0 0 0 0 - } - } -} diff --git a/files/materials/water.shader b/files/materials/water.shader deleted file mode 100644 index eff245b5ed..0000000000 --- a/files/materials/water.shader +++ /dev/null @@ -1,354 +0,0 @@ -#include "core.h" - - -#define SIMPLE_WATER @shGlobalSettingBool(simple_water) - -#if SIMPLE_WATER - // --------------------------------------- SIMPLE WATER --------------------------------------------------- - -#define FOG @shGlobalSettingBool(fog) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) - -#if FOG - shOutput(float, depth) -#endif - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; -#if FOG - depth = shOutputPosition.z; -#endif - } - -#else - - SH_BEGIN_PROGRAM - shSampler2D(animatedTexture) - shInput(float2, UV) - shInput(float, depth) - - shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) - shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) - - - SH_START_PROGRAM - { - shOutputColour(0).xyz = shSample(animatedTexture, UV * float2(15.0, 15.0)).xyz * float3(1.0, 1.0, 1.0); - shOutputColour(0).w = 0.7; - -#if FOG - float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); -#endif - } - -#endif - -#else - - - -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - -#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) -#define SHADOWS @shGlobalSettingBool(shadows) - -#if SHADOWS || SHADOWS_PSSM - #include "shadows.h" -#endif - -#define REFRACTION @shGlobalSettingBool(refraction) - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - - shOutput(float3, screenCoordsPassthrough) - shOutput(float4, position) - shOutput(float, depthPassthrough) - - -#if SHADOWS - shOutput(float4, lightSpacePos0) - shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) -#endif - -#if SHADOWS_PSSM - @shForeach(3) - shOutput(float4, lightSpacePos@shIterator) - shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) - @shEndForeach -#endif - -#if SHADOWS || SHADOWS_PSSM - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) -#endif - - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - - - #if !SH_GLSL && !SH_GLSLES - float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, - 0.0, -0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 ); - #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; - - -#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 - - // tweakables ---------------------------------------------------- - - #define VISIBILITY 1500.0 // how far you can look through water - - #define BIG_WAVES_X 0.1 // strength of big waves - #define BIG_WAVES_Y 0.1 - - #define MID_WAVES_X 0.1 // strength of middle sized waves - #define MID_WAVES_Y 0.1 - - #define SMALL_WAVES_X 0.1 // strength of small waves - #define SMALL_WAVES_Y 0.1 - - #define WAVE_CHOPPYNESS 0.05 // wave choppyness - #define WAVE_SCALE 75.0 // overall wave scale - - #define BUMP 0.5 // overall water surface bumpiness - #define REFL_BUMP 0.15 // reflection distortion amount - #define REFR_BUMP 0.06 // refraction distortion amount - - #define SCATTER_AMOUNT 0.3 // 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.0 // 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(float3, screenCoordsPassthrough) - shInput(float4, position) - shInput(float, depthPassthrough) - - shUniform(float, far) @shAutoConstant(far, far_clip_distance) - - shSampler2D(reflectionMap) -#if REFRACTION - shSampler2D(refractionMap) -#endif - shSampler2D(depthMap) - shSampler2D(normalMap) - - shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - 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) - - -#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 - - - SH_START_PROGRAM - { - float3 worldPos = shMatrixMult (wMat, position).xyz; - float2 UV = worldPos.xy / (8192.0*5.0) * 3.0; - UV.y *= -1.0; - -#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.0-((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 - - - float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; - screenCoords.y = (1.0-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; - - float2 nCoord = float2(0.0,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); - - normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); - normal = float3(normal.x, normal.y, -normal.z); - - // 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).xyz; - lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); - lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); - - - float3 lVec = normalize(sunPosition.xyz); - float3 vVec = normalize(position.xyz - cameraPos.xyz); - - - float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - - // sunlight scattering - float3 pNormal = float3(0,0,1); - float3 lR = reflect(lVec, lNormal); - float3 llR = reflect(lVec, pNormal); - - float s = shSaturate(dot(lR, vVec)*2.0-1.2); - float lightScatter = shadow * 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.z>0.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.xy*REFL_BUMP)).rgb; - - // refraction - float3 R = reflect(vVec, normal); - -#if REFRACTION - float3 refraction = shSample(refractionMap, (screenCoords-(normal.xy*REFR_BUMP))*1.0).rgb; - - // brighten up the refraction underwater - refraction = (cameraPos.z < 0.0) ? shSaturate(refraction * 1.5) : refraction; -#endif - - // specular - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; - -#if REFRACTION - shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; -#else - shOutputColour(0).xyz = shLerp(reflection, float3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * sunSpecular.xyz; -#endif - // fog - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - -#if REFRACTION - shOutputColour(0).w = 1.0; -#else - shOutputColour(0).w = shSaturate(fresnel*2.0 + specular); -#endif - } - -#endif - - -#endif diff --git a/files/materials/water.shaderset b/files/materials/water.shaderset deleted file mode 100644 index 5e070a45a9..0000000000 --- a/files/materials/water.shaderset +++ /dev/null @@ -1,15 +0,0 @@ -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/water/circle.png b/files/water/circle.png deleted file mode 100644 index 9a1cf268c0be2cdae27fe04ee7f7c0aa6de12c11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RY0s#yODLP_H6#xJL8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0$xc(K~#9!?VG<&8$l4pf3r}yK~51x zqM)L&3(GXPrAgYOr>3Lk4JgeU@D%ooAf>PicNCFA3Q(Fz0Zj_eDdq^q=iI@0XFq8g z%YXL!d^@wd^R1{VbwWh8fL)*q99VRLJ>Vno0NepLzy!Fqm;m2Y^|96gs%qr{w1Es5 z0s5aYvhQlwGS&)73oxjN^fEC9fHXz`BmM=rt&w;!ZtXYaT?GL8!0Zi)7h?wW-&_Eo z1q|Pjcrk`RYaK39whD+y2lxtX(=0pyJyo5S`A{fHKC|-FH1gP(CN{?E%OG&pphy0- zIIA=V0OuP-K9BQC1lX{DzVwsu8u@I4$>))+B>>QgfP5aEQe{v?TENeSX8UzZkrykKL0jHxq|slR18ie6i&%hJaRXJH0-u3>;>Esk{G0FcBq$;Re794Y znDGPnq(*%42{?2>9^-iUED6?plGC&pJy{2cNZSr3J>i3@-se-`2!A+Q%mJqk1vt&? z{+2BjJz_gp)50rugLP@Vq8qGLfHVc>U0Sc$6X17bhaaU*iUQ6N9PR-YaTl07 zGrZy^Fz@ww#UwEI<9Nk&62SWuNZVoa;f)=VAFJwPz7V={D8Lnv4n+fis@^-B24my= zq%SbQPhVj0%pc&sHD)iIIC%U|bkP;!y*-``5-%8}h7pn{vCMkPkFQUZP`xp5a z1uzk&z;OiRkC!^glT|jErITI0j0l@xp3c&hnGz`78L}VP0WKRv{?h9Flr;#YYjf%1 jWV$-*_wuxOzdrv5<*cfu_Ri)S00000NkvXXu0mjfBzZwt diff --git a/files/water/water_nm.png b/files/water/water_nm.png deleted file mode 100644 index 361431a0efc35882b56bab8ea407d245f27c879d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24405 zcmV(~K+nI4P)zc5 z|C-I$7<43zLB=3!a^>X8VD@AJlVs9l!-FOovbTP(O;@uvd~NvJ!LFdUpF!yNjKLWA z`N9miMi4X^n@Ihc)lh8KDqg#IEnsbW7gSTbh=z_$braF_XgVQ={@l2N$e^x(k?c&K zkxU9kH|&54x{D?$ijJTIA{#pB+%yFQbU?R0L^rV;Xfol^#Xqw7TJTpCtApx>eg5rc z_atd5psOH)AczX0;r=lV(a9Q36FfWkD}(3u%kKdV8PL7RPDVkl&3rXka1o5!1WCrG zM-Ux)G8yDZ=GD}MO+o}6LAJhUWw0A^Cxaw_ilA%gud5gV*+3NZBw{nsGijP%1yD2) zTmOEr=so;Bn+{kNJfdI#r2`sOj0U=>E}EjED4^Ly6irh!9Zik%lVC)$Q-7VQ=jyLT z7R>R4y@M#A3Mxr_{eTKR_-50EzEW4GAt*t9|kM9~@a zN3b424EQMhxkVEZR4FR4gC@ux6i_6y280guU_x)YC&?zd$WC7txM+4LBH-5+rN7FC zp24nGRG6EhnY$sNq8JoKK^GZCcG07VYC4PFO;uCbG*F?N-vQefc>uljJkM*Zg2_)9 zRrF5X<&i59(pX@kV6kAMl%Z@3H2&Jp71BokJ}x}R}~Du^zg%P ziprprJ?IfS8L`PqsyDF`B|wN*5E10|e}`URR}n+6hlDwSA3^-4G|&v1=CKDq5?+p4 zT|rcm-Na5Z6y@}=lIWlldY8f~gCa;49fRg82j9Qr5;e&?xE0@ z9X^oB=%8va*u+*oX6xlmPB>SpuWp!7pF#f)`5D9r-NIgE4?be^MoDu85nJCU(@_Uq;iAd075dnKB3O4p zGsap~a5y{-m9D|w=kDwnupo0NE5eMXuj1=RuztY) zRQ(beekQ>fsz1g@GG34ybwykC4_)j|KR=i!8D~1ugbzS|`{HrFhyG?~(-->n2h?u? zpFz&nzc+otXm;oUM8e0`OI(-!ak}^Y7?7(KzVPkOzH?z_Qyb=1*kd>Bgx>6O;@bgH ztbk&uKAFRxE6EYeRzZ1%4t$=VZym zSd4(E@PpM~4~kBh3o3;fj7RH#I~pE!_y0PG+%?G6&8}vA!Co*{v0o4!tP&8gDj)|d zHvJgv$7YQ5F;5plL2u}h^lAYiK)~(QYHKfcnzi1O27CB0ZUu;%p;l) zg3oh_KmBF-A$)4UY1f?-vJ^;&rPr2$J>YHCfMP7x#l+i&9wUQYs zeB9+Ll6TWR80~Q0O@@96_R}pN(|5=Do2WYiW$Uo^tLPQv7qFB*UQS)Bi@FAp1*w!% zos3phojcgTD22VwRuUbhbbx@AnegeuvR>yM>cxW(Ks2#ocQW%t$RaYBQDg)iPL=+Z zqg8jz)*+c2t|VqtSFt1YJ`9pY7%V%D1IhNwk5nfTrN5pXTzl|=3e=3Cvx(mpm6QG` z>gf(^G(D2pS5SkyU<#vZOh0g=ca#c>9q>$e4i!8R%0Cs!s9?m@5AIe#b&*4qk-nn3 z)mi~*P-%B@rK)AJEB70GoJCyf7~&sAJVQ70)$El@Uu-G_)I>J}fi%4YdJPxz zJDWM2M~wjPQAFz2e-7vhzP1j)c6UMvb&IVOH!1eg8_EoNZ#se+#TBP|ErsDKY6Lx1 zE7UdM(sv#$3?OcDR?qkAzPtjuyCPP>4TEap2@BuaD*@-;V@pORY(S{7s#e7xeHPM zCvJI3Az5(>lIW9LZa6vzlxu=mD%!e?A-lM%)y&v*4fWAE=!Bg*Fhr}nOX$=MjH%D~ z@ee)hU;hofc;7}^;kl9>YCEBXIUJmIozGmlRn-dZ(JY!8I;?d1K&TfHu3_BPr!ky@ zUnQ_$SCTmd9Qp7@39SS@hY^b05nBgrz)yl#!V0~Mxm~7Y=}SbMA&kL-P_JJNmC4?H z-}>H7M(T^K;T9;ASIdoiv=4z_Zu{?Z6FZ4E+SN()I+uk$pwL0nQ=wN))^Me*-y`9g zeu2@jg4zfw-D;;OrvTKxzD6=Gw_}&n*Xd}S2GjLGxWM}L->`ncF5Uj171_#p-~V5( zn=*u+jy6oLz{O9EU6fW*9n7ep5ZI)dg%7zQ_cF#?5%_ib!VVvcm#YMJU4>cLDtY^&%xY*suv)J+e-Y9ge?-f zO`2c@?B!x}(y{IXFhYl}dsEw;#~FL{@JSgySZc?5DnP7OeGpsep-V+r`G%E?wO6JF zIRgPhMhi!)_vfU;--4b2{{!`J2cXg+J0MtuQUlSRLA>h#Tr*U_ujzt(s!bzcW%6i) zUp~aRJz-Cxw0i3@FI(hpSW=qsW>nifThly43<1|D<{`I~5?ppc?|G_Gr%q zTBp8(7|wG{ClKAXO4u*Gl)X?C=zibOp)m7|$;f68)iSe#kpfJF?`zCDjHky8;vWH5 zu>J@7X;8&o4<2%jhT&OBN4XeQUGt=P7E}f-wP*bdwR{ooRa%3natG$-Xy^Hs2bIx* zP1grK6n#6CI(F>4D_N2J?Jj2xZJ1z_H14b)jlr_ zACmM7I@o?2|5wjko)-+y&IMWs#$C{Zsur*j`Z9%vMLS?m-b0=&RlnW-749m8lkbMT zb<=jkYJpa(6{0I9jM7X#6@m`{7CC&d1ni^(-bW}()Fa@(g8g^HFM%u=vd>oJ#8nZk z89)r-_J7TA3+aj6KE*Z$-?&l4?LvGzBtJckt@LNA7L4x_X>X?%lDO)g>r`r1^Xk;p zzXMld%-RPGIMbjBtLfaPV{GU_`ioozpBw&)W*fyCQ81@lk~rtxv&8rRWpTHF-ANiK zi(0TXcnaK~XXvB6jNt7vidNy*E-IsZ07{VQ*g@}NwsPJAO%R#9C|;55(e(7JGvTp- zE7^`*S?$p#PA^6wQ@G5Jkvga!Dx7(i>x9jyVmKmnZ*r)r-Y$#Q!8Y!JkOo0f=@z-% z-xpoNyGVFt@XP}$xkbm5+n3Yr3M$PL@I^YznqLJgHQ+jsbugH*4vZS#X0R$g(se<` zg5?3rZXPrr8-B5AQZ>ZhH=aODg|RzJodLhmw=S~uaKlAfm!?y9y9B&8tPa+~VOyiw zU4~sXBGCisO;))Q763&HMx7A~y(GV~HCvb}W=F%QWImgHC0Q_Hz=5&FN%GLkHKHTZ zD~mm$RxqNuqPYTQZjXjF@QPIQ`3j}5?4)uN+hEZSW{E=(E>bx!*#+bFP0Dxq1r@$T zanC9CcGlgBk~NjXo&#PDHPUko9j2+9ID80B8MrBBTB6$d&Ev$~e0Fm+yiADbWoAwL zn)D)4dASZ^dB&*i7gk$El25SOAy@kTvtJtSu}=(Sus4jMLt9{C#`dHuPFX~bre^Rc z1P(>;ielwpT_q9+1$(esbBgf{x173Bjm7zC3Xv zfR0v^r%%7XVuC|5wO!4-^`ZF@ra2vyu1@=^e_w2xezQ96vt=Z0!K|WJ6TOtIDLP7n zkEz4;icmM{pFCn1l^hynQZ5cm#%NKkpc$jtk7CSZm8#&^C>VnkYL#k>1=U-ffjR{7 z12o)Gfty{1Tuael2epf;X1|(Tdg;@Ln=FloL!i&|1L`+FhMn+LnttYHZoypxv9Zd} zORT$~66%4W_Ml%zOY%KwOyeqt?6KGTpj5-Nl~T=9AwpHa%faIiAYd}n73(YiztO_g?~NNXY1wf*O`x>@E7zF{7_pa-b{&S5r7@QQ7ri%D#o?kGZqGg4F zppm89H=7>Cy5Q@-;5D7YY4}LS*u=jFGdymNdj{&c3-l+{nYp;%*&o4p1$^oJ=N1BZ zE+L1{<-dP*+(mIr4OdQTne6h!FWwkHHJSBBWU_9OUWZz#+06&VFI)Fm+6ibNr@ zgwjcDBU*)rDWyWCe50cDp_lV&!D|VLsV(TZ{a!T08RRn4)vV%X(KYnKJeVPZ$Px(! z9J;4zZ>hq`e75$(YxS|BZ$&FiBQi#~R;d@{v-qfH@6sT(MB7qVz3l$IG7ec|Gg^gKY@>PwSwcwD-=WQ?>{1%5XnuYu_wO{&=F$6PGG{S=Gtlq^zVs0) zpngDKiejA!8Akb>zef z*t+osQN-41mdNl#Z>}A%Len|l{&)lH3a>lfWJEOZ8E)GM9fb3HVV+wxOy&C=K`r&t z!z9Tt(^cr3Zu;I^!D^UJoND)mdHj#r{MzO|B;+dQ9>l8{t?D@Tez(M~mb1z%;Zhy6 zMI;cPVBeihx$A&pXY=!dzkV3>InO*pT)b=^8RW^!*_3$_dl>A=gY&0TTtX@Wm>fl3 zDtL3kctHJ`zLJO02CiX>H=8RFeHoBZ!^bR|v;H%#Bo5|9!trpg8T1L6-AAsf-Mt`V9VK7fBi|E=2_ zB_=UUc9(`mhaEL^2!b}-!llpHx-FNLEK|i7;rVwgJ(OBxPM_7KuERKc3>Bg^R1}r_ z!r5?z63vdh`{>!td^KZ>^QU~D`sI-k~U$eyBmsZ5j}!gxx?)FH@XZjGY(cn`Ds+03V@;yXNh zv34b-XPC9NV9FSbSRz17AKK73xUOdZ2;##zsT7_fLIq8F()FAF_a9Kdihd=X%T;{o z^jWS{-LCj?3h<}PW?VkCVQ82ldU?*U$e2`Zf03lvJP?6$E`@#01hHY&sd%9~edB~! z&YDb`StrkHDk&hwWA9h+XFDiYLp;6wG*=H(&dnzJYX&d3p#s>(T>y&o?5@e|+^EfF@M4RRT+$DQDQ+F}&98`Y zOYrD494uPf2NzutV6)119(_GjHXg!TTQEAr{>i=hdT@Ptr-%f%%u_S{t8yK@byKu9Ku+=X zj;`-Ow!h*VVbfF5?jaVDYk_W)^iNpsrfR6JNvuUkA%^Fc=e(mNEAA=M(H^L)()=c> znC5U^G>q%(37K^0V2WNnYy7k2q9_)1duwk~dvC4h5R`(59tM zWRnIShWc}#mz^zM{SBLLx|A!ghnj~hwPkx-=k{7|hvGkx%dHo_OB2DpCBypb3C{@n zl0Hz%=iou`Ig;O|h?8L?`nB}Zh31RwxsUAXpTO_%cr+j5t@%@#QdD@_mLAQT5qwy? z!Qdg4jp*w)GfF9OhgxcOzDYO6FFMCP5R(kcAwJW@Q_m9G<9jn}g64B54g9@}Y)w~j zN}M}3UkP(2{Ydx>;-Mb6Gfjj{@zcu;o_>FrZ1nJ3Bi+rA&?JIofd)hT{Uh9nJXp3K zU_|?c>O-e7g#cho$VQY^fUV5|+9A*?b1+_-L(EKd;wS(n>$;da$_!00s&0_}n z!_V}uW(;`lW;y&nXS04l{lkUs@Hn>nPJ>6g(+1C<4t){hEh7_z!^0Ru#x|8*FF8#Z zxWT9r(e`jP6!G$IQOh^IjJb^1Y}$W5Z^g73#Xkc6HQ?EGi%(v_>{-f@pTU|%W-wAs z>p<1}8Q%(o7r>llh__B#SrCKFX64|ODrO3eIy=%>w@$dYb#-({H}D*mq)iuAJ3UY- zrIt2XBkDb3$a>S-5192D@IM?{cf3!$@%^h635FxpbOAS(h`Jm2ieg{EzD(rgeSpd@ zeYmp<^qszr$itO7x1d}yTiTJk$Cfb=ey-=ct5D zWSLj1W9Vcd01II5N0ArwSQ1jiP_NxXG%R!1YkRuC#k0%hm|1yP5cJed`ZaLXne-5V z5g`x*>kf}9hiEZ-4quR^XwXHBlDug;L?X6Lzupq^n?Jb)*0iNsUkU#ndRxmA#_HrU zOCgOdR0LxnU@L{kZ!?9rTi1Q$$-Kof`q|~Q;(y%DubyH(=Mae0N1i1xD(sao`bc!c zYT+|s%%iFCK`5%Gira%wo)=syN;@T!TNICoTUPJ-Q>{J4n4zNeOGHuWCVx{amJ^G* zVf0|HO^?Ae3K%VJU9?p)b=Whm!TkGc1b*5JN0Q&!=YsdlCDh;@r@%d z=!HqhsL4~!F+wH|@$waTHe>1U^BY1~L*Z_xip-;Vcp*=M;!R`A20#QCBeX5sgkjXT@f0QatW>H}!sRB%HL#1Zm zr04rp?u8L+0v zZ1+^J2!3IrY>bF#hpE=`0#e6%{{)JE&I2c4>TuQB*-7nk*mSOBvE{)`raS7{rTVXo!4N7-?H z@1$6Mq2;;&u4P8^QShGex#@P*OGMQUg?=<~#Gj?aZqxgl8lA68s;&r_4-e*^K~0$X z8N@Gr*<9bu4mucHE*4n_&@fxg@|Gu4iD-AY&}m{pgrF|HG6o47)QtJ zNN~Kx8;%HNWdfl?Jy>=csk<5aYuQ;L_h`hIB!BQNxvNt7{JFc;vXd(scXTr7&Ne{5G0@_T=w#6JCZ_J@l$> zUiP(l)R1C%CgBdFQs7b=LXB7Pv0<7XCrn|Bku!p)PkkaHOmC}^O;L$?RF`qsMKm(6_q=TRG^AJ`QG>mR{eDuDR`L-a>8N)aOHC zOaq|9E|$7irbvBT*$m6i{@E}xc!p95M%APvP}tvVuy)WNFn+?mh8;P~h~6TCR)i)0%xxY$~@8p$@={5O4odeydJ$2#465g3Mh) zy(ew|D7lOMvIk*dDs?u!)G}@wYS5SL6}8R#_!e3jhEh z07*naR3q%&y?weJ2^(9Ca%YvA%^!Jrje~@?@d1B!UyF3hl)VmaB!<<^uCm!h`{uVT z;W}>JMW&+ZfrqgZWH!v`LB`S5)vbVG7t0dsws%`!YAIAsx~%IrSAAL*n4akEGJR_6 z5ClVXaL?k;0eDMfj(k9}s=eVW;O~^VRM@vCN6=$P>z^%}c-1Y#4$s;zPw_;a2wwKk zsfK)d@>#`p+sPJjAcxyV3p|B7+8_(T;pK{}fIq)+sb>UxTM)Bayu}^24x(S`CSr-Z z(0g0dTJEii>DM0zx;C*z<6hVi7VE~XwcSI!!7&e4!?r&a^hzR*;g^`l5|9=%>mqB} z)&w4-Ji1Nww?n{5+EufVJ4Mt{zpCvUb`+hZAxRC*;a?>w*2z1kyCA}ieciRdc^LSH z)NFnNUuBTW7H~ZWwQU76Lc)s}^eD~FQHaI_&OEX!G2K|3n*-P;a?~nh&!O5R;~m+e zE&mEj+3h|Sz}JAM(Y_JF?5`H}JDktwmcTQ&iaOHtv291t*u+(a#;q|pTOs32(D*K7$(bVp7Rq9H%!TnvV#FRSz5E7#OLL+I55l zaho@FBbE!Mjt`-9(}qYp!kU2iHYeWP@IoJNoujB}p2$~Et(hJ`-#=60klwP36~thi z!Kok)N57hB-`+0I6a34av|jF3e;iW=4Tl#IcJMmUtEa~DuYmvQV4F4;6-*OLDM{yN zOJSwXs)XS$6--s7$T*w*ENVy>k%wk)lre1M6D7cC4;#mgpv~3jOLfjj!BgEy*I+cJ z%}M)lP~Grhn4^Z-F4h3_BvRVCGY3DCm#1R; z8&z%ybBV9yf_> z_r;z`hjIK!YA2CH564IJrgzsA!7}v2MmDdhp7z(PEpd9&#CN~zhPH?@rv9DpeC4u* zTJ-HBY03AH*EtRUuoN_n6d( z8mWWOXY48y=1&uQi)Qb>ef(}?%&>;;t8WaiZ2@7_%Aj&+-&$jJr3E*kpeoFAJz|gq;ff#s7sTW%0O~Ee)qh-Z^r`dXQ2#)9srjW>z z^Touo`Y`7|{qPpai;|gu35tqyliG1+TY`m44vt-^=Acy_4Bw0(_=sjj5mOZLebh(~ z;Scdc6G^6!$JiS5ToJsi--|ACrya)ZS-g+wVZW)82@iuT$=h0nHUnu(#k(p*9yzs3 zg$mXlnk?2ag_a$BdyKI*{5hmJ<^W$Qys29reHqD^1+Qf6tsMS>c=c^q!8dw*hpcyx z9nRqpjzg&%DtOmW0Z1pg_2MPpA12Knhn8pro)BNts2N% zo*lQD#BnD!t0l?<*L~yOfvWVJ!MFt6EDw?7%+btDyLOq@R1!LTgbJ-)Dn@T^JI5sY z&~f5+Rwy=e37Q_fU#1|GBzx@$nLp%$9A<$*{g;&CS**sEDd=FRsBXw~u(d*QT4k`w@2CTDgW8V6S z=scb;M>+7O0((x}xtMt#-qH2PGCO$iJiR8vbLb&5C~x<#WY`Ob`w#DJE28(joCr2>$b2hJgsewXublh%oN0)eW4qOTU?!5l= z0);diS;grh7}hVAWmepu=lp(q;JMYOikv~dlK%4i!zPzW+yK`(*PTh%V$I-RSMdCV z_&unp=%zYG1FP#;+}zV_&r|9&_9pCI2DMCb$qj4ER=-^R*ErUA&iSF2E{F0<9!ujg z$mWO}CYHpwE%^lLAES=rF|$qz_(tuj@}>#iu!QN_yU%3I7s?!VLR&jjhLEm`12o0|8d$?&E_dUJ4X4~atZnD4 zH}QvfPjOpe^#GOj2FPezo#^BqmJe-JOe$}Eb?|H45>xf_ws#$M&uL7I+}h7$+koui zH@koReTFJMiKusrc<}Fhn;^&xQu705z^8iWdJKo`W<&}uenJ0&{MlSTH5kgDhHULk z{rn96{71+RpU@P}mUVFxHp4)Sh$0&Gv=6~@Ix&`FwQokUM|qK!(8?ZIL!oH9Wa{S9 zd+NsLG~dz+qM@!p)&}wRIIv#gY%m&?w_(>*(cpXQ0mU#czRvjGEtIO(Er-w(9HYI> zBFv2s7cksUGU?0$2qOQ&2yE{2`ovwMFdm3Yo8AZ9?ewcBUb4!;rUwiye$Y)O-0oIqZia@=8-C zw3{hyN0wf3GqcO5!XSvJQu`#Z@)XU}zUm`7Sk{^Ur+TJF+~ZjuA?$s@GmZUE>|5r) zFWbEKv1^w-UDzlv&jKfcA5r4mjnf}1l+C+L*#P7T}fOn=^#4*yKqDwOWxD3d&d ze>7Z=X8xD-`ur4TksF>-EQVOWAxc}AxR}Hd`tTqAEp-eZO|UtOH%dfLZEIN~;<9Az7eNnE-YO;^a#GC~-% zj21gY(rAe^PFvHVR;OLn%XeT)g6#!KmBFu(#Iw~hz1&b&+PO$>q6`^J^w@qdKEaMW znVLzYi^}lxNOu+zPMS-9ne7{S;~GZ`)ppJh$R(GO;|MldRINwY2Vg>cLOh!_u<1H<4QKu!D?Af1mnydh~OK zQ4aN~-HQxI@02&;@X8;hd(Uhl&VRv;PVFvPm(+0zx5v+tWvn1y2_fjSH)pAOwRLTq z-L=>8`aRRb(3(0AO@h=eoE=_EqZVq0vR<1=nl?Q&^2v7LbADKy2Re@Hs7V>|&8hHa zQg|s&4=Z#eG0N5}7;Xv2IXtIH$`U8w7RVayysb9Fx9mUqhxgAj&hp+7;?JJvg-YT* z9RY6q#b(@H(g!9<)X>duL{i}xbbIaJS)w^Lbv!Ts@REk%=9v_`%I3tyF(se=2-}5N zS8#RRhK7>!$z&;a@f_mZomqbkh58sEczt7YJLoJsFxnW6PA z!>ji4fEfMF_VadEJ9@w-)2<)W%QBA%Mp>CvZ(RiziIV^65iFnKakH%AMm-N@tQL;#i$(*9LPLzJo6=%D^{|=DQ~8@2Q>8*EI{3=;%Th>=EPDuY^Zbvs z?7=#_sShLqq zChV=Kms@Ldj0gD-xYy&94V{j-R1Ze2U|J9oJy--EYf$+%mp&;c`uH=~e?|m0W7oIs zCCk%5L=HIXPF};t#y^TH<-pZX;IAdY-CuPtIV`+x<^mqcdI-a>tO5V zw=*oony>~uCah=?E8Yu)?u8Ov!XeITSMlB6j^no*#mV{Kh9Q`bxNo-z?LQDp24PI||%d^fzD{~t&FyZl}hAlE?MQBrI#$9j)dAF^2Xx068 zFkzL~vC5cYmljQ4E%8VYJn_DQsXlv-Al%NjRc%4rsZ><=yumK}7VKlSYlG}qas>C3 z^7#0_5}WkvNTvPW5A+ho1&$2t_yfo8_vW{=Rlp|N@;Fw}*S(poTUoi89h*Iiuc39M ze7sMT3JZxAv1)61tIF$fgIV`WtK(f;!N>2&?CC1|PdYnd%|Gb-Mh}PRUU7!U3T^UIr!$!+N!fc9w>7~@yudP5i=-tw8I-YvfoxPXNYu= zx&EfN3-@Qkn>VgZ=4|p)0Dn9@*LQ8yxxMP-05ti{=-^-z-@}G~IeOa2OaFKY>hGnt zvBF!k-tNLSp4hioBE1LcY~nu5;F{WsmYl*fS(oMza={PA!)@(Mt$eE>y~Zw|Z`nFe zz5K)bpSL4w*-2etZe{b8@M{F?JH_iPgQ#I642^cj&YS8kLZjW?oyuKJSaPQHDdzWP zvq_`AJvQ^#D85X@Jfq7t#2NeBM(_OQDVm5h~g-_9BBm!E|MJV3#-BO9>}Q`EE8M(HLGc9h??Z|>%@uAxu#(B^dOK?aer9~9?nzeJ)Z{xmUg^?zH>~C#FOrLc9gXEawIw5a) z=+&+}M4rWx`#5|aq0*^Kj6u|qcGtH<;004`iBfL=pKNkZ(=>}Q+H%Fx8-QNMLuo4{J%ysD-HqC ztCQD}TI+$#!@_g1w}-ceUgiN#dEv~$%c88-ZFvpI>1y93ka?Q6wwW>JFz&o_a=^pG3)FdaJ#c^{hCjx+tVOZN~(vKWN3Ma3`i>>Nm|l*}|LlQa5g3J=kyn^}3MKSe}a?sw4Z7*+elLCFT;}W|Iz)rMeSU5(VH91m$qUz0X-|Scj%4`zr6=NDVqjNDM|kfz z=w@s~@2#Cethl25j1Z`z5 zaS)&Sj|dh-t8|!`=j}sdsO#IaDAxv!Pyr*$I%5#=t=Y?&!n-E!@*n;$Q&pj{_rg$lt+Y3`;` z!3Z&O>LYmiXKQk%(r)lh2cyLn+Q;pDD!a^hTN2s*nf}m<_jo1sk|SArhhKkFtR5>Y z`a22aeZUSM@bu*!b zJ>I(t_-OVYLH{Aw)4UXs!Zn5RnG8W5c2S?7BjF*<+_0O4s9JSPlvcx+*}eK?;|A38 zNVHELv)*5{7dGjVeC7`K!3eAszCDc@DLeF@x~~>JndIpX#{{wA>2gydBGS z!ehUwho>nZT-e6(A@J~I2!rUayH*m_(d}v7o74{Dr~D$kk^9~p(%&|w#@qcnJhe=3 zNB0!7hry#1CH^-t(s{igUs{TlwW*lGKm6TC?0eo-7TrWP>$6#ZXuh%^o?(o$&~4aS zz8K}|qeLG0q?wOMW)$NiB&kAqx=@kvJou2+FW57`O^j4Av@H)mmgi;?#bFZj9!~7d zd}3xof$17%W>#ut}R-)LzqqaXKEC~ub=ama;oixZ65C|JjOK^; zX|PW5t!?Lvw0oY0Kr!u>I-34nH@zP4nsP*Hw<31^J=r?{PBA;e+&8n zb4X}WB|o4r#9UtV*rhdSVGN+%l2sR#!Dy|Znf4V3)6DZ5gXeQ=ukQUmy}q`P=Wp11 zNYTd=kR6VMnlF?ImUsPdkj@m%{jAEVkY(f;+xp1Vzy|m+;MKC5E2E%i+`n2bYk4V+ zCGqs- z+D*K?wR;^pl_=zW*2?bkL(~vNTgoB?zz@01g#Xj_BPrfZlwtrk=>-uWy3Hw(u zj)Wdnpd;dlP+GpI5}yli1_ z|N7$#Sk=S@Yc!7u^=Rs$D5gsxv&gH09~1W1i5>!cUQS~@f_@C*6Y@h*puOkeMe-GO z)5wq3vQ86pYdei*ngJaYbG*D7_8?GaHOa&NKl6w=adPI_clKv9zo4bd<6Rn zn@F2;aN4Y`MUA;tDF0=Bi+a@w#_MegukdN#fkq^_$3`yl{%gFRRyB*L z=Cjvf>BfBs&NS|o@Rz*;I=E4=Xu+j9y$WG@oeGk7XC0IZv+u+_4r7{qHP1_&f<5I3 z(#Iy%EqCpMY)UtFZC!_al~71CmB$(Da!-531b!X!sU{wlTzju!p(^`0ndWz9l{b1s zPOowoM?fQ5+0`Da7s@VQfvXu8ds>exEDglfUA@WIEY~uKm1%)zdMM1 z#IwWd>}Yp3>8)c44zS;^aF zs5jE;*ktq4A36m2Tq*86E^4t116+}5s~uYJqAYlc$lQ^e*DHy-k((cr|V? z&}P|Q;@LMZ#w_ZsUGgMTUd7F>B*%Nz%b&oX=G9lf?J?5-IYU}_Q36Vs$K~mi8|pCn z)-6Ara@hQJ!QW@M4*gy&8 zt3Z@Ox1&**rz^uH!?Ee*R?NQ1!FNY^tnz&T?uFS~Jc5mE^Y=)42yN6xv*MX@{#>K& zS^T!srM%y#oAFQuDAiTm*1WZ$zJ?ZWAHl1?S2_&VYOlA|HquK_{s;InxiVb!4#TXY z&_aflj4Gx_(rxRvK6`?Pc?+rWv6f0W^d0dha{1~}_kO?fm^q?l963ug?2z^CF~qjN z684C^H;J(=qw{Cb%KNsAO@p$9mQ~=TS6f^-9xJJ-Tiw0yZbS<>tTRX%S^dk@xU(Fq ztWVs#nYOt-!vkR!LLak_`baN+*t3Yd*OTeub<@bQvYi2lOSDP#KW)b{)!JiMWGWXil^r4&^uF@=G-h6_(O{B4>@nM8y zwMU+=+-Zf&d*%H(1a8x;Al9}L`~75450s;mcP+Gq)yGlbe52oo|GaQyNjr~hcNoi& z?KYw`1|kV~5-;<~&(1@WMzfDPTYf_u)60w7$uyT&&h;RB!A^EBTf(e6f<+{e%gZv% z!ig>7Z0O}PU{>w_udB1$lHd-Eo%qhJPu^OB=M#KFQD&PdlDx+5nmxXLqTj<;os7dL~h zQK@Sv)!K$N4eN(CikG$wMlg{FSKYLXorGI^s})-&XL%xJL(8CE)mk~HQxd&+D#us( z$eqk?zB52D2Jq0}^!9cVYtIyR@O;4*aux{S>IX&4M+;^kaZ8)KKB}R~X%uFnRCRLi z@lzW5Z17VW@@beaQ${kq_-@+zjocHbp<@=4^X$r|ZzTg2v+z?t3o~o9O_Y|ydf1ld z3oreiHkp)-4{ipzkICj+@C|EK?u*kCzYA00*xXgvRx;v8v6!r(4FYI18C=qIf5h z6)Vk~8Nr3ZFED6gg=@SjF{syeO!xl3J)Sv9C%36q$agKKG}2x+>EUr;e9*=<2hU`` zwPvoQGwFjGfPC;>Wfp>C6!rN0iyi(j%v%E^4W*`Y=+z5f_cy!^PD>_H6;FX2jErAK z_c7QBMdbDv+Jmk1)2X`{4$Kb@-OLJj(V%)QdLSAAQc6J$U+nE6>Z|mFE;I|60aD-F5(8RF*1<(N$ z#+iT{0~qSTr3of`>kXgUX_e=MsW&?mDlwBGk-Yo)Mb8Ypb5M8dL*kRv<{bL#l9f%}QIl$9OBhd1Sl0kfvepHkgUse^g}Zyj=c^_MRQ(goySz_^Uo?y00P>tnU!PaQUI z_?-9{g&zt0Q%xH`sFV`NM=K+CT{*-OAXq9}g1!?*oMY%u+@SOzbFM8MvcP!3-F(Sf9WL% zI+_5TqVnDDjWgO88v9&Bz-T4Jg{&Q9x0lkl_i)<81nQhIk| z+e;e!Hf>COMdNfVFMVV-c)XgN>a&=HK0kr+Dc;~0zW}C;1M7oG{E)@2q%&-P@YE2@ zrD7hsdQ6eI*#S{@zIbadf&QG)4?wr5lbXgke83|2atm6rSfnIh>e;nWu@7wuT{=LV zKh#q*dS@I7EHQJSurQJj#P=#hCH|=?36*W+u+-du3&?=MS8KarfO;v9m((T>X-XVZhM8$f)Q;rFEwVj(wcpHuAuq9Z2JdfINm<3abV9p(-LGY} z?OEI{HY6ZWs9eBtumR9Nt{`j?0!w(ZNizZKg30i-8Y)o7@!OdxJiJ{^b zw$Nm0z>>*nS?0hMiRF{))+TFaKM+FMY~Ou*C9zclJIKPg&aLEU)>Ulv#!I__Y9*4k zuSmimIQimL(@0(~#p&iL@-jN-fR1RE0Rl^=Xky|ixsY`nTTgh=3prgs(Ad_a(z~mp z&DkP$b`baD3`ZQHnb_8X>qAkDS(_9LrFJg1LuOPWf)Bw9td?C1qf@MeG>7A4>GtN! zPk>&j4a_R6!I?!Cvk49}Pz2Ge4M%UOdLZss5SpD*T$jk*Q`@Colg7t_BP%Z3)SmE+jewS96ScEMg3hYY66&! zuH{sF>y4hj(QJC-I(sUx8OkcGGNyj4zUq2B{I-3Qv^z7mP_;dcAr@jE+1|k%si}m1 zUze}ZYVeBGX}2-Edkop`Rw+*o)M59Drr0eP*>3p+ikBoB&w?{$lj^;D( z2Ouf2&I4*#APXo}xz^I1*`rPy+>~KZ2~?b*HQUEqcV@}sMsOatQYdpVXAgz%DEtaO zY!0J`zL((W2>3(|=B3%B^0%P0tgB!j1^WPE7E)kn!@#h@lvvfk-h1T0g}|#Ekx9+| z_SyrH6E1Zxx12^1#una$9;ml?doN^2GCuV0EOm07=$U>CQ*Gcr0o?w8U5N#5NLl<#2it_QcaYmEy8+WHqJv@Ppnjkc)77aYqAwWP!E!Gv=- zG>UJCML(IkMvU$t>mE7*bLQ_1m+7NqC`sTOfd58eiQW;tz)*C3hbfwxZl-|)F^GJ} zqkwM)yQrDx%~ZJClxc<#a;X8W!wL^Gyn?^0t;MRpTx!|w3~XcLQmgI3l_UfULd&;@vVn7(DWSLAEtKw+7*0$( ze<#YI{zBm=>Y!g#qL+dY()7m9L=GqR{hOm62ESZ_Q(fm9t1WZ+?Y%Gu@UJW^CnkQil5AHHfvSO2gh~iy zhXGPW!HBkgOG4|<4Aa_`@u}_GqmB>wD8rZ9QRLa~MNW}ZnTS?$5|tAv(`oA_qYIRg z$YZs+0XQ6iOn!br@1hHo949t9??!sSB0i03~fry*w1Iwvoi4QJLFcsb`*Gwh_kTwW-4o$#D8p@VZO*C{$ zmop~uaKj1()(UiOb|Z0-JG5~)bO3G9OEn`|s8=b8D@Xh337qWXy+R3Kve`LD#TgEp zq>wlFk=JRL5iL*&uBRnUvMMRB3m-*_`?GzC$BBvIM`YBF-(ybjAiddeoPFl3v#Ngc2>a80a45y?_VPQ3$ROfqi~IH#s{M7_ixiySwC5`I6DQ!_n3HnCAR9fU#0k8Qz4 zTjR$B9yjp2^OZCX9V4d&{6`n4zq_i}hfni2>)fy&& z4wG37=QJ^;vRz59gdD6y$ssY}Bz@FHR4P}RDt_KfAqReZ(x`XLY4NDn5=!hG_NCK9 z89O-0H8ZT@8_mT>;kLrdCt|4bpM)gE1n*#h+_ygm!Bzu5+lMKxFcFMubr3^GU|DOZ{qQW7+# z!c1Nul7$U&a-jRHii(^P9m~?T!sZ|(_jN-R>-*FZ@2EKw(S}FgCH4N2H{j_MrKV9h z+7HwWK`lPGeO&s>*0N)(T7LKgAgO$~hBd~}i;@O!DAg03fK!q+`Q*}5Ap7_*87*9~ zHEpJlNoAACq^$A6Y|)Ge>Ek64hxQI`flRV`yq}`Z5qe|$SA}vBcvJoWK> ztp6GK`et}eYU$@E7jt$M?B78BhhuN39`OvG@<<6e3lkG`<~onLSDBfvgu1Tyh!qt?fQ1#i>@>-WU728a+M&s%nXu)2M0OSVHj5>J`K!9 ze4IKF(X)->71V;**&dgY`9-I#2g;_#x&&%Iirgd{B!J+m0-*;@Ub{K;;eshC8v2Ax=d_BuJ=a{LQD$Ma8oOEjM zFaQmdU8)cgHiVG%p)Wl#f(hUw^6X00nrwQGu`F>ngp|NvMzo2AE6nlmcFa2VB{2hn zAxVN>e4^JZ*b7@yR29n0CB>tIk}OzE9#_7i5!;^^g z^L2C0m;I&3_Wwr#k%ku>&%uW!yePOta%^gIPv^Xs?d`;E9IOghJUBM)4c0X3kp86!J-`9lu}oxBJsr%~|XVmYa{ z7-C7L;6%R`kKrhhZo|dFRh~}rEw!G2i9BUmGSFPwop=2|4L1RWHk6B7hL=+a62TxS zU(NoNwmt!~slBxn%H8ja24P;h4rovT3iaY0zc-sHF0j+DNE;SsFTWQxdALai=iY!q zR3>rZq;l_8PF;lwa%pG4)U`{wK8wo`51_u$I?vI8tmo>W=QPAmL;ma)gBDF*%x}7U z>pEtEox^H3wUCoa2J2;B@A5rLO6@kZ%C%^r+$3PGFuVfzH5kjb_tNs8`Qnm;h%vQ% z-9r`c(I!><=GnbvvZ&|*M0+p8x*%n+iDYq{G(0ii5Ufi1gvH706TQodBy1bDvkbio z_9{j;mn`e1902`uP2fLi_!{IHAv$>44y_yZ=MYA2C{*a@TSs4y-gv6JK+$+Q0DRKv z^yv9Wz1iI-AB_6Wadth`LYnFV6|7viVJztv6kusu76HK(e}EcIot#Wf zZ8Z}xR{%fFu<}jMpS|bT@+Ucs>kk83J2ISDJMiB9zC#Es2sj>RO-Yj|!OYS2DY0z^ z6eeAMOdUIo#9`Jud*$F1yA>~k4~9ASkO$_d`$lAKA0v$OhPzmM++Hv(B%D3~x_+^O zBkhQ7!0a#VX@!>!Dv=}z9o6DYrHA%-8#Kf6B&v=n(E#k+y{Qa@-!gdK^X&Ouq(`=s zn)FN7?T!t)s0UED6vA4IH&~U>DOxe`5&XH zfkp#6nYL(SA(g08frJ^N*_6qWrF6jNqUNAm*UXpsinqHe1$M~HO`UUi6$mzk=EeZ`i0I@N~)Z~RGUb? z-Z8b5%%3fJp{8v_cFwHibU$^ zurH;WH%zGotj4>NQ>#!H(uTS|tChEtK!KP$cPf{|3r{b+^ue7Eu$*Z|`hQ*d# z)e!ZpIM_}v#7v$nJswCqsV8Yj8)~t)yjo%p+o@tEzrbi3i1Dgy@3?7xZ9UtM{3A57 z-3j~#6=nNQz?L07g|qo`VAdr|lAS8p;kpHd6xzM@?8})!-+O6`k{B`H`enm1 zM`GbN!>fgl$32NhI%|0`=1H+a5ve;q2# zldWZCO*A?C6u@@N#=Q{-WEr{D)o7*fM&dUQsSYJvMewlP1vqooF3F`^gRe2|bgF5_ z`ryMQZm_q4g%h|c+ONsQ@wezx zJ09q&?Pe}h%zS4VcmD5=uxX^gVz4t3pKiFl6xqW4yRYP1j|sUTs6|i>l3Ve{nSwiG zcI}bKt6xOlOMs1?SAb;Y`SMxHxNK#UQ@Xe0(X7H_*EI~2j^zOTRSi?yTYY5XB0LAJ(U$e@vv^KqsETb=Ua!2irqUV7`dnm;lbU%e?qI7O8WI0|{xXf`&!sg#N z*okk%CR(Rz>ie8Elu*a3G*@>vl8$9-`cDDJsqBzq_|LKKbYkSQWdqVPc(!aFTjW~e zG?GBJ5G&zRISfsYZsQP$)W3#fjxKWQ;8BKdWyhAh?qLavDV630`(7AV;{KViUx{3a zmz1h&4y=((-9{km675@gx{66-a+vMS8c%vTfcpe!9B-bM(yUO!u&i(o(y|MK>|S*T zHK>bE?K_58{Pv<1Y^=n8dEuV{+^GbU4qfVnaQl3IHLDp6}nWvsYdp<57k>K;48DIWw!hAY4L&JFh--9Z#oyebfKCB{gsmAZa3 zCQw^0U>qK0m_EiIY9DWLxfv}{c9vlK=t$aUj60hHh42BYxrSAP(J^l@> z$z_LY$Ye`u5B;+M$5LYUI$W5|hmrDEmbg`p=QQ@UT?CaOG}sBTg0ee`nDC{115Gv` zMkmd`XQIk+4?ciP5iIx{@J|xQhRJ-Q`T8uDhhwYxcXPTidywI_kVwU?Ib=Syfly~~ zZH~)PTlC!FLm7YNg*B8eTA{q?5WSSge+I>#v5HjEbwHNg5vJP~j?Tuz_!d8mJxH*| zjVojs*fR%i?L^6(pz3CP(C8O3MWj}%s6eg@RyWx{FtXZf9`D;8A$K3%!Hn2>JrGc_ z3Ru(eWkI-tOqu-uh?q?b%q6kuqWjqwr+in4B&x;Ne|h0I3~O?#c8@}Sr_~HYZ;qR+ ziPTK!w$PD{%|oD_D{*Ob@Cxh{mY%lIa_)Kvq_U9QY_IZok)Q)yuQaZ*SEFh*s8UD= zSJw5p|L>29!2tMt%$Jp1gFM}evB%oTbL#}kV=MoxvVl_LY&*y_sF zvowsG3#?HC(^4s*2ckR&@Hv4mXM4LooUZCYEl4`8RS)e3P?ENz6TPVe^J42bx5tMc z>x!;{0;oxZz7-u;Vh_aN&c0x0Dky@uSK-5x^7qNi<8qF>8|zt?JBt}8+}g^v8!dxV gMoYrLm+F-N1M82l_OpCl^Z)<=07*qoM6N<$g1e6Q^Z)<= From d9d84bd7b2054cba16e6d1ee3c7110daa2a82d4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 21:43:21 +0200 Subject: [PATCH 0191/1812] Remove bullet raycasting shapes, to be replaced with OSG ray casts --- apps/openmw/mwworld/physicssystem.cpp | 123 +------------- apps/openmw/mwworld/physicssystem.hpp | 14 +- apps/openmw/mwworld/worldimp.cpp | 4 +- components/CMakeLists.txt | 6 +- components/nifbullet/bulletnifloader.cpp | 123 +++++--------- components/nifbullet/bulletnifloader.hpp | 5 +- libs/openengine/bullet/BulletShapeLoader.cpp | 5 - libs/openengine/bullet/BulletShapeLoader.h | 12 +- libs/openengine/bullet/physic.cpp | 163 +++---------------- libs/openengine/bullet/physic.hpp | 22 +-- 10 files changed, 87 insertions(+), 390 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a1b37a2757..14cab6c828 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -519,58 +519,6 @@ namespace MWWorld return mEngine; } - std::pair PhysicsSystem::getFacedHandle(float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); - - Ogre::Vector3 origin_ = ray.getOrigin(); - btVector3 origin(origin_.x, origin_.y, origin_.z); - Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy(); - btVector3 dir(dir_.x, dir_.y, dir_.z); - - btVector3 dest = origin + dir * queryDistance; - std::pair result = mEngine->rayTest(origin, dest); - result.second *= queryDistance; - - return std::make_pair (result.second, result.first); - } - - std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); - - Ogre::Vector3 origin_ = ray.getOrigin(); - btVector3 origin(origin_.x, origin_.y, origin_.z); - Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy(); - btVector3 dir(dir_.x, dir_.y, dir_.z); - - btVector3 dest = origin + dir * queryDistance; - std::vector < std::pair > results; - /* auto */ results = mEngine->rayTest2(origin, dest); - std::vector < std::pair >::iterator i; - for (/* auto */ i = results.begin (); i != results.end (); ++i) - i->first *= queryDistance; - return results; - } - - std::vector < std::pair > PhysicsSystem::getFacedHandles (float mouseX, float mouseY, float queryDistance) - { - Ray ray;// = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(queryDistance); - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::vector < std::pair > results; - /* auto */ results = mEngine->rayTest2(_from,_to); - std::vector < std::pair >::iterator i; - for (/* auto */ i = results.begin (); i != results.end (); ++i) - i->first *= queryDistance; - return results; - } - std::pair PhysicsSystem::getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orient, @@ -600,13 +548,13 @@ namespace MWWorld } - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool raycastingObjectOnly,bool ignoreHeightMap) + bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool ignoreHeightMap) { btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly,ignoreHeightMap); + std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); return !(result.first == ""); } @@ -626,30 +574,6 @@ namespace MWWorld return std::make_pair(true, ray.getPoint(len * test.second)); } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit) - { - Ogre::Ray ray;// = mRender.getCamera()->getCameraToViewportRay( - //mouseX, - //mouseY); - Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable - - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::pair result = mEngine->rayTest(_from, _to, true, false, normal); - - if (result.first == "") - return std::make_pair(false, Ogre::Vector3()); - else - { - if (hit != NULL) - *hit = result.first; - return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable - } - } - std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); @@ -712,12 +636,6 @@ namespace MWWorld mEngine->mDynamicsWorld->updateSingleAabb(body); } - if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle, true)) - { - body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } - // Actors update their AABBs every frame (DISABLE_DEACTIVATION), so no need to do it manually if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) physact->setPosition(position); @@ -742,14 +660,6 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); mEngine->mDynamicsWorld->updateSingleAabb(body); } - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle, true)) - { - if(dynamic_cast(body->getCollisionShape()) == NULL) - body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); - else - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } } void PhysicsSystem::scaleObject (const Ptr& ptr) @@ -762,9 +672,7 @@ namespace MWWorld //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model bool placeable = false; - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) - placeable = body->mPlaceable; - else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) placeable = body->mPlaceable; removeObject(handle); addObject(ptr, model, placeable); @@ -806,30 +714,6 @@ namespace MWWorld throw std::logic_error ("can't find player"); } - bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) - { - // FIXME: since raycasting shapes are going away, this should use the osg ComputeBoundingBoxVisitor - std::string model = ptr.getClass().getModel(ptr); - //model = Misc::ResourceHelpers::correctActorModelPath(model); - if (model.empty()) { - return false; - } - btVector3 btMin, btMax; - float scale = ptr.getCellRef().getScale(); - 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; - } - - void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); @@ -913,7 +797,6 @@ namespace MWWorld void PhysicsSystem::stepSimulation(float dt) { animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); - animateCollisionShapes(mEngine->mAnimatedRaycastingShapes, mEngine->mDynamicsWorld); mEngine->stepSimulation(dt); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index bc61914bc7..23bf47543c 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -60,29 +60,19 @@ namespace MWWorld std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getFacedHandle(float queryDistance); std::pair getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orientation, float queryDistance); - std::vector < std::pair > getFacedHandles (float queryDistance); - std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); - // cast ray, return true if it hit something. if raycasringObjectOnlt is set to false, it ignores NPCs and objects with no collisions. - bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool raycastingObjectOnly = true,bool ignoreHeightMap = false); + // cast ray, return true if it hit something. + bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = NULL, std::string* hit = NULL); - ///< cast ray from the mouse, return true if it hit something and the first result - /// @param normal if non-NULL, the hit normal will be written there (if there is a hit) - /// @param hit if non-NULL, the string handle of the hit object will be written there (if there is a hit) - OEngine::Physic::PhysicEngine* getEngine(); - bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max); - /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8cb9f4d509..416ef74164 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2724,13 +2724,14 @@ namespace MWWorld origin += node->_getDerivedPosition(); } #endif + /* + Ogre::Quaternion orient; orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); Ogre::Vector3 direction = orient.yAxis(); Ogre::Vector3 dest = origin + direction * distance; - std::vector > collisions = mPhysEngine->rayTest2(btVector3(origin.x, origin.y, origin.z), btVector3(dest.x, dest.y, dest.z)); for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end(); ++cIt) { @@ -2741,6 +2742,7 @@ namespace MWWorld break; } } + */ } std::string selectedSpell = stats.getSpells().getSelectedSpell(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ac7eef16af..9ec6483812 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifbullet -# bulletnifloader -# ) +add_component_dir (nifbullet + bulletnifloader + ) add_component_dir (to_utf8 to_utf8 diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index cdc06f985b..1d07bea26e 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -25,11 +25,9 @@ http://www.gnu.org/licenses/ . #include - +#include #include -#include - #include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" @@ -43,11 +41,6 @@ http://www.gnu.org/licenses/ . // For warning messages #include -// float infinity -#include - -typedef unsigned char ubyte; - // Extract a list of keyframe-controlled nodes from a .kf file // FIXME: this is a similar copy of OgreNifLoader::loadKf void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) @@ -116,14 +109,13 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) { mShape = static_cast(resource); mResourceName = mShape->getName(); - mShape->mCollide = false; mBoundingBox = NULL; - mShape->mBoxTranslation = Ogre::Vector3(0,0,0); - mShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mShape->mBoxTranslation = osg::Vec3f(0,0,0); + mShape->mBoxRotation = osg::Quat(); mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); + Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) { @@ -140,7 +132,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) kfname.replace(kfname.size()-4, 4, ".kf"); if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) { - Nif::NIFFilePtr kf (Nif::Cache::getInstance().load(kfname)); + Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); extractControlledNodes(kf, mControlledNodes); } @@ -188,28 +180,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) else if (mStaticMesh) mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); } - - //second pass which create a shape for raycasting. - mResourceName = mShape->getName(); - mShape->mCollide = false; - mBoundingBox = NULL; - mStaticMesh = NULL; - mCompoundShape = NULL; - - handleNode(node,0,true,true,false); - - if (mCompoundShape) - { - mShape->mRaycastingShape = mCompoundShape; - if (mStaticMesh) - { - btTransform trans; - trans.setIdentity(); - mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true)); - } - } - else if (mStaticMesh) - mShape->mRaycastingShape = new TriangleMeshShape(mStaticMesh,true); } bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) @@ -231,8 +201,7 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo } void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, - bool isCollisionNode, - bool raycasting, bool isAnimated) + bool isCollisionNode, bool isAnimated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -245,10 +214,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, if (mControlledNodes.find(node->name) != mControlledNodes.end()) isAnimated = true; - if (!raycasting) - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); - else - isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); // Don't collide with AvoidNode shapes if(node->recType == Nif::RC_AvoidNode) @@ -274,33 +240,26 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers && raycasting) - { - // Marker objects should be invisible, but still have collision. - // Except in the editor, the marker objects are visible. - return; - } } } - if (isCollisionNode || (mShape->mAutogenerated && !raycasting)) + if (isCollisionNode || (mShape->mAutogenerated)) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) if(node->hasBounds) { - if (flags & Nif::NiNode::Flag_BBoxCollision && !raycasting) + if (flags & Nif::NiNode::Flag_BBoxCollision) { mShape->mBoxTranslation = node->boundPos; - mShape->mBoxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + //mShape->mBoxRotation = node->boundRot; + //mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } } else if(node->recType == Nif::RC_NiTriShape) { - mShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycasting, isAnimated); + handleNiTriShape(static_cast(node), flags, Ogre::Matrix4()/*node->getWorldTransform()*/, isAnimated); } } @@ -312,13 +271,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); } } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, - bool raycasting, bool isAnimated) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated) { assert(shape != NULL); @@ -329,12 +287,12 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. - if ((flags & 0x800) && !raycasting) + if ((flags & 0x800)) { return; } - if (!collide && !bbcollide && hidden && !raycasting) + if (!collide && !bbcollide && hidden) // This mesh apparently isn't being used for anything, so don't // bother setting it up. return; @@ -354,18 +312,18 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int childMesh->preallocateVertices(data->vertices.size()); childMesh->preallocateIndices(data->triangles.size()); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + //const std::vector &vertices = data->vertices; + //const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = vertices[triangles[i+0]]; - Ogre::Vector3 b2 = vertices[triangles[i+1]]; - Ogre::Vector3 b3 = vertices[triangles[i+2]]; - childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + //Ogre::Vector3 b1 = vertices[triangles[i+0]]; + //Ogre::Vector3 b2 = vertices[triangles[i+1]]; + //Ogre::Vector3 b3 = vertices[triangles[i+2]]; + //childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } - TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + //TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -374,18 +332,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int parent = parent->parent; scale *= parent->trafo.scale; } - Ogre::Quaternion q = transform.extractQuaternion(); - Ogre::Vector3 v = transform.getTrans(); - childShape->setLocalScaling(btVector3(scale, scale, scale)); + //Ogre::Quaternion q = transform.extractQuaternion(); + //Ogre::Vector3 v = transform.getTrans(); + //childShape->setLocalScaling(btVector3(scale, scale, scale)); - btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); + //btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); - if (raycasting) - mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - else - mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); + //mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - mCompoundShape->addChildShape(trans, childShape); + //mCompoundShape->addChildShape(trans, childShape); } else { @@ -394,15 +349,17 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + //const std::vector &vertices = data->vertices; + //const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; - Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; - Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; + /* + osg::Vec3f b1 = transform*vertices[triangles[i+0]]; + osg::Vec3f b2 = transform*vertices[triangles[i+1]]; + osg::Vec3f b3 = transform*vertices[triangles[i+2]]; mStaticMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + */ } } } @@ -422,9 +379,9 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V { if (!(node->flags & Nif::NiNode::Flag_Hidden)) { - translation = node->boundPos; - orientation = node->boundRot; - halfExtents = node->boundXYZ; + //translation = node->boundPos; + //orientation = node->boundRot; + //halfExtents = node->boundXYZ; return true; } } @@ -445,7 +402,7 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) { - Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(nifFile)); + Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile)); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0d81d84b6b..81e854a946 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,8 +107,7 @@ private: /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, - bool raycasting, bool isAnimated=false); + void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false); /** *Helper function @@ -118,7 +117,7 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting, bool isAnimated); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated); std::string mResourceName; diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 92d56b42c5..26b6caa0ed 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -18,16 +18,13 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) we have none as such. Full details can be set through scripts. */ mCollisionShape = NULL; - mRaycastingShape = NULL; mAutogenerated = true; - mCollide = true; createParamDictionary("BulletShape"); } BulletShape::~BulletShape() { deleteShape(mCollisionShape); - deleteShape(mRaycastingShape); } // farm out to BulletShapeLoader @@ -56,9 +53,7 @@ void BulletShape::deleteShape(btCollisionShape* shape) void BulletShape::unloadImpl() { deleteShape(mCollisionShape); - deleteShape(mRaycastingShape); mCollisionShape = NULL; - mRaycastingShape = NULL; } //TODO:change this? diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 907ff8bfe9..472efac6d4 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -6,6 +6,9 @@ #include #include +#include +#include + namespace OEngine { namespace Physic { @@ -36,18 +39,13 @@ public: // we store the node's record index mapped to the child index of the shape in the btCompoundShape. std::map mAnimatedShapes; - std::map mAnimatedRaycastingShapes; - btCollisionShape* mCollisionShape; - btCollisionShape* mRaycastingShape; // Does this .nif have an autogenerated collision mesh? bool mAutogenerated; - Ogre::Vector3 mBoxTranslation; - Ogre::Quaternion mBoxRotation; - //this flag indicate if the shape is used for collision or if it's for raycasting only. - bool mCollide; + osg::Vec3f mBoxTranslation; + osg::Quat mBoxRotation; }; /** diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d5103d32bf..0125fd01e5 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -266,7 +266,6 @@ namespace Physic { new BulletShapeManager(); } - //TODO:singleton? mShapeLoader = shapeLoader; isDebugCreated = false; @@ -310,8 +309,6 @@ namespace Physic { for (std::map::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it) deleteShape(it->second.mCompound); - for (std::map::iterator it = mAnimatedRaycastingShapes.begin(); it != mAnimatedRaycastingShapes.end(); ++it) - deleteShape(it->second.mCompound); HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); for (; hf_it != mHeightFieldMap.end(); ++hf_it) @@ -332,17 +329,6 @@ namespace Physic rb_it->second = NULL; } } - rb_it = mRaycastingObjectMap.begin(); - for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } PhysicActorContainer::iterator pa_it = mActorMap.begin(); for (; pa_it != mActorMap.end(); ++pa_it) @@ -362,9 +348,6 @@ namespace Physic delete dispatcher; delete broadphase; delete mShapeLoader; - - // Moved the cleanup to mwworld/physicssystem - //delete BulletShapeManager::getSingletonPtr(); } void PhysicEngine::addHeightField(float* heights, @@ -407,7 +390,7 @@ namespace Physic mHeightFieldMap [name] = hf; mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, - CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile); + CollisionType_Actor|CollisionType_Projectile); } void PhysicEngine::removeHeightField(int x, int y) @@ -452,12 +435,12 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); + //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool placeable) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -469,21 +452,17 @@ namespace Physic // TODO: add option somewhere to enable collision for placeable meshes - if (placeable && !raycasting && shape->mCollisionShape) + if (placeable && shape->mCollisionShape) return NULL; - if (!shape->mCollisionShape && !raycasting) - return NULL; - if (!shape->mRaycastingShape && raycasting) + if (!shape->mCollisionShape) return NULL; - btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; + btCollisionShape* collisionShape = shape->mCollisionShape; // If this is an animated compound shape, we must duplicate it so we can animate // multiple instances independently. - if (!raycasting && !shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) + if (!shape->mAnimatedShapes.empty()) collisionShape = duplicateCollisionShape(collisionShape); collisionShape->setLocalScaling( btVector3(scale,scale,scale)); @@ -494,41 +473,24 @@ namespace Physic RigidBody* body = new RigidBody(CI,name); body->mPlaceable = placeable; - if (!raycasting && !shape->mAnimatedShapes.empty()) + if (!shape->mAnimatedShapes.empty()) { AnimatedShapeInstance instance; instance.mAnimatedShapes = shape->mAnimatedShapes; instance.mCompound = collisionShape; mAnimatedShapes[body] = instance; } - if (raycasting && !shape->mAnimatedRaycastingShapes.empty()) - { - AnimatedShapeInstance instance; - instance.mAnimatedShapes = shape->mAnimatedRaycastingShapes; - instance.mCompound = collisionShape; - mAnimatedRaycastingShapes[body] = instance; - } - if(scaledBoxTranslation != 0) - *scaledBoxTranslation = shape->mBoxTranslation * scale; - if(boxRotation != 0) - *boxRotation = shape->mBoxRotation; + //if(scaledBoxTranslation != 0) + // *scaledBoxTranslation = shape->mBoxTranslation * scale; + //if(boxRotation != 0) + // *boxRotation = shape->mBoxRotation; - adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); + //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - if (!raycasting) - { - assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); - mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); - } - else - { - assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); - mRaycastingObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_Projectile); - body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); - } + assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); + mCollisionObjectMap[name] = body; + mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); return body; } @@ -544,15 +506,6 @@ namespace Physic mDynamicsWorld->removeRigidBody(body); } } - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } } void PhysicEngine::deleteRigidBody(const std::string &name) @@ -572,30 +525,14 @@ namespace Physic } mCollisionObjectMap.erase(it); } - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - if (mAnimatedRaycastingShapes.find(body) != mAnimatedRaycastingShapes.end()) - deleteShape(mAnimatedRaycastingShapes[body].mCompound); - mAnimatedRaycastingShapes.erase(body); - - delete body; - } - mRaycastingObjectMap.erase(it); - } } - RigidBody* PhysicEngine::getRigidBody(const std::string &name, bool raycasting) + RigidBody* PhysicEngine::getRigidBody(const std::string &name) { - RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; - RigidBodyContainer::iterator it = map->find(name); - if (it != map->end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) { - RigidBody* body = (*map)[name]; + RigidBody* body = mCollisionObjectMap[name]; return body; } else @@ -617,8 +554,7 @@ namespace Physic const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) { const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); - if (body && !(colObj0Wrap->m_collisionObject->getBroadphaseHandle()->m_collisionFilterGroup - & CollisionType_Raycasting)) + if (body) mResult.push_back(body->mName); return 0.f; @@ -628,8 +564,7 @@ namespace Physic const btCollisionObject* col1, int partId1, int index1) { const RigidBody* body = dynamic_cast(col0); - if (body && !(col0->getBroadphaseHandle()->m_collisionFilterGroup - & CollisionType_Raycasting)) + if (body) mResult.push_back(body->mName); return 0.f; @@ -698,8 +633,6 @@ namespace Physic std::vector PhysicEngine::getCollisions(const std::string& name, int collisionGroup, int collisionMask) { RigidBody* body = getRigidBody(name); - if (!body) // fall back to raycasting body if there is no collision body - body = getRigidBody(name, true); ContactTestResultCallback callback; callback.m_collisionFilterGroup = collisionGroup; callback.m_collisionFilterMask = collisionMask; @@ -769,17 +702,14 @@ namespace Physic } } - std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool raycastingObjectOnly, bool ignoreHeightMap, Ogre::Vector3* normal) + std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool ignoreHeightMap, Ogre::Vector3* normal) { std::string name = ""; float d = -1; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; - if(raycastingObjectOnly) - resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor; - else - resultCallback1.m_collisionFilterMask = CollisionType_World; + resultCallback1.m_collisionFilterMask = CollisionType_World; if(!ignoreHeightMap) resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; @@ -833,51 +763,6 @@ namespace Physic return std::make_pair(false, 1.0f); } - std::vector< std::pair > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup) - { - MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterGroup = filterGroup; - resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap; - mDynamicsWorld->rayTest(from, to, resultCallback1); - std::vector< std::pair > results = resultCallback1.results; - - std::vector< std::pair > results2; - - for (std::vector< std::pair >::iterator it=results.begin(); - it != results.end(); ++it) - { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); - } - - std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp); - - 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(); - - if (shape->mRaycastingShape) - shape->mRaycastingShape->getAabb(trans, min, max); - else if (shape->mCollisionShape) - shape->mCollisionShape->getAabb(trans, min, max); - else - { - min = btVector3(0,0,0); - max = btVector3(0,0,0); - } - } - int PhysicEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { if(!sceneMgr) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 7784e8941d..71f84cca7c 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -46,9 +46,8 @@ namespace Physic CollisionType_World = 1<<0, // rayTest(const btVector3& from,const btVector3& to,bool raycastingObjectOnly = true, + std::pair rayTest(const btVector3& from,const btVector3& to, bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); - /** - * Return all objects hit by a ray. - */ - std::vector< std::pair > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff); - std::pair sphereCast (float radius, btVector3& from, btVector3& to); ///< @return (hit, relative distance) @@ -333,10 +325,6 @@ namespace Physic // the index refers to an element in mCollisionObjectMap std::map mAnimatedShapes; - RigidBodyContainer mRaycastingObjectMap; - - std::map mAnimatedRaycastingShapes; - typedef std::map PhysicActorContainer; PhysicActorContainer mActorMap; From cac288d5be337758005ca9b2583821e8f5f3665f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 May 2015 21:49:36 +0200 Subject: [PATCH 0192/1812] Remove OgreInit --- apps/launcher/graphicspage.cpp | 121 +---------------- apps/launcher/graphicspage.hpp | 13 -- components/CMakeLists.txt | 4 - components/ogreinit/ogreinit.cpp | 210 ----------------------------- components/ogreinit/ogreinit.hpp | 78 ----------- components/ogreinit/ogreplugin.cpp | 45 ------- components/ogreinit/ogreplugin.hpp | 42 ------ files/settings-default.cfg | 7 - 8 files changed, 1 insertion(+), 519 deletions(-) delete mode 100644 components/ogreinit/ogreinit.cpp delete mode 100644 components/ogreinit/ogreinit.hpp delete mode 100644 components/ogreinit/ogreplugin.cpp delete mode 100644 components/ogreinit/ogreplugin.hpp diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index cdb51348c8..cb3a3e7cb3 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -12,9 +12,6 @@ #include -#include -#include - #include #include @@ -36,11 +33,7 @@ QString getAspect(int x, int y) } Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) - : mOgre(NULL) - , mSelectedRenderSystem(NULL) - , mOpenGLRenderSystem(NULL) - , mDirect3DRenderSystem(NULL) - , mCfgMgr(cfg) + : mCfgMgr(cfg) , mGraphicsSettings(graphicsSetting) , QWidget(parent) { @@ -52,79 +45,12 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsS customWidthSpinBox->setMaximum(res.width()); customHeightSpinBox->setMaximum(res.height()); - connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int))); } -bool Launcher::GraphicsPage::setupOgre() -{ - try - { - mOgre = mOgreInit.init(mCfgMgr.getLogPath().string() + "/launcherOgre.log"); - } - catch(Ogre::Exception &ex) - { - QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating Ogre::Root"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Failed to create the Ogre::Root object

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(ogreError); - msgBox.exec(); - - qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError)); - return false; - } - - // Get the available renderers and put them in the combobox - const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers(); - - for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) { - mSelectedRenderSystem = *r; - rendererComboBox->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 Ogre plugins were installed correctly.
")); - msgBox.exec(); - return false; - } - - // Now fill the GUI elements - int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); - if ( index != -1) { - rendererComboBox->setCurrentIndex(index); - } else { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName)); -#else - rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName)); -#endif - } - - antiAliasingComboBox->clear(); - antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - - return true; -} - bool Launcher::GraphicsPage::setupSDL() { int displays = SDL_GetNumVideoDisplays(); @@ -153,8 +79,6 @@ bool Launcher::GraphicsPage::loadSettings() { if (!setupSDL()) return false; - if (!mOgre && !setupOgre()) - return false; if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -203,7 +127,6 @@ void Launcher::GraphicsPage::saveSettings() : mGraphicsSettings.setValue(QString("Video/window border"), QString("false")); mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); - mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); if (standardRadioButton->isChecked()) { @@ -221,39 +144,6 @@ void Launcher::GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); } -QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) -{ - QStringList result; - - uint row = 0; - Ogre::ConfigOptionMap options = renderer->getConfigOptions(); - - for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row) - { - Ogre::StringVector::iterator opt_it; - uint idx = 0; - - for (opt_it = i->second.possibleValues.begin(); - opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) - { - if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*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; -} - QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) { QStringList result; @@ -316,15 +206,6 @@ QRect Launcher::GraphicsPage::getMaximumResolution() return max; } -void Launcher::GraphicsPage::rendererChanged(const QString &renderer) -{ - mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); - - antiAliasingComboBox->clear(); - - antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); -} - void Launcher::GraphicsPage::screenChanged(int screen) { if (screen >= 0) { diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 213b6bccb4..fb96c39d78 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,12 +3,8 @@ #include -#include - #include "ui_graphicspage.h" -namespace Ogre { class Root; class RenderSystem; } - namespace Files { struct ConfigurationManager; } namespace Launcher @@ -26,7 +22,6 @@ namespace Launcher bool loadSettings(); public slots: - void rendererChanged(const QString &renderer); void screenChanged(int screen); private slots: @@ -34,20 +29,12 @@ namespace Launcher void slotStandardToggled(bool checked); private: - OgreInit::OgreInit mOgreInit; - Ogre::Root *mOgre; - Ogre::RenderSystem *mSelectedRenderSystem; - Ogre::RenderSystem *mOpenGLRenderSystem; - Ogre::RenderSystem *mDirect3DRenderSystem; - Files::ConfigurationManager &mCfgMgr; GraphicsSettings &mGraphicsSettings; - QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); - bool setupOgre(); bool setupSDL(); }; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9ec6483812..1f9bd337b1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -114,10 +114,6 @@ add_component_dir (loadinglistener loadinglistener ) -add_component_dir (ogreinit - ogreinit ogreplugin - ) - add_component_dir (myguiplatform myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener ) diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp deleted file mode 100644 index e8ca2e8bd9..0000000000 --- a/components/ogreinit/ogreinit.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "ogreinit.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include -#endif - -#include -#include - -#include "ogreplugin.hpp" - - -namespace bfs = boost::filesystem; - -namespace -{ - /** \brief Custom Ogre::LogListener interface implementation being - able to portably handle UTF-8 encoded path. - - Effectively this is used in conjunction with default listener, - but since on every message messageLogged() set 'skip' flag to - true, there should be no troubles sharing same file. - */ - class LogListener : public Ogre::LogListener - { - bfs::ofstream file; - char buffer[16]; - - - public: - - LogListener(const std::string &path) - : file((bfs::path(path))) - { - memset(buffer, 0, sizeof(buffer)); - } - - void timestamp() - { - int local = time(0) % 86400; - int sec = local % 60; - int min = (local / 60) % 60; - int hrs = local / 3600; - sprintf(buffer, "%02d:%02d:%02d: ", hrs, min, sec); - } - - virtual void messageLogged(const std::string &msg, Ogre::LogMessageLevel lvl, bool mask, const std::string &logName, bool &skip) - { - timestamp(); - file << buffer << msg << std::endl; - skip = true; - } - }; -} - -namespace OgreInit -{ - - OgreInit::OgreInit() - : mRoot(NULL) - #ifdef ENABLE_PLUGIN_CgProgramManager - , mCgPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - , mOctreePlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - , mParticleFXPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_GL - , mGLPlugin(NULL) - #endif - #ifdef ENABLE_PLUGIN_GLES2 - , mGLES2Plugin(NULL) - #endif - - #ifdef ENABLE_PLUGIN_Direct3D9 - , mD3D9Plugin(NULL) - #endif - {} - - Ogre::Root* OgreInit::init(const std::string &logPath) - { - if (mRoot) - throw std::runtime_error("OgreInit was already initialised"); - - #ifndef ANDROID - // Set up logging first - new Ogre::LogManager; - Ogre::Log *log = Ogre::LogManager::getSingleton().createLog(logPath); - - #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - // Use custom listener only on Windows - log->addListener(new LogListener(logPath)); - #endif - - // Disable logging to cout/cerr - log->setDebugOutputEnabled(false); - #endif - mRoot = new Ogre::Root("", "", ""); - - #if defined(ENABLE_PLUGIN_GL) || (ENABLE_PLUGIN_GLES2) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) - loadStaticPlugins(); - #else - loadPlugins(); - #endif - - return mRoot; - } - - OgreInit::~OgreInit() - { - delete mRoot; - delete Ogre::LogManager::getSingletonPtr(); - - #ifdef ENABLE_PLUGIN_GL - delete mGLPlugin; - mGLPlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_GLES2 - delete mGLES2Plugin; - mGLES2Plugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - delete mD3D9Plugin; - mD3D9Plugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_CgProgramManager - delete mCgPlugin; - mCgPlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - delete mOctreePlugin; - mOctreePlugin = NULL; - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - delete mParticleFXPlugin; - mParticleFXPlugin = NULL; - #endif - } - - void OgreInit::loadStaticPlugins() - { - #ifdef ENABLE_PLUGIN_GL - mGLPlugin = new Ogre::GLPlugin(); - mRoot->installPlugin(mGLPlugin); - #endif - #ifdef ENABLE_PLUGIN_GLES2 - mGLES2Plugin = new Ogre::GLES2Plugin(); - mRoot->installPlugin(mGLES2Plugin); - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - mD3D9Plugin = new Ogre::D3D9Plugin(); - mRoot->installPlugin(mD3D9Plugin); - #endif - #ifdef ENABLE_PLUGIN_CgProgramManager - mCgPlugin = new Ogre::CgPlugin(); - mRoot->installPlugin(mCgPlugin); - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - mOctreePlugin = new Ogre::OctreePlugin(); - mRoot->installPlugin(mOctreePlugin); - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - mParticleFXPlugin = new Ogre::ParticleFXPlugin(); - mRoot->installPlugin(mParticleFXPlugin); - #endif - } - - void OgreInit::loadPlugins() - { - 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; - // if path is not specified try to find plugins inside the app bundle - if (pluginDir.empty()) - pluginDir = Ogre::macFrameworksPath(); - #endif - #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - pluginDir = OGRE_PLUGIN_DIR; - #endif - } - Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); - Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); - Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); - if (!Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot)) - throw std::runtime_error("Required Plugin_ParticleFX for Ogre not found!"); - } -} diff --git a/components/ogreinit/ogreinit.hpp b/components/ogreinit/ogreinit.hpp deleted file mode 100644 index d1743950f2..0000000000 --- a/components/ogreinit/ogreinit.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef OPENMW_COMPONENTS_OGREINIT_H -#define OPENMW_COMPONENTS_OGREINIT_H - -#include -#include - -// Static plugin headers -#ifdef ENABLE_PLUGIN_CgProgramManager -# include "OgreCgPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_OctreeSceneManager -# include "OgreOctreePlugin.h" -#endif -#ifdef ENABLE_PLUGIN_ParticleFX -# include "OgreParticleFXPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_GL -# include "OgreGLPlugin.h" -#endif -#ifdef ENABLE_PLUGIN_GLES2 -# include "OgreGLES2Plugin.h" -#endif - -#ifdef ENABLE_PLUGIN_Direct3D9 -# include "OgreD3D9Plugin.h" -#endif - -namespace Ogre -{ - class ParticleEmitterFactory; - class ParticleAffectorFactory; - class Root; -} - -namespace OgreInit -{ - /** - * @brief Starts Ogre::Root and loads required plugins and NIF particle factories - */ - class OgreInit - { - public: - OgreInit(); - - Ogre::Root* init(const std::string &logPath // Path to directory where to store log files - ); - - ~OgreInit(); - - private: - Ogre::Root* mRoot; - - void loadStaticPlugins(); - void loadPlugins(); - - #ifdef ENABLE_PLUGIN_CgProgramManager - Ogre::CgPlugin* mCgPlugin; - #endif - #ifdef ENABLE_PLUGIN_OctreeSceneManager - Ogre::OctreePlugin* mOctreePlugin; - #endif - #ifdef ENABLE_PLUGIN_ParticleFX - Ogre::ParticleFXPlugin* mParticleFXPlugin; - #endif - #ifdef ENABLE_PLUGIN_GL - Ogre::GLPlugin* mGLPlugin; - #endif - #ifdef ENABLE_PLUGIN_GLES2 - Ogre::GLES2Plugin* mGLES2Plugin; - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - Ogre::D3D9Plugin* mD3D9Plugin; - #endif - - }; -} - -#endif diff --git a/components/ogreinit/ogreplugin.cpp b/components/ogreinit/ogreplugin.cpp deleted file mode 100644 index 069b25e7b5..0000000000 --- a/components/ogreinit/ogreplugin.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "ogreplugin.hpp" - -#include -#include - -namespace Files { - -bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { - std::string pluginExt; -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - pluginExt = ".dll"; -#endif -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - pluginExt = ".framework"; -#endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - pluginExt = ".so"; -#endif - - // Append plugin suffix if debugging. - std::string pluginPath; -#if defined(DEBUG) - pluginPath = pluginDir + "/" + pluginName + OGRE_PLUGIN_DEBUG_SUFFIX + pluginExt; - if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; - } - else { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - return false; -#endif //OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - } -#endif //defined(DEBUG) - - pluginPath = pluginDir + "/" + pluginName + pluginExt; - if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; - } - else { - return false; - } -} - -} diff --git a/components/ogreinit/ogreplugin.hpp b/components/ogreinit/ogreplugin.hpp deleted file mode 100644 index 6fcf613768..0000000000 --- a/components/ogreinit/ogreplugin.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#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/files/settings-default.cfg b/files/settings-default.cfg index 32c3861c07..f1af8b6549 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -12,13 +12,6 @@ screen = 0 # Minimize the window if it loses key focus? minimize on focus loss = true -# Render system -# blank means default -# Valid values: -# OpenGL Rendering Subsystem -# Direct3D9 Rendering Subsystem -render system = - # Valid values: # none # MSAA 2 From bddd31e385d1897597fdd21d093fd4083b22c742 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 16:39:03 +0200 Subject: [PATCH 0193/1812] Dead code removal --- apps/openmw/mwworld/physicssystem.cpp | 8 +-- libs/openengine/bullet/physic.cpp | 75 --------------------------- libs/openengine/bullet/physic.hpp | 9 ---- 3 files changed, 4 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 14cab6c828..271b23d098 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -503,14 +503,14 @@ namespace MWWorld { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - //mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); } PhysicsSystem::~PhysicsSystem() { - //if (mWaterCollisionObject.get()) - // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - //delete mEngine; + if (mWaterCollisionObject.get()) + mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + delete mEngine; //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 0125fd01e5..b1bd978c6b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -262,10 +262,6 @@ namespace Physic mDynamicsWorld->setGravity(btVector3(0,0,-10)); - if(BulletShapeManager::getSingletonPtr() == NULL) - { - new BulletShapeManager(); - } mShapeLoader = shapeLoader; isDebugCreated = false; @@ -763,76 +759,5 @@ namespace Physic return std::make_pair(false, 1.0f); } - int PhysicEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return 0; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - { - // set a new drawer each time (maybe with a different scene manager) - mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]); - if(!mDebugDrawers[sceneMgr]->getDebugMode()) - mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); - else - mDebugDrawers[sceneMgr]->setDebugMode(0); - mDynamicsWorld->debugDrawWorld(); - - return mDebugDrawers[sceneMgr]->getDebugMode(); - } - } - return 0; - } - - void PhysicEngine::stepDebug(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - (*iter).second->step(); - else - return; - } - } - - void PhysicEngine::createDebugDraw(Ogre::SceneManager *sceneMgr) - { - if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end()) - { - mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode(); - mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld); - mDebugDrawers[sceneMgr]->setDebugMode(0); - } - } - - void PhysicEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr) - { - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) - { - delete (*iter).second; - mDebugDrawers.erase(iter); - } - - std::map::iterator it = - mDebugSceneNodes.find(sceneMgr); - if(it != mDebugSceneNodes.end()) - { - std::string sceneNodeName = (*it).second->getName(); - if(sceneMgr->hasSceneNode(sceneNodeName)) - sceneMgr->destroySceneNode(sceneNodeName); - } - } - } } diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 71f84cca7c..e92e9c3c1c 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -335,15 +335,6 @@ namespace Physic bool isDebugCreated; bool mDebugActive; - // for OpenCS with multiple engines per document - std::map mDebugDrawers; - std::map mDebugSceneNodes; - - int toggleDebugRendering(Ogre::SceneManager *sceneMgr); - void stepDebug(Ogre::SceneManager *sceneMgr); - void createDebugDraw(Ogre::SceneManager *sceneMgr); - void removeDebugDraw(Ogre::SceneManager *sceneMgr); - private: PhysicEngine(const PhysicEngine&); PhysicEngine& operator=(const PhysicEngine&); From 8817f44d6390bacec6118ca9fc4ca7eae7da02f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 17:48:24 +0200 Subject: [PATCH 0194/1812] Remove advanced FPS counter (obsoleted by the OSG stats viewer) --- apps/openmw/engine.cpp | 5 +--- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 31 +++---------------- apps/openmw/mwgui/hud.hpp | 8 ++--- apps/openmw/mwgui/settingswindow.cpp | 8 ++--- apps/openmw/mwgui/windowmanagerimp.cpp | 10 ++----- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +-- apps/openmw/mwworld/worldimp.cpp | 5 ---- apps/openmw/mwworld/worldimp.hpp | 2 -- files/mygui/openmw_hud.layout | 41 -------------------------- files/settings-default.cfg | 3 +- 12 files changed, 15 insertions(+), 106 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0abb43cfde..0dc19144c0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -150,10 +150,7 @@ void OMW::Engine::frame(float frametime) MWBase::StateManager::State_NoGame) { #if 0 - Ogre::RenderWindow* window = mOgre->getWindow(); - unsigned int tri, batch; - MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); - MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); + MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps); #endif MWBase::Environment::get().getWindowManager()->update(); } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 59407fbeb0..d1f1ad3a33 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -152,7 +152,7 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; + virtual void wmUpdateFps(float fps) = 0; /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 00d4d8536a..1f27756d10 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -130,8 +130,6 @@ namespace MWBase virtual void adjustSky() = 0; - virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual const MWWorld::Fallback *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 9c8fa48a1d..5f5f2eca36 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,7 +70,7 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, int fpsLevel, DragAndDrop* dragAndDrop) + HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop) : Layout("openmw_hud.layout") , LocalMapBase(customMarkers) , mHealth(NULL) @@ -89,8 +89,6 @@ namespace MWGui , mCrosshair(NULL) , mFpsBox(NULL) , mFpsCounter(NULL) - , mTriangleCounter(NULL) - , mBatchCounter(NULL) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -166,10 +164,7 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - setFpsLevel(fpsLevel); - - getWidget(mTriangleCounter, "TriangleCounter"); - getWidget(mBatchCounter, "BatchCounter"); + setFpsVisible(showFps); LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); @@ -189,23 +184,15 @@ namespace MWGui delete mSpellIcons; } - void HUD::setFpsLevel(int level) + void HUD::setFpsVisible(const bool visible) { mFpsCounter = 0; MyGUI::Widget* fps; - getWidget(fps, "FPSBoxAdv"); - fps->setVisible(false); getWidget(fps, "FPSBox"); fps->setVisible(false); - if (level == 2) - { - getWidget(mFpsBox, "FPSBoxAdv"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounterAdv"); - } - else if (level == 1) + if (visible) { getWidget(mFpsBox, "FPSBox"); mFpsBox->setVisible(true); @@ -219,16 +206,6 @@ namespace MWGui mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); } - void HUD::setTriangleCount(unsigned int count) - { - mTriangleCounter->setCaption(MyGUI::utility::toString(count)); - } - - void HUD::setBatchCount(unsigned int count) - { - mBatchCounter->setCaption(MyGUI::utility::toString(count)); - } - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { int current = std::max(0, static_cast(value.getCurrent())); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index e717e094eb..9eed9811a4 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,12 +19,10 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, int fpsLevel, DragAndDrop* dragAndDrop); + HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); - void setTriangleCount(unsigned int count); - void setBatchCount(unsigned int count); /// Set time left for the player to start drowning /// @param time time left to start drowning @@ -40,7 +38,7 @@ namespace MWGui void setEffectVisible(bool visible); void setMinimapVisible(bool visible); - void setFpsLevel(const int level); + void setFpsVisible(const bool visible); void setSelectedSpell(const std::string& spellId, int successChancePercent); void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); @@ -80,8 +78,6 @@ namespace MWGui MyGUI::Widget* mFpsBox; MyGUI::TextBox* mFpsCounter; - MyGUI::TextBox* mTriangleCounter; - MyGUI::TextBox* mBatchCounter; // bottom left elements int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d895a28ea7..23cf2c62e1 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -32,10 +32,8 @@ namespace { if (level == 0) return "#{sOff}"; - else if (level == 1) - return "Basic"; - else - return "Detailed"; + else //if (level == 1) + return "#{sOn}"; } std::string textureFilteringToStr(const std::string& val) @@ -413,7 +411,7 @@ namespace MWGui void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { - int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 3; + int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; Settings::Manager::setInt("fps", "HUD", newLevel); mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); apply(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 096838f81a..e4e0c3167c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -174,8 +174,6 @@ namespace MWGui , mAllowed(GW_ALL) , mRestAllowed(true) , mFPS(0.0f) - , mTriangleCount(0) - , mBatchCount(0) , mCurrentModals() , mFallbackMap(fallbackMap) { @@ -440,8 +438,6 @@ namespace MWGui cleanupGarbage(); mHud->setFPS(mFPS); - mHud->setTriangleCount(mTriangleCount); - mHud->setBatchCount(mBatchCount); mHud->update(); } @@ -1078,7 +1074,7 @@ namespace MWGui void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mHud->setFpsVisible(static_cast(Settings::Manager::getInt("fps", "HUD"))); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); for (Settings::CategorySettingVector::const_iterator it = changed.begin(); @@ -1278,11 +1274,9 @@ namespace MWGui mConsole->executeFile (path); } - void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) + void WindowManager::wmUpdateFps(float fps) { mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; } MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 765a181562..7fccff2d85 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -172,7 +172,7 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); + virtual void wmUpdateFps(float fps); ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); @@ -474,8 +474,6 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings float mFPS; - unsigned int mTriangleCount; - unsigned int mBatchCount; std::map mFallbackMap; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 416ef74164..842a24dedb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1979,11 +1979,6 @@ namespace MWWorld //mRendering->processChangedSettings(settings); } - void World::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) - { - //mRendering->getTriangleBatchCount(triangles, batches); - } - bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 447bb13006..9598d43571 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -205,8 +205,6 @@ namespace MWWorld virtual void adjustSky(); - virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual const Fallback *getFallback() const; virtual Player& getPlayer(); diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 0cbe0dd971..dd114097e5 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -132,46 +132,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f1af8b6549..862f9495ac 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -93,8 +93,7 @@ debug = false [HUD] # FPS counter # 0: not visible -# 1: basic FPS display -# 2: advanced FPS display (batches, triangles) +# 1: FPS display fps = 0 crosshair = true From 1b78acc2c01e168dc3d556a3501dc26791ebeb50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:06:17 +0200 Subject: [PATCH 0195/1812] Remove manual allocation for images --- components/fontloader/fontloader.cpp | 7 ++++--- components/resource/texturemanager.cpp | 13 +++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index e579de18f8..080c64c4c9 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -277,9 +277,10 @@ namespace Gui osg::ref_ptr image = new osg::Image; - unsigned char* bytes = (unsigned char*)calloc(width*height*4, sizeof(unsigned char)); - memcpy(bytes, &textureData[0], textureData.size()); - image->setImage(width, height, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); + image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert (image->isDataContiguous()); + + memcpy(image->data(), &textureData[0], textureData.size()); osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image); diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d0d32a40e1..b86b70cde1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -13,15 +13,16 @@ namespace { osg::ref_ptr warningImage = new osg::Image; - int width=8, height=8; - unsigned char* bytes = (unsigned char*)calloc(width*height*3, sizeof(unsigned char)); + int width = 8, height = 8; + warningImage->allocateImage(width, height, 1, GL_RGB, GL_UNSIGNED_BYTE); + assert (warningImage->isDataContiguous()); + unsigned char* data = warningImage->data(); for (int i=0;isetImage(width, height, 1, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, bytes, osg::Image::USE_MALLOC_FREE); osg::ref_ptr warningTexture = new osg::Texture2D; warningTexture->setImage(warningImage); From dc9b27acfe175dfec36a1e0bd6db59e82d3b03a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:06:54 +0200 Subject: [PATCH 0196/1812] Create manual GUI textures --- apps/openmw/mwgui/windowmanagerimp.cpp | 56 +++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + .../myguiplatform/myguirendermanager.cpp | 3 + 3 files changed, 62 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e4e0c3167c..3755de07e8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -183,6 +183,8 @@ namespace MWGui MyGUI::Gui* gui = new MyGUI::Gui; gui->initialise(""); + createTextures(); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Load fonts @@ -1084,6 +1086,8 @@ namespace MWGui mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + else if (it->first == "GUI" && it->second == "menu transparency") + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } } @@ -1929,4 +1933,56 @@ namespace MWGui return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); } + void WindowManager::createTextures() + { + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 255; + *(data++) = 255; + *(data++) = 255; + } + tex->unlock(); + } + + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 0; + *(data++) = 0; + *(data++) = 0; + } + tex->unlock(); + } + + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent.png"); + tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); + } + } + + void WindowManager::setMenuTransparency(float value) + { + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent.png"); + unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + for (int x=0; x<8; ++x) + for (int y=0; y<8; ++y) + { + *(data++) = 255; + *(data++) = 255; + *(data++) = 255; + *(data++) = static_cast(value*255); + } + tex->unlock(); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7fccff2d85..3258818896 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -499,6 +499,9 @@ namespace MWGui void onClipboardChanged(const std::string& _type, const std::string& _data); void onClipboardRequested(const std::string& _type, std::string& _data); + + void createTextures(); + void setMenuTransparency(float value); }; } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3ebbd957a8..87464f22da 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -420,6 +420,9 @@ void RenderManager::destroyTexture(MyGUI::ITexture *texture) MyGUI::ITexture* RenderManager::getTexture(const std::string &name) { + if (name.empty()) + return NULL; + MapTexture::const_iterator item = mTextures.find(name); if(item == mTextures.end()) { From d772da37202941e139e22834e7f827db5481b457 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 18:14:53 +0200 Subject: [PATCH 0197/1812] Main menu background videos --- apps/openmw/mwgui/mainmenu.cpp | 7 +++++-- apps/openmw/mwgui/mainmenu.hpp | 8 +++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d563eacc80..48f9ee42ce 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -29,8 +30,9 @@ namespace MWGui { - MainMenu::MainMenu(int w, int h) + MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs) : Layout("openmw_mainmenu.layout") + , mVFS(vfs) , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) , mBackground(NULL) @@ -53,7 +55,7 @@ namespace MWGui std::string output = sstream.str(); mVersionText->setCaption(output); - mHasAnimatedMenu = 0;//(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); + mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); updateMenu(); } @@ -174,6 +176,7 @@ namespace MWGui mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mVideo->setVFS(mVFS); mVideo->playVideo("video\\menu_background.bik"); } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 9089ed1d59..d01f67fbd2 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -8,6 +8,11 @@ namespace Gui class ImageButton; } +namespace VFS +{ + class Manager; +} + namespace MWGui { @@ -24,7 +29,7 @@ namespace MWGui public: - MainMenu(int w, int h); + MainMenu(int w, int h, const VFS::Manager* vfs); ~MainMenu(); void onResChange(int w, int h); @@ -34,6 +39,7 @@ namespace MWGui void update(float dt); private: + const VFS::Manager* mVFS; MyGUI::Widget* mButtonBox; MyGUI::TextBox* mVersionText; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3755de07e8..9d9ba329b0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -259,7 +259,7 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); - mMenu = new MainMenu(w,h); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, ""); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); From 1a5407af989efcf3f79f53f95fee2e7470929015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 19:36:36 +0200 Subject: [PATCH 0198/1812] Reduce texture memory usage in OpenMW --- apps/openmw/engine.cpp | 2 ++ components/resource/texturemanager.cpp | 9 +++++++-- components/resource/texturemanager.hpp | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0dc19144c0..15fee0cb1f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -307,6 +308,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); + mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index b86b70cde1..939f81d9b8 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -37,10 +37,16 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) , mWarningTexture(createWarningTexture()) + , mUnRefImageDataAfterApply(false) { } + void TextureManager::setUnRefImageDataAfterApply(bool unref) + { + mUnRefImageDataAfterApply = unref; + } + /* osg::ref_ptr TextureManager::getImage(const std::string &filename) { @@ -91,8 +97,7 @@ namespace Resource texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); - // Can be enabled for single-context, i.e. in openmw - //texture->setUnRefImageDataAfterApply(true); + texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply); mTextures.insert(std::make_pair(key, texture)); return texture; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index f4ade515d3..d44d47d243 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -24,6 +24,10 @@ namespace Resource // TODO: texture filtering settings + /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, + /// otherwise should be disabled to reduce memory usage. + void setUnRefImageDataAfterApply(bool unref); + /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); @@ -43,6 +47,7 @@ namespace Resource osg::ref_ptr mWarningTexture; + bool mUnRefImageDataAfterApply; }; } From 9cf9c2876e9bcd9ea40d3090deb896df6988e9b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 May 2015 22:45:27 +0200 Subject: [PATCH 0199/1812] Pathgrid rendering --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/world.hpp | 12 +- apps/openmw/mwmechanics/pathfinding.hpp | 5 + apps/openmw/mwrender/creatureanimation.cpp | 3 - apps/openmw/mwrender/debugging.cpp | 245 +++++++++------------ apps/openmw/mwrender/debugging.hpp | 50 ++--- apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwrender/objects.cpp | 1 - apps/openmw/mwrender/renderconst.hpp | 76 ------- apps/openmw/mwrender/renderingmanager.cpp | 30 +++ apps/openmw/mwrender/renderingmanager.hpp | 6 + apps/openmw/mwrender/rendermode.hpp | 17 ++ apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwrender/vismask.hpp | 1 + apps/openmw/mwscript/miscextensions.cpp | 8 +- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 18 files changed, 197 insertions(+), 271 deletions(-) delete mode 100644 apps/openmw/mwrender/renderconst.hpp create mode 100644 apps/openmw/mwrender/rendermode.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f049f03870..ed55301260 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,8 +21,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface -# debugging camera activatoranimation + creatureanimation effectmanager util renderinginterface debugging rendermode +# camera activatoranimation # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst weaponanimation diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1f27756d10..4ccbfc784c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -9,6 +9,8 @@ #include "../mwworld/ptr.hpp" +#include "../mwrender/rendermode.hpp" + namespace Ogre { class Vector2; @@ -83,14 +85,6 @@ namespace MWBase public: - enum RenderMode - { - Render_CollisionDebug, - Render_Wireframe, - Render_Pathgrid, - Render_BoundingBoxes - }; - struct DoorMarker { std::string name; @@ -320,7 +314,7 @@ namespace MWBase /// collisions and gravity. /// \return Resulting mode - virtual bool toggleRenderMode (RenderMode mode) = 0; + virtual bool toggleRenderMode (MWRender::RenderMode mode) = 0; ///< Toggle a render mode. ///< \return Resulting mode diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index f48de6624c..0f4d42775c 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -88,6 +88,11 @@ namespace MWMechanics return ESM::Pathgrid::Point(static_cast(p.pos[0]), static_cast(p.pos[1]), static_cast(p.pos[2])); } + static osg::Vec3f MakeOsgVec3(const ESM::Pathgrid::Point& p) + { + return osg::Vec3f(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); + } + /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index d2abf14135..25d9e9e471 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -12,12 +12,9 @@ #include "../mwworld/class.hpp" -#include "renderconst.hpp" - namespace MWRender { - CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 79eeff2d04..97ead9d7d3 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -2,13 +2,10 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -23,145 +20,118 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" -#include "renderconst.hpp" - -using namespace Ogre; +#include "vismask.hpp" namespace MWRender { -static const std::string PATHGRID_POINT_MATERIAL = "pathgridPointMaterial"; -static const std::string PATHGRID_LINE_MATERIAL = "pathgridLineMaterial"; -static const std::string DEBUGGING_GROUP = "debugging"; static const int POINT_MESH_BASE = 35; -void Debugging::createGridMaterials() +osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { - if (mGridMatsCreated) return; + osg::ref_ptr geom = new osg::Geometry; - if (MaterialManager::getSingleton().getByName(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) - { - MaterialPtr lineMatPtr = MaterialManager::getSingleton().create(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP); - lineMatPtr->setReceiveShadows(false); - lineMatPtr->getTechnique(0)->setLightingEnabled(true); - lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0); - lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0); - lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0); - } + osg::ref_ptr vertices = new osg::Vec3Array; - if (MaterialManager::getSingleton().getByName(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP).isNull()) - { - MaterialPtr pointMatPtr = MaterialManager::getSingleton().create(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP); - pointMatPtr->setReceiveShadows(false); - pointMatPtr->getTechnique(0)->setLightingEnabled(true); - pointMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,0,0,0); - pointMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,0,0); - pointMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,0,0); - } - mGridMatsCreated = true; -} - -void Debugging::destroyGridMaterials() -{ - if (mGridMatsCreated) - { - MaterialManager::getSingleton().remove(PATHGRID_POINT_MATERIAL); - MaterialManager::getSingleton().remove(PATHGRID_LINE_MATERIAL); - mGridMatsCreated = false; - } -} - -ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) -{ - ManualObject *result = mSceneMgr->createManualObject(); - - result->begin(PATHGRID_LINE_MATERIAL, RenderOperation::OT_LINE_LIST); for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->mEdges.begin(); it != pathgrid->mEdges.end(); ++it) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - Vector3 direction = (MWMechanics::PathFinder::MakeOgreVector3(p2) - MWMechanics::PathFinder::MakeOgreVector3(p1)); - Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); + + osg::Vec3f direction = MWMechanics::PathFinder::MakeOsgVec3(p2) - MWMechanics::PathFinder::MakeOsgVec3(p1); + osg::Vec3f lineDisplacement = (direction^osg::Vec3f(0,0,1)); + lineDisplacement.normalize(); + lineDisplacement = lineDisplacement * POINT_MESH_BASE + - Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - result->position(MWMechanics::PathFinder::MakeOgreVector3(p1) + lineDisplacement); - result->position(MWMechanics::PathFinder::MakeOgreVector3(p2) + lineDisplacement); + osg::Vec3f(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape + + vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p1) + lineDisplacement); + vertices->push_back(MWMechanics::PathFinder::MakeOsgVec3(p2) + lineDisplacement); } - result->end(); - result->setVisibilityFlags (RV_Debug); + geom->setVertexArray(vertices); - return result; + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertices->size())); + + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 0.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + + return geom; } -ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) { - ManualObject *result = mSceneMgr->createManualObject(); + osg::ref_ptr geom = new osg::Geometry; + const float height = POINT_MESH_BASE * sqrtf(2); - result->begin(PATHGRID_POINT_MATERIAL, RenderOperation::OT_TRIANGLE_STRIP); + osg::ref_ptr vertices = new osg::Vec3Array; + osg::ref_ptr indices = new osg::UShortArray; bool first = true; - uint32 startIndex = 0; + unsigned short startIndex = 0; for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->mPoints.begin(); it != pathgrid->mPoints.end(); ++it, startIndex += 6) { - Vector3 pointPos(MWMechanics::PathFinder::MakeOgreVector3(*it)); + osg::Vec3f pointPos(MWMechanics::PathFinder::MakeOsgVec3(*it)); if (!first) { // degenerate triangle from previous octahedron - result->index(startIndex - 4); // 2nd point of previous octahedron - result->index(startIndex); // start point of current octahedron + indices->push_back(startIndex - 4); // 2nd point of previous octahedron + indices->push_back(startIndex); // start point of current octahedron } - Ogre::Real pointMeshBase = static_cast(POINT_MESH_BASE); + float pointMeshBase = static_cast(POINT_MESH_BASE); - result->position(pointPos + Vector3(0, 0, height)); // 0 - result->position(pointPos + Vector3(-pointMeshBase, -pointMeshBase, 0)); // 1 - result->position(pointPos + Vector3(pointMeshBase, -pointMeshBase, 0)); // 2 - result->position(pointPos + Vector3(pointMeshBase, pointMeshBase, 0)); // 3 - result->position(pointPos + Vector3(-pointMeshBase, pointMeshBase, 0)); // 4 - result->position(pointPos + Vector3(0, 0, -height)); // 5 + vertices->push_back(pointPos + osg::Vec3f(0, 0, height)); // 0 + vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, -pointMeshBase, 0)); // 1 + vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, -pointMeshBase, 0)); // 2 + vertices->push_back(pointPos + osg::Vec3f(pointMeshBase, pointMeshBase, 0)); // 3 + vertices->push_back(pointPos + osg::Vec3f(-pointMeshBase, pointMeshBase, 0)); // 4 + vertices->push_back(pointPos + osg::Vec3f(0, 0, -height)); // 5 - result->index(startIndex + 0); - result->index(startIndex + 1); - result->index(startIndex + 2); - result->index(startIndex + 5); - result->index(startIndex + 3); - result->index(startIndex + 4); + indices->push_back(startIndex + 0); + indices->push_back(startIndex + 1); + indices->push_back(startIndex + 2); + indices->push_back(startIndex + 5); + indices->push_back(startIndex + 3); + indices->push_back(startIndex + 4); // degenerates - result->index(startIndex + 4); - result->index(startIndex + 5); - result->index(startIndex + 5); + indices->push_back(startIndex + 4); + indices->push_back(startIndex + 5); + indices->push_back(startIndex + 5); // end degenerates - result->index(startIndex + 1); - result->index(startIndex + 4); - result->index(startIndex + 0); - result->index(startIndex + 3); - result->index(startIndex + 2); + indices->push_back(startIndex + 1); + indices->push_back(startIndex + 4); + indices->push_back(startIndex + 0); + indices->push_back(startIndex + 3); + indices->push_back(startIndex + 2); first = false; } - result->end(); + geom->setVertexArray(vertices); - result->setVisibilityFlags (RV_Debug); + geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, indices->size(), &(*indices)[0])); - return result; + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 0.f, 0.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + + return geom; } -Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : - mRootNode(root), mEngine(engine), - mSceneMgr(root->getCreator()), - mPathgridEnabled(false), - mInteriorPathgridNode(NULL), mPathGridRoot(NULL), - mGridMatsCreated(false) +Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/) + : mRootNode(root) + , mPathgridEnabled(false) + , mInteriorPathgridNode(NULL) + , mPathGridRoot(NULL) { - ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); } Debugging::~Debugging() @@ -170,34 +140,34 @@ Debugging::~Debugging() { togglePathgrid(); } - - ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); } bool Debugging::toggleRenderMode (int mode){ switch (mode) { - case MWBase::World::Render_CollisionDebug: + //case Render_CollisionDebug: - return mEngine->toggleDebugRendering(); + //return mEngine->toggleDebugRendering(); - case MWBase::World::Render_Pathgrid: + case Render_Pathgrid: togglePathgrid(); return mPathgridEnabled; + default: + return false; } return false; } -void Debugging::cellAdded(MWWorld::CellStore *store) +void Debugging::addCell(const MWWorld::CellStore *store) { mActiveCells.push_back(store); if (mPathgridEnabled) enableCellPathgrid(store); } -void Debugging::cellRemoved(MWWorld::CellStore *store) +void Debugging::removeCell(const MWWorld::CellStore *store) { mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end()); if (mPathgridEnabled) @@ -209,10 +179,11 @@ void Debugging::togglePathgrid() mPathgridEnabled = !mPathgridEnabled; if (mPathgridEnabled) { - createGridMaterials(); - // add path grid meshes to already loaded cells - mPathGridRoot = mRootNode->createChildSceneNode(); + mPathGridRoot = new osg::Group; + mPathGridRoot->setNodeMask(Mask_Debug); + mRootNode->addChild(mPathGridRoot); + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); @@ -225,29 +196,44 @@ void Debugging::togglePathgrid() { disableCellPathgrid(*it); } - mPathGridRoot->removeAndDestroyAllChildren(); - mSceneMgr->destroySceneNode(mPathGridRoot); - mPathGridRoot = NULL; - destroyGridMaterials(); + + if (mPathGridRoot) + { + mRootNode->removeChild(mPathGridRoot); + mPathGridRoot = NULL; + } } } -void Debugging::enableCellPathgrid(MWWorld::CellStore *store) +void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) { MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = world->getStore().get().search(*store->getCell()); if (!pathgrid) return; - Vector3 cellPathGridPos(0, 0, 0); + osg::Vec3f cellPathGridPos(0, 0, 0); if (store->getCell()->isExterior()) { - cellPathGridPos.x = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); - cellPathGridPos.y = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); + cellPathGridPos.x() = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); + cellPathGridPos.y() = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); } - SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); - cellPathGrid->attachObject(createPathgridLines(pathgrid)); - cellPathGrid->attachObject(createPathgridPoints(pathgrid)); + + osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; + cellPathGrid->setPosition(cellPathGridPos); + + osg::ref_ptr lineGeode = new osg::Geode; + osg::ref_ptr lines = createPathgridLines(pathgrid); + lineGeode->addDrawable(lines); + + osg::ref_ptr pointGeode = new osg::Geode; + osg::ref_ptr points = createPathgridPoints(pathgrid); + pointGeode->addDrawable(points); + + cellPathGrid->addChild(lineGeode); + cellPathGrid->addChild(pointGeode); + + mPathGridRoot->addChild(cellPathGrid); if (store->getCell()->isExterior()) { @@ -260,7 +246,7 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) } } -void Debugging::disableCellPathgrid(MWWorld::CellStore *store) +void Debugging::disableCellPathgrid(const MWWorld::CellStore *store) { if (store->getCell()->isExterior()) { @@ -268,7 +254,7 @@ void Debugging::disableCellPathgrid(MWWorld::CellStore *store) mExteriorPathgridNodes.find(std::make_pair(store->getCell()->getGridX(), store->getCell()->getGridY())); if (it != mExteriorPathgridNodes.end()) { - destroyCellPathgridNode(it->second); + mPathGridRoot->removeChild(it->second); mExteriorPathgridNodes.erase(it); } } @@ -276,27 +262,10 @@ void Debugging::disableCellPathgrid(MWWorld::CellStore *store) { if (mInteriorPathgridNode) { - destroyCellPathgridNode(mInteriorPathgridNode); + mPathGridRoot->removeChild(mInteriorPathgridNode); mInteriorPathgridNode = NULL; } } } -void Debugging::destroyCellPathgridNode(SceneNode *node) -{ - mPathGridRoot->removeChild(node); - destroyAttachedObjects(node); - mSceneMgr->destroySceneNode(node); -} - -void Debugging::destroyAttachedObjects(SceneNode *node) -{ - SceneNode::ObjectIterator objIt = node->getAttachedObjectIterator(); - while (objIt.hasMoreElements()) - { - MovableObject *mesh = static_cast(objIt.getNext()); - mSceneMgr->destroyMovableObject(mesh); - } -} - } diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index e243318013..4ec5bc41d3 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace ESM { struct Pathgrid; @@ -20,16 +22,10 @@ namespace OEngine } } -namespace Ogre +namespace osg { - class Camera; - class Viewport; - class SceneManager; - class SceneNode; - class RaySceneQuery; - class Quaternion; - class Vector3; - class ManualObject; + class Group; + class Geometry; } namespace MWWorld @@ -42,47 +38,37 @@ namespace MWRender { class Debugging { - OEngine::Physic::PhysicEngine* mEngine; - Ogre::SceneManager *mSceneMgr; + //OEngine::Physic::PhysicEngine* mEngine; // Path grid stuff bool mPathgridEnabled; void togglePathgrid(); - typedef std::vector CellList; + typedef std::vector CellList; CellList mActiveCells; - Ogre::SceneNode *mRootNode; + osg::ref_ptr mRootNode; - Ogre::SceneNode *mPathGridRoot; + osg::ref_ptr mPathGridRoot; - typedef std::map, Ogre::SceneNode *> ExteriorPathgridNodes; + typedef std::map, osg::ref_ptr > ExteriorPathgridNodes; ExteriorPathgridNodes mExteriorPathgridNodes; - Ogre::SceneNode *mInteriorPathgridNode; + osg::ref_ptr mInteriorPathgridNode; - void enableCellPathgrid(MWWorld::CellStore *store); - void disableCellPathgrid(MWWorld::CellStore *store); - - // utility - void destroyCellPathgridNode(Ogre::SceneNode *node); - void destroyAttachedObjects(Ogre::SceneNode *node); - - // materials - bool mGridMatsCreated; - void createGridMaterials(); - void destroyGridMaterials(); + void enableCellPathgrid(const MWWorld::CellStore *store); + void disableCellPathgrid(const MWWorld::CellStore *store); // path grid meshes - Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); - Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); + osg::ref_ptr createPathgridLines(const ESM::Pathgrid *pathgrid); + osg::ref_ptr createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine); + Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/); ~Debugging(); bool toggleRenderMode (int mode); - void cellAdded(MWWorld::CellStore* store); - void cellRemoved(MWWorld::CellStore* store); + void addCell(const MWWorld::CellStore* store); + void removeCell(const MWWorld::CellStore* store); }; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 80dbf3c7f6..d6aa05fcbc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -23,7 +23,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" -#include "renderconst.hpp" #include "camera.hpp" namespace diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index a06b751cc7..6f4f4ef79d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -17,7 +17,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" -#include "renderconst.hpp" #include "animation.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp deleted file mode 100644 index cfd84cb32e..0000000000 --- a/apps/openmw/mwrender/renderconst.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef GAME_RENDER_CONST_H -#define GAME_RENDER_CONST_H - -#include - -namespace MWRender -{ - -// Render queue groups -enum RenderQueueGroups -{ - // Sky early (atmosphere, clouds, moons) - RQG_SkiesEarly = Ogre::RENDER_QUEUE_SKIES_EARLY, - - 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 = RQG_Alpha, - RQG_Ripples = RQG_Water+1, - - // Sky late (sun & sun flare) - RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE -}; - -// Visibility flags -enum VisibilityFlags -{ - // Terrain - RV_Terrain = (1<<0), - - // Statics (e.g. trees, houses) - RV_Statics = (1<<1), - - // Small statics - RV_StaticsSmall = (1<<2), - - // Water - RV_Water = (1<<3), - - // Actors (npcs, creatures) - RV_Actors = (1<<4), - - // Misc objects (containers, dynamic objects) - RV_Misc = (1<<5), - - // VFX, don't appear on map and don't cast shadows - RV_Effects = (1<<6), - - RV_Sky = (1<<7), - - // not visible in reflection - RV_NoReflection = (1<<8), - - RV_OcclusionQuery = (1<<9), - - RV_Debug = (1<<10), - - // overlays, we only want these on the main render target - RV_Overlay = (1<<11), - - // First person meshes do not cast shadows - RV_FirstPerson = (1<<12), - - RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, - - RV_Refraction = RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Effects + RV_Sky + RV_FirstPerson -}; - -} - -#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d07c98ed7d..5cb7795453 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -21,10 +21,13 @@ #include +#include "../mwbase/world.hpp" + #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" #include "vismask.hpp" +#include "debugging.hpp" namespace MWRender { @@ -88,6 +91,8 @@ namespace MWRender mRootNode->addChild(lightRoot); + mDebugging.reset(new Debugging(mRootNode)); + mObjects.reset(new Objects(mResourceSystem, lightRoot)); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); @@ -182,8 +187,14 @@ namespace MWRender return eye; } + void RenderingManager::addCell(const MWWorld::CellStore *store) + { + mDebugging->addCell(store); + } + void RenderingManager::removeCell(const MWWorld::CellStore *store) { + mDebugging->removeCell(store); mObjects->removeCell(store); } @@ -192,6 +203,25 @@ namespace MWRender mSky->setEnabled(enabled); } + bool RenderingManager::toggleRenderMode(RenderMode mode) + { + if (mode == Render_CollisionDebug || mode == Render_Pathgrid) + return mDebugging->toggleRenderMode(mode); + else if (mode == Render_Wireframe) + { + return false; + } + /* + else //if (mode == Render_BoundingBoxes) + { + bool show = !mRendering.getScene()->getShowBoundingBoxes(); + mRendering.getScene()->showBoundingBoxes(show); + return show; + } + */ + return false; + } + void RenderingManager::configureFog(const ESM::Cell *cell) { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71c70b9907..334025096d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -7,6 +7,7 @@ #include "objects.hpp" #include "renderinginterface.hpp" +#include "rendermode.hpp" namespace osg { @@ -37,6 +38,7 @@ namespace MWRender class EffectManager; class SkyManager; class NpcAnimation; + class Debugging; class RenderingManager : public MWRender::RenderingInterface { @@ -57,6 +59,7 @@ namespace MWRender void configureFog(const ESM::Cell* cell); void configureFog(float fogDepth, const osg::Vec4f& colour); + void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); // TODO rename to setRotation/setPosition/setScale, along with the World equivalents @@ -66,6 +69,8 @@ namespace MWRender void setSkyEnabled(bool enabled); + bool toggleRenderMode(RenderMode mode); + SkyManager* getSkyManager(); osg::Vec3f getEyePos(); @@ -94,6 +99,7 @@ namespace MWRender osg::ref_ptr mSunLight; + std::auto_ptr mDebugging; std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp new file mode 100644 index 0000000000..a74d9bd526 --- /dev/null +++ b/apps/openmw/mwrender/rendermode.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWRENDER_RENDERMODE_H +#define OPENMW_MWRENDER_RENDERMODE_H + +namespace MWRender +{ + + enum RenderMode + { + Render_CollisionDebug, + Render_Wireframe, + Render_Pathgrid, + Render_BoundingBoxes + }; + +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4fd5b7e631..48de57239c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -34,7 +34,6 @@ #include "../mwworld/fallback.hpp" -#include "renderconst.hpp" #include "renderingmanager.hpp" namespace diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 48845c78c3..8726955568 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -11,6 +11,7 @@ namespace MWRender // child of Scene Mask_Effect = 0x2, + Mask_Debug = 0x4, // top level masks Mask_Scene = 0x10, diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 29f586a653..ce74c0c9f3 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -213,7 +213,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_CollisionDebug); runtime.getContext().report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); @@ -228,7 +228,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_BoundingBoxes); runtime.getContext().report (enabled ? "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); @@ -242,7 +242,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_Wireframe); runtime.getContext().report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); @@ -255,7 +255,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_Pathgrid); runtime.getContext().report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e61e5d84e8..637fde18ca 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -270,8 +270,8 @@ namespace MWWorld /// \todo rescale depending on the state of a new GMST insertCell (*cell, true, loadingListener); + mRendering.addCell(cell); #if 0 - mRendering.cellAdded (cell); bool waterEnabled = cell->getCell()->hasWater(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 842a24dedb..fda9d53af6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1501,9 +1501,9 @@ namespace MWWorld return 0;//mPhysics->toggleCollisionMode(); } - bool World::toggleRenderMode (RenderMode mode) + bool World::toggleRenderMode (MWRender::RenderMode mode) { - return 0;//mRendering->toggleRenderMode (mode); + return mRendering->toggleRenderMode (mode); } const ESM::Potion *World::createRecord (const ESM::Potion& record) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9598d43571..464f2d605a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -396,7 +396,7 @@ namespace MWWorld /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (RenderMode mode); + virtual bool toggleRenderMode (MWRender::RenderMode mode); ///< Toggle a render mode. ///< \return Resulting mode From 1943110170fb7c5242da9a4fa511f779fbc21121 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 00:39:01 +0200 Subject: [PATCH 0200/1812] Add bullet debug drawer --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/bulletdebugdraw.cpp | 98 ++++++++++++++++++++++++ apps/openmw/mwrender/bulletdebugdraw.hpp | 58 ++++++++++++++ apps/openmw/mwrender/debugging.cpp | 4 - apps/openmw/mwworld/physicssystem.cpp | 26 ++++++- apps/openmw/mwworld/physicssystem.hpp | 21 ++++- apps/openmw/mwworld/scene.cpp | 26 ++----- apps/openmw/mwworld/worldimp.cpp | 17 ++-- libs/openengine/bullet/physic.cpp | 46 +---------- libs/openengine/bullet/physic.hpp | 23 ------ 10 files changed, 221 insertions(+), 99 deletions(-) create mode 100644 apps/openmw/mwrender/bulletdebugdraw.cpp create mode 100644 apps/openmw/mwrender/bulletdebugdraw.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ed55301260..81cecc2c87 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,6 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface debugging rendermode + bulletdebugdraw # camera activatoranimation # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp new file mode 100644 index 0000000000..9e683232b1 --- /dev/null +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -0,0 +1,98 @@ +#include "bulletdebugdraw.hpp" + +#include + +#include +#include +#include + +#include "vismask.hpp" + +namespace +{ + osg::Vec3f toOsg(const btVector3& vec) + { + return osg::Vec3f(vec.x(), vec.y(), vec.z()); + } +} + +namespace MWRender +{ + +DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world) + : mParentNode(parentNode), + mWorld(world), + mDebugOn(true) +{ + mGeode = new osg::Geode; + mParentNode->addChild(mGeode); + mGeode->setNodeMask(Mask_Debug); + + mGeometry = new osg::Geometry; + + mVertices = new osg::Vec3Array; + + mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + + mGeometry->setUseDisplayList(false); + mGeometry->setVertexArray(mVertices); + mGeometry->setDataVariance(osg::Object::DYNAMIC); + mGeometry->addPrimitiveSet(mDrawArrays); + + mGeode->addDrawable(mGeometry); + mParentNode->addChild(mGeode); +} + +DebugDrawer::~DebugDrawer() +{ + mParentNode->removeChild(mGeode); +} + +void DebugDrawer::step() +{ + if (mDebugOn) + { + mVertices->clear(); + mWorld->debugDrawWorld(); + mDrawArrays->setCount(mVertices->size()); + mVertices->dirty(); + } +} + +void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) +{ + mVertices->push_back(toOsg(from)); + mVertices->push_back(toOsg(to)); +} + +void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color) +{ + mVertices->push_back(toOsg(PointOnB)); + mVertices->push_back(toOsg(PointOnB) + (toOsg(normalOnB) * distance * 20)); +} + +void DebugDrawer::reportErrorWarning(const char *warningString) +{ + std::cerr << warningString << std::endl; +} + +void DebugDrawer::setDebugMode(int isOn) +{ + mDebugOn = (isOn == 0) ? false : true; + + if (!mDebugOn) + { + mVertices->clear(); + mVertices->releaseGLObjects(0); + mGeometry->releaseGLObjects(0); + } +} + +int DebugDrawer::getDebugMode() const +{ + return mDebugOn; +} + + + +} diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp new file mode 100644 index 0000000000..288091e7ce --- /dev/null +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H +#define OPENMW_MWRENDER_BULLETDEBUGDRAW_H + +#include "btBulletDynamicsCommon.h" + +#include +#include +#include + +namespace osg +{ + class Group; + class Geode; + class Geometry; +} + +namespace MWRender +{ + +class DebugDrawer : public btIDebugDraw +{ +protected: + osg::ref_ptr mParentNode; + btDynamicsWorld *mWorld; + osg::ref_ptr mGeode; + osg::ref_ptr mGeometry; + osg::ref_ptr mVertices; + osg::ref_ptr mDrawArrays; + + bool mDebugOn; + +public: + + DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); + ~DebugDrawer(); + + void step(); + + void drawLine(const btVector3& from,const btVector3& to,const btVector3& color); + + void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color); + + void reportErrorWarning(const char* warningString); + + void draw3dText(const btVector3& location,const char* textString) {} + + //0 for off, anything else for on. + void setDebugMode(int isOn); + + //0 for off, anything else for on. + int getDebugMode() const; + +}; + + +} + +#endif diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 97ead9d7d3..9cbf94d46e 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -146,10 +146,6 @@ Debugging::~Debugging() bool Debugging::toggleRenderMode (int mode){ switch (mode) { - //case Render_CollisionDebug: - - //return mEngine->toggleDebugRendering(); - case Render_Pathgrid: togglePathgrid(); return mPathgridEnabled; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 271b23d098..4222683977 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include #include @@ -29,6 +31,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwrender/bulletdebugdraw.hpp" + //#include "../apps/openmw/mwrender/animation.hpp" #include "../apps/openmw/mwbase/world.hpp" #include "../apps/openmw/mwbase/environment.hpp" @@ -498,8 +502,8 @@ namespace MWWorld }; - PhysicsSystem::PhysicsSystem() : - mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0) + PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : + mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { // Create physics. shapeLoader is deleted by the physic engine //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); @@ -514,6 +518,21 @@ namespace MWWorld //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } + bool PhysicsSystem::toggleDebugRendering() + { + mDebugDrawEnabled = !mDebugDrawEnabled; + + if (mDebugDrawEnabled && !mDebugDrawer.get()) + { + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); + mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer->setDebugMode(mDebugDrawEnabled); + } + else if (mDebugDrawer.get()) + mDebugDrawer->setDebugMode(mDebugDrawEnabled); + return mDebugDrawEnabled; + } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; @@ -799,6 +818,9 @@ namespace MWWorld animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); mEngine->stepSimulation(dt); + + if (mDebugDrawer.get()) + mDebugDrawer->step(); } bool PhysicsSystem::isActorStandingOn(const Ptr &actor, const Ptr &object) const diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 23bf47543c..1fc0e0e768 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -7,8 +7,14 @@ #include +#include + #include "ptr.hpp" +namespace osg +{ + class Group; +} namespace OEngine { @@ -18,6 +24,11 @@ namespace OEngine } } +namespace MWRender +{ + class DebugDrawer; +} + namespace MWWorld { class World; @@ -27,7 +38,7 @@ namespace MWWorld class PhysicsSystem { public: - PhysicsSystem (); + PhysicsSystem (osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); @@ -98,10 +109,14 @@ namespace MWWorld /// Get the handle of all actors colliding with \a object in this frame. void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + bool toggleDebugRendering(); + private: void updateWater(); + bool mDebugDrawEnabled; + OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; @@ -123,6 +138,10 @@ namespace MWWorld std::auto_ptr mWaterCollisionObject; std::auto_ptr mWaterCollisionShape; + std::auto_ptr mDebugDrawer; + + osg::ref_ptr mParentNode; + PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 637fde18ca..1ccbc6b555 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -18,7 +18,7 @@ #include "../mwrender/renderingmanager.hpp" -//#include "physicssystem.hpp" +#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -26,8 +26,6 @@ #include "cellfunctors.hpp" #include "cellstore.hpp" -#include - namespace { @@ -194,26 +192,22 @@ namespace MWWorld ListAndResetHandles functor; (*iter)->forEach(functor); + for (std::vector::const_iterator iter2 (functor.mHandles.begin()); + iter2!=functor.mHandles.end(); ++iter2) { - // silence annoying g++ warning - for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2) - { - //Ogre::SceneNode* node = *iter2; - //mPhysics->removeObject (node->getName()); - } + //Ogre::SceneNode* node = *iter2; + //mPhysics->removeObject (node->getName()); } if ((*iter)->getCell()->isExterior()) { - /*ESM::Land* land = + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get().search( (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); - */ } mRendering.removeCell(*iter); @@ -234,10 +228,9 @@ namespace MWWorld { std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; - //float verts = ESM::Land::LAND_SIZE; - //float worldsize = ESM::Land::REAL_SIZE; + float verts = ESM::Land::LAND_SIZE; + float worldsize = ESM::Land::REAL_SIZE; -#if 0 // Load terrain physics first... if (cell->getCell()->isExterior()) { @@ -262,7 +255,6 @@ namespace MWWorld ; } } -#endif cell->respawn(); @@ -316,9 +308,7 @@ namespace MWWorld { int newX, newY; MWBase::Environment::get().getWorld()->positionToIndex(pos.x(), pos.y(), newX, newY); - osg::Timer timer; changeCellGrid(newX, newY); - std::cout << "changeCellGrid took " << timer.time_m() << std::endl; //mRendering.updateTerrain(); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fda9d53af6..04fd82e80a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -161,7 +161,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(); + mPhysics = new PhysicsSystem(rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -1409,9 +1409,8 @@ namespace MWWorld void World::doPhysics(float duration) { + mPhysics->stepSimulation(duration); #if 0 - //mPhysics->stepSimulation(duration); - processDoors(duration); mProjectileManager->update(duration); @@ -1503,7 +1502,13 @@ namespace MWWorld bool World::toggleRenderMode (MWRender::RenderMode mode) { - return mRendering->toggleRenderMode (mode); + switch (mode) + { + case MWRender::Render_CollisionDebug: + return mPhysics->toggleDebugRendering(); + default: + return mRendering->toggleRenderMode(mode); + } } const ESM::Potion *World::createRecord (const ESM::Potion& record) @@ -1601,8 +1606,8 @@ namespace MWWorld updateWeather(duration, paused); - //if (!paused) - // doPhysics (duration); + if (!paused) + doPhysics (duration); mWorldScene->update (duration, paused); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b1bd978c6b..35c767ca92 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -240,9 +240,7 @@ namespace Physic - PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) : - mDebugActive(0) - , mSceneMgr(NULL) + PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) { // Set up the collision configuration and dispatcher collisionConfiguration = new btDefaultCollisionConfiguration(); @@ -263,42 +261,6 @@ namespace Physic mDynamicsWorld->setGravity(btVector3(0,0,-10)); mShapeLoader = shapeLoader; - - isDebugCreated = false; - mDebugDrawer = NULL; - } - - void PhysicEngine::createDebugRendering() - { - if(!isDebugCreated) - { - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mDebugDrawer = new BtOgre::DebugDrawer(node, mDynamicsWorld); - mDynamicsWorld->setDebugDrawer(mDebugDrawer); - isDebugCreated = true; - mDynamicsWorld->debugDrawWorld(); - } - } - - void PhysicEngine::setDebugRenderingMode(bool isDebug) - { - if(!isDebugCreated) - { - createDebugRendering(); - } - mDebugDrawer->setDebugMode(isDebug); - mDebugActive = isDebug; - } - - bool PhysicEngine::toggleDebugRendering() - { - setDebugRenderingMode(!mDebugActive); - return mDebugActive; - } - - void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr) - { - mSceneMgr = sceneMgr; } PhysicEngine::~PhysicEngine() @@ -336,8 +298,6 @@ namespace Physic } } - delete mDebugDrawer; - delete mDynamicsWorld; delete solver; delete collisionConfiguration; @@ -652,10 +612,6 @@ namespace Physic { // This seems to be needed for character controller objects mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); - if(isDebugCreated) - { - mDebugDrawer->step(); - } } void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index e92e9c3c1c..6322105e8e 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -271,22 +271,6 @@ namespace Physic */ void stepSimulation(double deltaT); - /** - * Create a debug rendering. It is called by setDebgRenderingMode if it's not created yet. - * Important Note: this will crash if the Render is not yet initialise! - */ - void createDebugRendering(); - - /** - * Set the debug rendering mode. 0 to turn it off. - * Important Note: this will crash if the Render is not yet initialise! - */ - void setDebugRenderingMode(bool isDebug); - - bool toggleDebugRendering(); - - void setSceneManager(Ogre::SceneManager* sceneMgr); - /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) @@ -328,13 +312,6 @@ namespace Physic typedef std::map PhysicActorContainer; PhysicActorContainer mActorMap; - Ogre::SceneManager* mSceneMgr; - - //debug rendering - BtOgre::DebugDrawer* mDebugDrawer; - bool isDebugCreated; - bool mDebugActive; - private: PhysicEngine(const PhysicEngine&); PhysicEngine& operator=(const PhysicEngine&); From 92cbc139648daf586202ff551fdd4e0ab05cb765 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 00:50:56 +0200 Subject: [PATCH 0201/1812] Remove BtOgre --- apps/openmw/mwworld/physicssystem.cpp | 30 +- libs/openengine/CMakeLists.txt | 4 - libs/openengine/bullet/BtOgre.cpp | 1096 ------------------------- libs/openengine/bullet/BtOgreExtras.h | 284 ------- libs/openengine/bullet/BtOgreGP.h | 144 ---- libs/openengine/bullet/BtOgrePG.h | 81 -- libs/openengine/bullet/physic.cpp | 25 +- 7 files changed, 40 insertions(+), 1624 deletions(-) delete mode 100644 libs/openengine/bullet/BtOgre.cpp delete mode 100644 libs/openengine/bullet/BtOgreExtras.h delete mode 100644 libs/openengine/bullet/BtOgreGP.h delete mode 100644 libs/openengine/bullet/BtOgrePG.h diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 4222683977..6a08e8e1f3 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -14,7 +14,6 @@ #include #include -#include //#include #include @@ -93,6 +92,35 @@ void animateCollisionShapes (std::map -#include -#include - -using namespace Ogre; - -namespace BtOgre { - -/* - * ============================================================================================= - * BtOgre::VertexIndexToShape - * ============================================================================================= - */ - - void VertexIndexToShape::addStaticVertexData(const VertexData *vertex_data) - { - if (!vertex_data) - return; - - const VertexData *data = vertex_data; - - const unsigned int prev_size = mVertexCount; - mVertexCount += (unsigned int)data->vertexCount; - - Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount]; - if (mVertexBuffer) - { - memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size); - delete[] mVertexBuffer; - } - mVertexBuffer = tmp_vert; - - // Get the positional buffer element - { - const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); - Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - float* pReal; - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - const unsigned int vertexCount = (unsigned int)data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - posElem->baseVertexPointerToElement(vertex, &pReal); - vertex += vSize; - - curVertices->x = (*pReal++); - curVertices->y = (*pReal++); - curVertices->z = (*pReal++); - - *curVertices = mTransform * (*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - } - - //------------------------------------------------------------------------------------------------ - void VertexIndexToShape::addAnimatedVertexData(const Ogre::VertexData *vertex_data, - const Ogre::VertexData *blend_data, - const Ogre::Mesh::IndexMap *indexMap) - { - // Get the bone index element - assert(vertex_data); - - const VertexData *data = blend_data; - const unsigned int prev_size = mVertexCount; - mVertexCount += (unsigned int)data->vertexCount; - Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount]; - if (mVertexBuffer) - { - memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size); - delete[] mVertexBuffer; - } - mVertexBuffer = tmp_vert; - - // Get the positional buffer element - { - const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); - assert (posElem); - Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - float* pReal; - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - const unsigned int vertexCount = (unsigned int)data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - posElem->baseVertexPointerToElement(vertex, &pReal); - vertex += vSize; - - curVertices->x = (*pReal++); - curVertices->y = (*pReal++); - curVertices->z = (*pReal++); - - *curVertices = mTransform * (*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - - { - const Ogre::VertexElement* bneElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_BLEND_INDICES); - assert (bneElem); - - Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(bneElem->getSource()); - const unsigned int vSize = (unsigned int)vbuf->getVertexSize(); - unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); - - unsigned char* pBone; - - if (!mBoneIndex) - mBoneIndex = new BoneIndex(); - BoneIndex::iterator i; - - Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size]; - - const unsigned int vertexCount = (unsigned int)vertex_data->vertexCount; - for(unsigned int j = 0; j < vertexCount; ++j) - { - bneElem->baseVertexPointerToElement(vertex, &pBone); - vertex += vSize; - - const unsigned char currBone = (indexMap) ? (*indexMap)[*pBone] : *pBone; - i = mBoneIndex->find (currBone); - Vector3Array* l = 0; - if (i == mBoneIndex->end()) - { - l = new Vector3Array; - mBoneIndex->insert(std::make_pair(currBone, l)); - } - else - { - l = i->second; - } - - l->push_back(*curVertices); - - curVertices++; - } - vbuf->unlock(); - } - } - - //------------------------------------------------------------------------------------------------ - void VertexIndexToShape::addIndexData(IndexData *data, const unsigned int offset) - { - const unsigned int prev_size = mIndexCount; - mIndexCount += (unsigned int)data->indexCount; - - unsigned int* tmp_ind = new unsigned int[mIndexCount]; - if (mIndexBuffer) - { - memcpy (tmp_ind, mIndexBuffer, sizeof(unsigned int) * prev_size); - delete[] mIndexBuffer; - } - mIndexBuffer = tmp_ind; - - const unsigned int numTris = (unsigned int) data->indexCount / 3; - HardwareIndexBufferSharedPtr ibuf = data->indexBuffer; - const bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT); - unsigned int index_offset = prev_size; - - if (use32bitindexes) - { - const unsigned int* pInt = static_cast(ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); - for(unsigned int k = 0; k < numTris; ++k) - { - mIndexBuffer[index_offset ++] = offset + *pInt++; - mIndexBuffer[index_offset ++] = offset + *pInt++; - mIndexBuffer[index_offset ++] = offset + *pInt++; - } - ibuf->unlock(); - } - else - { - const unsigned short* pShort = static_cast(ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); - for(unsigned int k = 0; k < numTris; ++k) - { - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - mIndexBuffer[index_offset ++] = offset + static_cast (*pShort++); - } - ibuf->unlock(); - } - - } - - //------------------------------------------------------------------------------------------------ - Real VertexIndexToShape::getRadius() - { - if (mBoundRadius == (-1)) - { - getSize(); - mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5f); - } - return mBoundRadius; - } - - //------------------------------------------------------------------------------------------------ - Vector3 VertexIndexToShape::getSize() - { - const unsigned int vCount = getVertexCount(); - if (mBounds == Ogre::Vector3(-1,-1,-1) && vCount > 0) - { - - const Ogre::Vector3 * const v = getVertices(); - - Ogre::Vector3 vmin(v[0]); - Ogre::Vector3 vmax(v[0]); - - for(unsigned int j = 1; j < vCount; j++) - { - vmin.x = std::min(vmin.x, v[j].x); - vmin.y = std::min(vmin.y, v[j].y); - vmin.z = std::min(vmin.z, v[j].z); - - vmax.x = std::max(vmax.x, v[j].x); - vmax.y = std::max(vmax.y, v[j].y); - vmax.z = std::max(vmax.z, v[j].z); - } - - mBounds.x = vmax.x - vmin.x; - mBounds.y = vmax.y - vmin.y; - mBounds.z = vmax.z - vmin.z; - } - - return mBounds; - } - - //------------------------------------------------------------------------------------------------ - const Ogre::Vector3* VertexIndexToShape::getVertices() - { - return mVertexBuffer; - } - - //------------------------------------------------------------------------------------------------ - unsigned int VertexIndexToShape::getVertexCount() - { - return mVertexCount; - } - - //------------------------------------------------------------------------------------------------ - const unsigned int* VertexIndexToShape::getIndices() - { - return mIndexBuffer; - } - - //------------------------------------------------------------------------------------------------ - unsigned int VertexIndexToShape::getIndexCount() - { - return mIndexCount; - } - - //------------------------------------------------------------------------------------------------ - btSphereShape* VertexIndexToShape::createSphere() - { - const Ogre::Real rad = getRadius(); - assert((rad > 0.0) && - ("Sphere radius must be greater than zero")); - btSphereShape* shape = new btSphereShape(rad); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape* VertexIndexToShape::createBox() - { - const Ogre::Vector3 sz = getSize(); - - assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.z > 0.0) && - ("Size of box must be greater than zero on all axes")); - - btBoxShape* shape = new btBoxShape(Convert::toBullet(sz * 0.5)); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btCylinderShape* VertexIndexToShape::createCylinder() - { - const Ogre::Vector3 sz = getSize(); - - assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.z > 0.0) && - ("Size of Cylinder must be greater than zero on all axes")); - - btCylinderShape* shape = new btCylinderShapeX(Convert::toBullet(sz * 0.5)); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - btConvexHullShape* VertexIndexToShape::createConvex() - { - assert(mVertexCount && (mIndexCount >= 6) && - ("Mesh must have some vertices and at least 6 indices (2 triangles)")); - - return new btConvexHullShape((btScalar*) &mVertexBuffer[0].x, mVertexCount, sizeof(Vector3)); - } - - //------------------------------------------------------------------------------------------------ - btBvhTriangleMeshShape* VertexIndexToShape::createTrimesh() - { - assert(mVertexCount && (mIndexCount >= 6) && - ("Mesh must have some vertices and at least 6 indices (2 triangles)")); - - unsigned int numFaces = mIndexCount / 3; - - btTriangleMesh *trimesh = new btTriangleMesh(); - unsigned int *indices = mIndexBuffer; - Vector3 *vertices = mVertexBuffer; - - btVector3 vertexPos[3]; - for (unsigned int n = 0; n < numFaces; ++n) - { - { - const Vector3 &vec = vertices[*indices]; - vertexPos[0][0] = vec.x; - vertexPos[0][1] = vec.y; - vertexPos[0][2] = vec.z; - } - { - const Vector3 &vec = vertices[*(indices + 1)]; - vertexPos[1][0] = vec.x; - vertexPos[1][1] = vec.y; - vertexPos[1][2] = vec.z; - } - { - const Vector3 &vec = vertices[*(indices + 2)]; - vertexPos[2][0] = vec.x; - vertexPos[2][1] = vec.y; - vertexPos[2][2] = vec.z; - } - - indices += 3; - - trimesh->addTriangle(vertexPos[0], vertexPos[1], vertexPos[2]); - } - - const bool useQuantizedAABB = true; - btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(trimesh, useQuantizedAABB); - - shape->setLocalScaling(Convert::toBullet(mScale)); - - return shape; - } - - //------------------------------------------------------------------------------------------------ - VertexIndexToShape::~VertexIndexToShape() - { - delete[] mVertexBuffer; - delete[] mIndexBuffer; - - if (mBoneIndex) - { - for(BoneIndex::iterator i = mBoneIndex->begin(); - i != mBoneIndex->end(); - ++i) - { - delete i->second; - } - delete mBoneIndex; - } - } - - //------------------------------------------------------------------------------------------------ - VertexIndexToShape::VertexIndexToShape(const Matrix4 &transform) : - mVertexBuffer (0), - mIndexBuffer (0), - mVertexCount (0), - mIndexCount (0), - mTransform (transform), - mBoundRadius (-1), - mBounds (Vector3(-1,-1,-1)), - mBoneIndex (0), - mScale(1) - { - } - -/* - * ============================================================================================= - * BtOgre::StaticMeshToShapeConverter - * ============================================================================================= - */ - - StaticMeshToShapeConverter::StaticMeshToShapeConverter() : - VertexIndexToShape(), - mEntity (0), - mNode (0) - { - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::~StaticMeshToShapeConverter() - { - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::StaticMeshToShapeConverter(Entity *entity, const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0) - { - addEntity(entity, transform); - } - - //------------------------------------------------------------------------------------------------ - StaticMeshToShapeConverter::StaticMeshToShapeConverter(Renderable *rend, const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0) - { - RenderOperation op; - rend->getRenderOperation(op); - VertexIndexToShape::addStaticVertexData(op.vertexData); - if(op.useIndexes) - VertexIndexToShape::addIndexData(op.indexData); - - } - - //------------------------------------------------------------------------------------------------ - void StaticMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - mEntity = entity; - mNode = (SceneNode*)(mEntity->getParentNode()); - mTransform = transform; - mScale = mNode->getScale(); - - if (mEntity->getMesh()->sharedVertexData) - { - VertexIndexToShape::addStaticVertexData (mEntity->getMesh()->sharedVertexData); - } - - for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i) - { - SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh(); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - - //------------------------------------------------------------------------------------------------ - void StaticMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - //_entity = entity; - //_node = (SceneNode*)(_entity->getParentNode()); - mTransform = transform; - - if (mesh->hasSkeleton ()) - Ogre::LogManager::getSingleton().logMessage("MeshToShapeConverter::addMesh : Mesh " + mesh->getName () + " as skeleton but added to trimesh non animated"); - - if (mesh->sharedVertexData) - { - VertexIndexToShape::addStaticVertexData (mesh->sharedVertexData); - } - - for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i) - { - SubMesh *sub_mesh = mesh->getSubMesh(i); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - -/* - * ============================================================================================= - * BtOgre::AnimatedMeshToShapeConverter - * ============================================================================================= - */ - - AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter(Entity *entity,const Matrix4 &transform) : - VertexIndexToShape(transform), - mEntity (0), - mNode (0), - mTransformedVerticesTemp(0), - mTransformedVerticesTempSize(0) - { - addEntity(entity, transform); - } - - //------------------------------------------------------------------------------------------------ - AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter() : - VertexIndexToShape(), - mEntity (0), - mNode (0), - mTransformedVerticesTemp(0), - mTransformedVerticesTempSize(0) - { - } - - //------------------------------------------------------------------------------------------------ - AnimatedMeshToShapeConverter::~AnimatedMeshToShapeConverter() - { - delete[] mTransformedVerticesTemp; - } - - //------------------------------------------------------------------------------------------------ - void AnimatedMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - mEntity = entity; - mNode = (SceneNode*)(mEntity->getParentNode()); - mTransform = transform; - - assert (entity->getMesh()->hasSkeleton ()); - - mEntity->addSoftwareAnimationRequest(false); - mEntity->_updateAnimation(); - - if (mEntity->getMesh()->sharedVertexData) - { - VertexIndexToShape::addAnimatedVertexData (mEntity->getMesh()->sharedVertexData, - mEntity->_getSkelAnimVertexData(), - &mEntity->getMesh()->sharedBlendIndexToBoneIndexMap); - } - - for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i) - { - SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh(); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - - VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData, - mEntity->getSubEntity(i)->_getSkelAnimVertexData(), - &sub_mesh->blendIndexToBoneIndexMap); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - - mEntity->removeSoftwareAnimationRequest(false); - } - - //------------------------------------------------------------------------------------------------ - void AnimatedMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform) - { - // Each entity added need to reset size and radius - // next time getRadius and getSize are asked, they're computed. - mBounds = Ogre::Vector3(-1,-1,-1); - mBoundRadius = -1; - - //_entity = entity; - //_node = (SceneNode*)(_entity->getParentNode()); - mTransform = transform; - - assert (mesh->hasSkeleton ()); - - if (mesh->sharedVertexData) - { - VertexIndexToShape::addAnimatedVertexData (mesh->sharedVertexData, - 0, - &mesh->sharedBlendIndexToBoneIndexMap); - } - - for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i) - { - SubMesh *sub_mesh = mesh->getSubMesh(i); - - if (!sub_mesh->useSharedVertices) - { - VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount); - - VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData, - 0, - &sub_mesh->blendIndexToBoneIndexMap); - } - else - { - VertexIndexToShape::addIndexData (sub_mesh->indexData); - } - - } - } - - //------------------------------------------------------------------------------------------------ - bool AnimatedMeshToShapeConverter::getBoneVertices(unsigned char bone, - unsigned int &vertex_count, - Ogre::Vector3* &vertices, - const Vector3 &bonePosition) - { - BoneIndex::iterator i = mBoneIndex->find(bone); - - if (i == mBoneIndex->end()) - return false; - - if (i->second->empty()) - return false; - - vertex_count = (unsigned int) i->second->size() + 1; - if (vertex_count > mTransformedVerticesTempSize) - { - if (mTransformedVerticesTemp) - delete[] mTransformedVerticesTemp; - - mTransformedVerticesTemp = new Ogre::Vector3[vertex_count]; - - } - - vertices = mTransformedVerticesTemp; - vertices[0] = bonePosition; - //mEntity->_getParentNodeFullTransform() * - //mEntity->getSkeleton()->getBone(bone)->_getDerivedPosition(); - - //mEntity->getSkeleton()->getBone(bone)->_getDerivedOrientation() - unsigned int currBoneVertex = 1; - Vector3Array::iterator j = i->second->begin(); - while(j != i->second->end()) - { - vertices[currBoneVertex] = (*j); - ++j; - ++currBoneVertex; - } - return true; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape* AnimatedMeshToShapeConverter::createAlignedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation) - { - unsigned int vertex_count; - Vector3* vertices; - - if (!getBoneVertices(bone, vertex_count, vertices, bonePosition)) - return 0; - - Vector3 min_vec(vertices[0]); - Vector3 max_vec(vertices[0]); - - for(unsigned int j = 1; j < vertex_count ;j++) - { - min_vec.x = std::min(min_vec.x,vertices[j].x); - min_vec.y = std::min(min_vec.y,vertices[j].y); - min_vec.z = std::min(min_vec.z,vertices[j].z); - - max_vec.x = std::max(max_vec.x,vertices[j].x); - max_vec.y = std::max(max_vec.y,vertices[j].y); - max_vec.z = std::max(max_vec.z,vertices[j].z); - } - const Ogre::Vector3 maxMinusMin(max_vec - min_vec); - btBoxShape* box = new btBoxShape(Convert::toBullet(maxMinusMin)); - - /*const Ogre::Vector3 pos - (min_vec.x + (maxMinusMin.x * 0.5), - min_vec.y + (maxMinusMin.y * 0.5), - min_vec.z + (maxMinusMin.z * 0.5));*/ - - //box->setPosition(pos); - - return box; - } - - //------------------------------------------------------------------------------------------------ - bool AnimatedMeshToShapeConverter::getOrientedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation, - Vector3 &box_afExtent, - Vector3 *box_akAxis, - Vector3 &box_kCenter) - { - unsigned int vertex_count; - Vector3* vertices; - - if (!getBoneVertices(bone, vertex_count, vertices, bonePosition)) - return false; - - box_kCenter = Vector3::ZERO; - - { - for(unsigned int c = 0 ;c < vertex_count;c++) - { - box_kCenter += vertices[c]; - } - const Ogre::Real invVertexCount = 1.0f / vertex_count; - box_kCenter *= invVertexCount; - } - Quaternion orient = boneOrientation; - orient.ToAxes(box_akAxis); - - // Let C be the box center and let U0, U1, and U2 be the box axes. Each - // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The - // following code computes min(y0), max(y0), min(y1), max(y1), min(y2), - // and max(y2). The box center is then adjusted to be - // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 + - // 0.5*(min(y2)+max(y2))*U2 - - Ogre::Vector3 kDiff (vertices[1] - box_kCenter); - Ogre::Real fY0Min = kDiff.dotProduct(box_akAxis[0]), fY0Max = fY0Min; - Ogre::Real fY1Min = kDiff.dotProduct(box_akAxis[1]), fY1Max = fY1Min; - Ogre::Real fY2Min = kDiff.dotProduct(box_akAxis[2]), fY2Max = fY2Min; - - for (unsigned int i = 2; i < vertex_count; i++) - { - kDiff = vertices[i] - box_kCenter; - - const Ogre::Real fY0 = kDiff.dotProduct(box_akAxis[0]); - if ( fY0 < fY0Min ) - fY0Min = fY0; - else if ( fY0 > fY0Max ) - fY0Max = fY0; - - const Ogre::Real fY1 = kDiff.dotProduct(box_akAxis[1]); - if ( fY1 < fY1Min ) - fY1Min = fY1; - else if ( fY1 > fY1Max ) - fY1Max = fY1; - - const Ogre::Real fY2 = kDiff.dotProduct(box_akAxis[2]); - if ( fY2 < fY2Min ) - fY2Min = fY2; - else if ( fY2 > fY2Max ) - fY2Max = fY2; - } - - box_afExtent.x = ((Real)0.5)*(fY0Max - fY0Min); - box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min); - box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min); - - box_kCenter += (0.5f*(fY0Max+fY0Min))*box_akAxis[0] + - (0.5f*(fY1Max+fY1Min))*box_akAxis[1] + - (0.5f*(fY2Max+fY2Min))*box_akAxis[2]; - - box_afExtent *= 2.0; - - return true; - } - - //------------------------------------------------------------------------------------------------ - btBoxShape *AnimatedMeshToShapeConverter::createOrientedBox(unsigned char bone, - const Vector3 &bonePosition, - const Quaternion &boneOrientation) - { - Ogre::Vector3 box_akAxis[3]; - Ogre::Vector3 box_afExtent; - Ogre::Vector3 box_afCenter; - - if (!getOrientedBox(bone, bonePosition, boneOrientation, - box_afExtent, - box_akAxis, - box_afCenter)) - return 0; - - btBoxShape *geom = new btBoxShape(Convert::toBullet(box_afExtent)); - //geom->setOrientation(Quaternion(box_akAxis[0],box_akAxis[1],box_akAxis[2])); - //geom->setPosition(box_afCenter); - return geom; - } - -/* - * ============================================================================================= - * BtOgre::DynamicRenderable - * ============================================================================================= - */ - - DynamicRenderable::DynamicRenderable() - : mVertexBufferCapacity(0) - , mIndexBufferCapacity(0) - { - } - - //------------------------------------------------------------------------------------------------ - DynamicRenderable::~DynamicRenderable() - { - delete mRenderOp.vertexData; - delete mRenderOp.indexData; - } - - //------------------------------------------------------------------------------------------------ - void DynamicRenderable::initialize(RenderOperation::OperationType operationType, - bool useIndices) - { - // Initialize render operation - mRenderOp.operationType = operationType; - mRenderOp.useIndexes = useIndices; - mRenderOp.vertexData = new VertexData; - if (mRenderOp.useIndexes) - mRenderOp.indexData = new IndexData; - - // Reset buffer capacities - mVertexBufferCapacity = 0; - mIndexBufferCapacity = 0; - - // Create vertex declaration - createVertexDeclaration(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicRenderable::prepareHardwareBuffers(size_t vertexCount, - size_t indexCount) - { - // Prepare vertex buffer - size_t newVertCapacity = mVertexBufferCapacity; - if ((vertexCount > mVertexBufferCapacity) || - (!mVertexBufferCapacity)) - { - // vertexCount exceeds current capacity! - // It is necessary to reallocate the buffer. - - // Check if this is the first call - if (!newVertCapacity) - newVertCapacity = 1; - - // Make capacity the next power of two - while (newVertCapacity < vertexCount) - newVertCapacity <<= 1; - } - else if (vertexCount < mVertexBufferCapacity>>1) { - // Make capacity the previous power of two - while (vertexCount < newVertCapacity>>1) - newVertCapacity >>= 1; - } - if (newVertCapacity != mVertexBufferCapacity) - { - mVertexBufferCapacity = newVertCapacity; - // Create new vertex buffer - HardwareVertexBufferSharedPtr vbuf = - HardwareBufferManager::getSingleton().createVertexBuffer( - mRenderOp.vertexData->vertexDeclaration->getVertexSize(0), - mVertexBufferCapacity, - HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_? - - // Bind buffer - mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf); - } - // Update vertex count in the render operation - mRenderOp.vertexData->vertexCount = vertexCount; - - if (mRenderOp.useIndexes) - { - OgreAssert(indexCount <= std::numeric_limits::max(), "indexCount exceeds 16 bit"); - - size_t newIndexCapacity = mIndexBufferCapacity; - // Prepare index buffer - if ((indexCount > newIndexCapacity) || - (!newIndexCapacity)) - { - // indexCount exceeds current capacity! - // It is necessary to reallocate the buffer. - - // Check if this is the first call - if (!newIndexCapacity) - newIndexCapacity = 1; - - // Make capacity the next power of two - while (newIndexCapacity < indexCount) - newIndexCapacity <<= 1; - - } - else if (indexCount < newIndexCapacity>>1) - { - // Make capacity the previous power of two - while (indexCount < newIndexCapacity>>1) - newIndexCapacity >>= 1; - } - - if (newIndexCapacity != mIndexBufferCapacity) - { - mIndexBufferCapacity = newIndexCapacity; - // Create new index buffer - mRenderOp.indexData->indexBuffer = - HardwareBufferManager::getSingleton().createIndexBuffer( - HardwareIndexBuffer::IT_16BIT, - mIndexBufferCapacity, - HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_? - } - - // Update index count in the render operation - mRenderOp.indexData->indexCount = indexCount; - } - } - - //------------------------------------------------------------------------------------------------ - Real DynamicRenderable::getBoundingRadius(void) const - { - return Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength())); - } - - //------------------------------------------------------------------------------------------------ - Real DynamicRenderable::getSquaredViewDepth(const Camera* cam) const - { - Vector3 vMin, vMax, vMid, vDist; - vMin = mBox.getMinimum(); - vMax = mBox.getMaximum(); - vMid = ((vMax - vMin) * 0.5) + vMin; - vDist = cam->getDerivedPosition() - vMid; - - return vDist.squaredLength(); - } - -/* - * ============================================================================================= - * BtOgre::DynamicLines - * ============================================================================================= - */ - - enum { - POSITION_BINDING, - TEXCOORD_BINDING - }; - - //------------------------------------------------------------------------------------------------ - DynamicLines::DynamicLines(OperationType opType) - { - initialize(opType,false); - setMaterial("BaseWhiteNoLighting"); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - DynamicLines::~DynamicLines() - { - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::setOperationType(OperationType opType) - { - mRenderOp.operationType = opType; - } - - //------------------------------------------------------------------------------------------------ - RenderOperation::OperationType DynamicLines::getOperationType() const - { - return mRenderOp.operationType; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::addPoint(const Vector3 &p) - { - mPoints.push_back(p); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::addPoint(Real x, Real y, Real z) - { - mPoints.push_back(Vector3(x,y,z)); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - const Vector3& DynamicLines::getPoint(unsigned short index) const - { - assert(index < mPoints.size() && "Point index is out of bounds!!"); - return mPoints[index]; - } - - //------------------------------------------------------------------------------------------------ - unsigned short DynamicLines::getNumPoints(void) const - { - return (unsigned short)mPoints.size(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::setPoint(unsigned short index, const Vector3 &value) - { - assert(index < mPoints.size() && "Point index is out of bounds!!"); - - mPoints[index] = value; - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::clear() - { - mPoints.clear(); - mDirty = true; - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::update() - { - if (mDirty) fillHardwareBuffers(); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::createVertexDeclaration() - { - VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration; - decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION); - } - - //------------------------------------------------------------------------------------------------ - void DynamicLines::fillHardwareBuffers() - { - int size = mPoints.size(); - - prepareHardwareBuffers(size,0); - - if (!size) { - mBox.setExtents(Vector3::ZERO,Vector3::ZERO); - mDirty=false; - return; - } - - Vector3 vaabMin = mPoints[0]; - Vector3 vaabMax = mPoints[0]; - - HardwareVertexBufferSharedPtr vbuf = - mRenderOp.vertexData->vertexBufferBinding->getBuffer(0); - - Real *prPos = static_cast(vbuf->lock(HardwareBuffer::HBL_DISCARD)); - { - for(int i = 0; i < size; i++) - { - *prPos++ = mPoints[i].x; - *prPos++ = mPoints[i].y; - *prPos++ = mPoints[i].z; - - if(mPoints[i].x < vaabMin.x) - vaabMin.x = mPoints[i].x; - if(mPoints[i].y < vaabMin.y) - vaabMin.y = mPoints[i].y; - if(mPoints[i].z < vaabMin.z) - vaabMin.z = mPoints[i].z; - - if(mPoints[i].x > vaabMax.x) - vaabMax.x = mPoints[i].x; - if(mPoints[i].y > vaabMax.y) - vaabMax.y = mPoints[i].y; - if(mPoints[i].z > vaabMax.z) - vaabMax.z = mPoints[i].z; - } - } - vbuf->unlock(); - - mBox.setExtents(vaabMin, vaabMax); - - mDirty = false; - } -} diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h deleted file mode 100644 index f8c1fe41d0..0000000000 --- a/libs/openengine/bullet/BtOgreExtras.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgreExtras.h - * - * Description: Contains the Ogre Mesh to Bullet Shape converters. - * - * Version: 1.0 - * Created: 27/12/2008 01:45:56 PM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgreShapes_H_ -#define BtOgreShapes_H_ - -#include "btBulletDynamicsCommon.h" -#include "OgreSimpleRenderable.h" -#include "OgreCamera.h" -#include "OgreHardwareBufferManager.h" -#include "OgreMaterialManager.h" -#include "OgreTechnique.h" -#include "OgrePass.h" - -#include "OgreLogManager.h" - -namespace BtOgre -{ - -typedef std::vector Vector3Array; - -//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory. -class Convert -{ -public: - Convert() {}; - ~Convert() {}; - - static btQuaternion toBullet(const Ogre::Quaternion &q) - { - return btQuaternion(q.x, q.y, q.z, q.w); - } - static btVector3 toBullet(const Ogre::Vector3 &v) - { - return btVector3(v.x, v.y, v.z); - } - - static Ogre::Quaternion toOgre(const btQuaternion &q) - { - return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z()); - } - static Ogre::Vector3 toOgre(const btVector3 &v) - { - return Ogre::Vector3(v.x(), v.y(), v.z()); - } -}; - -//From here on its debug-drawing stuff. ------------------------------------------------------------------ - -class DynamicRenderable : public Ogre::SimpleRenderable -{ -public: - /// Constructor - DynamicRenderable(); - /// Virtual destructor - virtual ~DynamicRenderable(); - - /** Initializes the dynamic renderable. - @remarks - This function should only be called once. It initializes the - render operation, and calls the abstract function - createVertexDeclaration(). - @param operationType The type of render operation to perform. - @param useIndices Specifies whether to use indices to determine the - vertices to use as input. */ - void initialize(Ogre::RenderOperation::OperationType operationType, - bool useIndices); - - /// Implementation of Ogre::SimpleRenderable - virtual Ogre::Real getBoundingRadius(void) const; - /// Implementation of Ogre::SimpleRenderable - virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const; - -protected: - /// Maximum capacity of the currently allocated vertex buffer. - size_t mVertexBufferCapacity; - /// Maximum capacity of the currently allocated index buffer. - size_t mIndexBufferCapacity; - - /** Creates the vertex declaration. - @remarks - Override and set mRenderOp.vertexData->vertexDeclaration here. - mRenderOp.vertexData will be created for you before this method - is called. */ - virtual void createVertexDeclaration() = 0; - - /** Prepares the hardware buffers for the requested vertex and index counts. - @remarks - This function must be called before locking the buffers in - fillHardwareBuffers(). It guarantees that the hardware buffers - are large enough to hold at least the requested number of - vertices and indices (if using indices). The buffers are - possibly reallocated to achieve this. - @par - The vertex and index count in the render operation are set to - the values of vertexCount and indexCount respectively. - @param vertexCount The number of vertices the buffer must hold. - - @param indexCount The number of indices the buffer must hold. This - parameter is ignored if not using indices. */ - void prepareHardwareBuffers(size_t vertexCount, size_t indexCount); - - /** Fills the hardware vertex and index buffers with data. - @remarks - This function must call prepareHardwareBuffers() before locking - the buffers to ensure the they are large enough for the data to - be written. Afterwards the vertex and index buffers (if using - indices) can be locked, and data can be written to them. */ - virtual void fillHardwareBuffers() = 0; -}; - -class DynamicLines : public DynamicRenderable -{ - typedef Ogre::Vector3 Vector3; - typedef Ogre::Quaternion Quaternion; - typedef Ogre::Camera Camera; - typedef Ogre::Real Real; - typedef Ogre::RenderOperation::OperationType OperationType; - -public: - /// Constructor - see setOperationType() for description of argument. - DynamicLines(OperationType opType=Ogre::RenderOperation::OT_LINE_STRIP); - virtual ~DynamicLines(); - - /// Add a point to the point list - void addPoint(const Ogre::Vector3 &p); - /// Add a point to the point list - void addPoint(Real x, Real y, Real z); - - /// Change the location of an existing point in the point list - void setPoint(unsigned short index, const Vector3 &value); - - /// Return the location of an existing point in the point list - const Vector3& getPoint(unsigned short index) const; - - /// Return the total number of points in the point list - unsigned short getNumPoints(void) const; - - /// Remove all points from the point list - void clear(); - - /// Call this to update the hardware buffer after making changes. - void update(); - - /** Set the type of operation to draw with. - * @param opType Can be one of - * - RenderOperation::OT_LINE_STRIP - * - RenderOperation::OT_LINE_LIST - * - RenderOperation::OT_POINT_LIST - * - RenderOperation::OT_TRIANGLE_LIST - * - RenderOperation::OT_TRIANGLE_STRIP - * - RenderOperation::OT_TRIANGLE_FAN - * The default is OT_LINE_STRIP. - */ - void setOperationType(OperationType opType); - OperationType getOperationType() const; - -protected: - /// Implementation DynamicRenderable, creates a simple vertex-only decl - virtual void createVertexDeclaration(); - /// Implementation DynamicRenderable, pushes point list out to hardware memory - virtual void fillHardwareBuffers(); - -private: - std::vector mPoints; - bool mDirty; -}; - -class DebugDrawer : public btIDebugDraw -{ -protected: - Ogre::SceneNode *mNode; - btDynamicsWorld *mWorld; - DynamicLines *mLineDrawer; - bool mDebugOn; - -public: - - DebugDrawer(Ogre::SceneNode *node, btDynamicsWorld *world) - : mNode(node), - mWorld(world), - mDebugOn(true) - { - mLineDrawer = new DynamicLines(Ogre::RenderOperation::OT_LINE_LIST); - mNode->attachObject(mLineDrawer); - - if (!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().createResourceGroup("BtOgre"); - if (!Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - { - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("BtOgre/DebugLines", "BtOgre"); - mat->setReceiveShadows(false); - mat->setSelfIllumination(1,1,1); - } - - mLineDrawer->setMaterial("BtOgre/DebugLines"); - - //mLineDrawer->setVisibilityFlags (1024); - } - - ~DebugDrawer() - { - if (Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); - if (Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); - delete mLineDrawer; - } - - void step() - { - if (mDebugOn) - { - mWorld->debugDrawWorld(); - mLineDrawer->update(); - mNode->needUpdate(); - mLineDrawer->clear(); - } - else - { - mLineDrawer->clear(); - mLineDrawer->update(); - mNode->needUpdate(); - } - } - - void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) - { - mLineDrawer->addPoint(Convert::toOgre(from)); - mLineDrawer->addPoint(Convert::toOgre(to)); - } - - void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) - { - mLineDrawer->addPoint(Convert::toOgre(PointOnB)); - mLineDrawer->addPoint(Convert::toOgre(PointOnB) + (Convert::toOgre(normalOnB) * distance * 20)); - } - - void reportErrorWarning(const char* warningString) - { - Ogre::LogManager::getSingleton().logMessage(warningString); - } - - void draw3dText(const btVector3& location,const char* textString) - { - } - - //0 for off, anything else for on. - void setDebugMode(int isOn) - { - mDebugOn = (isOn == 0) ? false : true; - - if (!mDebugOn) - mLineDrawer->clear(); - } - - //0 for off, anything else for on. - int getDebugMode() const - { - return mDebugOn; - } - -}; - -} - -#endif - - - - - diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h deleted file mode 100644 index 7e497b5352..0000000000 --- a/libs/openengine/bullet/BtOgreGP.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgreGP.h - * - * Description: The part of BtOgre that handles information transfer from Ogre to - * Bullet (like mesh data for making trimeshes). - * - * Version: 1.0 - * Created: 27/12/2008 03:29:56 AM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgrePG_H_ -#define BtOgrePG_H_ - -#include "btBulletDynamicsCommon.h" -#include "BtOgreExtras.h" - -#include -#include -#include - -namespace BtOgre { - -typedef std::map BoneIndex; - -class VertexIndexToShape -{ -public: - VertexIndexToShape(const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - ~VertexIndexToShape(); - - Ogre::Real getRadius(); - Ogre::Vector3 getSize(); - - - btSphereShape* createSphere(); - btBoxShape* createBox(); - btBvhTriangleMeshShape* createTrimesh(); - btCylinderShape* createCylinder(); - btConvexHullShape* createConvex(); - - const Ogre::Vector3* getVertices(); - unsigned int getVertexCount(); - const unsigned int* getIndices(); - unsigned int getIndexCount(); - -protected: - - void addStaticVertexData(const Ogre::VertexData *vertex_data); - - void addAnimatedVertexData(const Ogre::VertexData *vertex_data, - const Ogre::VertexData *blended_data, - const Ogre::Mesh::IndexMap *indexMap); - - void addIndexData(Ogre::IndexData *data, const unsigned int offset = 0); - - -protected: - Ogre::Vector3* mVertexBuffer; - unsigned int* mIndexBuffer; - unsigned int mVertexCount; - unsigned int mIndexCount; - - Ogre::Matrix4 mTransform; - - Ogre::Real mBoundRadius; - Ogre::Vector3 mBounds; - - BoneIndex *mBoneIndex; - - Ogre::Vector3 mScale; -}; - -//For static (non-animated) meshes. -class StaticMeshToShapeConverter : public VertexIndexToShape -{ -public: - - StaticMeshToShapeConverter(Ogre::Renderable *rend, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - StaticMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - StaticMeshToShapeConverter(); - - ~StaticMeshToShapeConverter(); - - void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - - void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - - -protected: - - Ogre::Entity* mEntity; - Ogre::SceneNode* mNode; -}; - -//For animated meshes. -class AnimatedMeshToShapeConverter : public VertexIndexToShape -{ -public: - - AnimatedMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - AnimatedMeshToShapeConverter(); - ~AnimatedMeshToShapeConverter(); - - void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY); - void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform); - - btBoxShape* createAlignedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation); - - btBoxShape* createOrientedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation); - -protected: - - bool getBoneVertices(unsigned char bone, - unsigned int &vertex_count, - Ogre::Vector3* &vertices, - const Ogre::Vector3 &bonePosition); - - bool getOrientedBox(unsigned char bone, - const Ogre::Vector3 &bonePosition, - const Ogre::Quaternion &boneOrientation, - Ogre::Vector3 &extents, - Ogre::Vector3 *axis, - Ogre::Vector3 ¢er); - - Ogre::Entity* mEntity; - Ogre::SceneNode* mNode; - - Ogre::Vector3 *mTransformedVerticesTemp; - size_t mTransformedVerticesTempSize; -}; - -} - -#endif diff --git a/libs/openengine/bullet/BtOgrePG.h b/libs/openengine/bullet/BtOgrePG.h deleted file mode 100644 index 2e42fe1f91..0000000000 --- a/libs/openengine/bullet/BtOgrePG.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: BtOgrePG.h - * - * Description: The part of BtOgre that handles information transfer from Bullet to - * Ogre (like updating graphics object positions). - * - * Version: 1.0 - * Created: 27/12/2008 03:40:56 AM - * - * Author: Nikhilesh (nikki) - * - * ===================================================================================== - */ - -#ifndef BtOgreGP_H_ -#define BtOgreGP_H_ - -#include "btBulletDynamicsCommon.h" -#include "OgreSceneNode.h" -#include "BtOgreExtras.h" - -namespace BtOgre { - -//A MotionState is Bullet's way of informing you about updates to an object. -//Pass this MotionState to a btRigidBody to have your SceneNode updated automaticaly. -class RigidBodyState : public btMotionState -{ - protected: - btTransform mTransform; - btTransform mCenterOfMassOffset; - - Ogre::SceneNode *mNode; - - public: - RigidBodyState(Ogre::SceneNode *node, const btTransform &transform, const btTransform &offset = btTransform::getIdentity()) - : mTransform(transform), - mCenterOfMassOffset(offset), - mNode(node) - { - } - - RigidBodyState(Ogre::SceneNode *node) - : mTransform(((node != NULL) ? BtOgre::Convert::toBullet(node->getOrientation()) : btQuaternion(0,0,0,1)), - ((node != NULL) ? BtOgre::Convert::toBullet(node->getPosition()) : btVector3(0,0,0))), - mCenterOfMassOffset(btTransform::getIdentity()), - mNode(node) - { - } - - virtual void getWorldTransform(btTransform &ret) const - { - ret = mCenterOfMassOffset.inverse() * mTransform; - } - - virtual void setWorldTransform(const btTransform &in) - { - if (mNode == NULL) - return; - - mTransform = in; - btTransform transform = in * mCenterOfMassOffset; - - btQuaternion rot = transform.getRotation(); - btVector3 pos = transform.getOrigin(); - mNode->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); - mNode->setPosition(pos.x(), pos.y(), pos.z()); - } - - void setNode(Ogre::SceneNode *node) - { - mNode = node; - } -}; - -//Softbody-Ogre connection goes here! - -} - -#endif diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 35c767ca92..11b6b18349 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -12,10 +12,6 @@ #include #include -#include "BtOgrePG.h" -#include "BtOgreGP.h" -#include "BtOgreExtras.h" - namespace { @@ -90,7 +86,7 @@ namespace Physic mMeshOrientation = Ogre::Quaternion::IDENTITY; } */ - + /* // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) { @@ -99,6 +95,7 @@ namespace Physic } else mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents))); + */ mShape->setLocalScaling(btVector3(scale,scale,scale)); @@ -160,20 +157,20 @@ namespace Physic mPosition = position; - btTransform tr = mBody->getWorldTransform(); - Ogre::Quaternion meshrot = mMeshOrientation; - Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); - Ogre::Vector3 newPosition = transrot + position; + //btTransform tr = mBody->getWorldTransform(); + //Ogre::Quaternion meshrot = mMeshOrientation; + //Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); + //Ogre::Vector3 newPosition = transrot + position; - tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); - mBody->setWorldTransform(tr); + //tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); + //mBody->setWorldTransform(tr); } void PhysicActor::setRotation (const Ogre::Quaternion& rotation) { - btTransform tr = mBody->getWorldTransform(); - tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); - mBody->setWorldTransform(tr); + //btTransform tr = mBody->getWorldTransform(); + //tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); + //mBody->setWorldTransform(tr); } void PhysicActor::setScale(float scale) From 351fd842fd497236d77d8096e6efb2a3867a76c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 16:58:05 +0200 Subject: [PATCH 0202/1812] Port loading screen --- apps/openmw/mwgui/loadingscreen.cpp | 114 +++++++++++-------------- apps/openmw/mwgui/loadingscreen.hpp | 30 ++++--- apps/openmw/mwgui/windowmanagerimp.cpp | 29 ++----- 3 files changed, 77 insertions(+), 96 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7e88f2d973..01bd590a79 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -1,14 +1,6 @@ #include "loadingscreen.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include @@ -18,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -26,15 +19,17 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwrender/vismask.hpp" + #include "backgroundimage.hpp" namespace MWGui { - LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) - : mSceneMgr(sceneMgr) - , mWindow(rw) - , WindowBase("openmw_loading_screen.layout") + LoadingScreen::LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer) + : WindowBase("openmw_loading_screen.layout") + , mVFS(vfs) + , mViewer(viewer) , mLastRenderTime(0) , mLastWallpaperChangeTime(0) , mProgress(0) @@ -52,6 +47,32 @@ namespace MWGui MyGUI::Align::Stretch, "Menu"); setVisible(false); + + findSplashScreens(); + } + + void LoadingScreen::findSplashScreens() + { + const std::map& index = mVFS->getIndex(); + std::string pattern = "Splash/"; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) + { + const std::string& name = found->first; + if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) + { + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".tga") == 0) + mSplashScreens.push_back(found->first); + } + else + break; + ++found; + } + if (mSplashScreens.empty()) + std::cerr << "No splash screens found!" << std::endl; } void LoadingScreen::setLabel(const std::string &label) @@ -80,17 +101,13 @@ namespace MWGui if (mMainWidget->getVisible()) return; - // Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync. - // Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it. - mVSyncWasEnabled = mWindow->isVSyncEnabled(); - mWindow->setVSyncEnabled(false); - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - if (!showWallpaper) { + // TODO + /* mBackgroundImage->setImageTexture(""); int width = mWindow->getWidth(); int height = mWindow->getHeight(); @@ -111,6 +128,7 @@ namespace MWGui mWindow->copyContentsToMemory(texture->getBuffer()->lock(Ogre::Image::Box(0,0,width,height), Ogre::HardwareBuffer::HBL_DISCARD)); texture->getBuffer()->unlock(); mBackgroundImage->setBackgroundImage(texture->getName(), false, false); + */ } setVisible(true); @@ -125,9 +143,6 @@ namespace MWGui void LoadingScreen::loadingOff() { - // Re-enable vsync now. - mWindow->setVSyncEnabled(mVSyncWasEnabled); - setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); @@ -136,29 +151,15 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - if (mResources.empty()) + if (!mSplashScreens.empty()) { - Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); - for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) - { - Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash/*.tga"); - mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); - } - } - - if (!mResources.empty()) - { - std::string const & randomSplash = mResources.at(Misc::Rng::rollDice(mResources.size())); - - Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + std::string const & randomSplash = mSplashScreens.at(Misc::Rng::rollDice(mSplashScreens.size())); // TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3 // we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3 bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); mBackgroundImage->setBackgroundImage(randomSplash, true, stretch); } - else - std::cerr << "No loading screens found!" << std::endl; } void LoadingScreen::setProgressRange (size_t range) @@ -190,7 +191,7 @@ namespace MWGui void LoadingScreen::indicateProgress() { - float time = (mTimer.getMilliseconds() % 2001) / 1000.f; + float time = (static_cast(mTimer.time_m()) % 2001) / 1000.f; if (time > 1) time = (time-2)*-1; @@ -203,43 +204,32 @@ namespace MWGui { const float loadingScreenFps = 20.f; - if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) { - mLastRenderTime = mTimer.getMilliseconds (); + mLastRenderTime = mTimer.time_m(); bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); - if (showWallpaper && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1) + if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) { - mLastWallpaperChangeTime = mTimer.getMilliseconds (); + mLastWallpaperChangeTime = mTimer.time_m(); changeWallpaper(); } // Turn off rendering except the GUI - mSceneMgr->clearSpecialCaseRenderQueues(); - // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. - for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) - { - if (i > 0 && i < 96) - mSceneMgr->addSpecialCaseRenderQueue(i); - } - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - MWBase::Environment::get().getInputManager()->update(0, true, true); + //MWBase::Environment::get().getInputManager()->update(0, true, true); - // First, swap buffers from last draw, then, queue an update of the - // window contents, but don't swap buffers (which would have - // caused a sync / flush and would be expensive). - // We're doing this so we can do some actual loading while the GPU is busy with the render. - // This means the render is lagging a frame behind, but this is hardly noticable. - mWindow->swapBuffers(); - - mWindow->update(false); + mViewer->frame(); // resume 3d rendering - mSceneMgr->clearSpecialCaseRenderQueues(); - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); } } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 0d3ffbbec7..46bbb00ccb 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,16 +1,20 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H -#include -#include +#include +#include #include "windowbase.hpp" #include -namespace Ogre +namespace osgViewer { - class SceneManager; + class Viewer; +} +namespace VFS +{ + class Manager; } namespace MWGui @@ -20,6 +24,9 @@ namespace MWGui class LoadingScreen : public WindowBase, public Loading::Listener { public: + LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer); + virtual ~LoadingScreen(); + virtual void setLabel (const std::string& label); /// Indicate that some progress has been made, without specifying how much @@ -34,21 +41,18 @@ namespace MWGui virtual void setVisible(bool visible); - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); - virtual ~LoadingScreen(); - void setLoadingProgress (const std::string& stage, int depth, int current, int total); void loadingDone(); - void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } - private: - Ogre::SceneManager* mSceneMgr; - Ogre::RenderWindow* mWindow; + void findSplashScreens(); + + const VFS::Manager* mVFS; + osg::ref_ptr mViewer; unsigned long mLastWallpaperChangeTime; unsigned long mLastRenderTime; - Ogre::Timer mTimer; + osg::Timer mTimer; size_t mProgress; @@ -58,7 +62,7 @@ namespace MWGui MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; - Ogre::StringVector mResources; + std::vector mSplashScreens; bool mVSyncWasEnabled; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9d9ba329b0..575d7045a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -213,9 +213,9 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); -#if 0 - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); -#endif + + mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); + //set up the hardware cursor manager //mCursorManager = new SFO::SDLCursorManager(); @@ -1173,8 +1173,8 @@ namespace MWGui if (!mGuiModes.empty()) mGuiModes.pop_back(); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1190,8 +1190,8 @@ namespace MWGui ++it; } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + //bool gameMode = !isGuiMode(); + //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1541,22 +1541,9 @@ namespace MWGui mHud->setEnemy(enemy); } - class DummyListener : public Loading::Listener - { - public: - virtual void setLabel (const std::string& label){} - virtual void loadingOn(){} - virtual void loadingOff(){} - virtual void indicateProgress (){} - virtual void setProgressRange (size_t range){} - virtual void setProgress (size_t value){} - virtual void increaseProgress (size_t increase = 1){} - }; - Loading::Listener* WindowManager::getLoadingScreen() { - static DummyListener listener; - return &listener; + return mLoadingScreen; } void WindowManager::startRecharge(MWWorld::Ptr soulgem) From 31ead3a9f463ac24155711fbbddc921dc0c06bb3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:04:21 +0200 Subject: [PATCH 0203/1812] Increase loading screen FPS Now that it's rendered in a background thread, we can have a smooth loading bar at virtually no performance cost. --- apps/openmw/mwgui/loadingscreen.cpp | 10 +++++----- apps/openmw/mwgui/loadingscreen.hpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 01bd590a79..3b13ed5a9f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,8 +30,8 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) - , mLastRenderTime(0) - , mLastWallpaperChangeTime(0) + , mLastRenderTime(0.0) + , mLastWallpaperChangeTime(0.0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -202,12 +202,10 @@ namespace MWGui void LoadingScreen::draw() { - const float loadingScreenFps = 20.f; + const float loadingScreenFps = 120.f; if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) { - mLastRenderTime = mTimer.time_m(); - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -230,6 +228,8 @@ namespace MWGui // resume 3d rendering mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); mViewer->getCamera()->setCullMask(oldCullMask); + + mLastRenderTime = mTimer.time_m(); } } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 46bbb00ccb..4c9d45f668 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -50,8 +50,8 @@ namespace MWGui const VFS::Manager* mVFS; osg::ref_ptr mViewer; - unsigned long mLastWallpaperChangeTime; - unsigned long mLastRenderTime; + double mLastWallpaperChangeTime; + double mLastRenderTime; osg::Timer mTimer; size_t mProgress; From 140e67036c3beef4fb85e27f20e24c4f0471d195 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:10:50 +0200 Subject: [PATCH 0204/1812] Flip non-dds textures vertically Fixes the up-side down loading screens. --- components/resource/texturemanager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 939f81d9b8..ee75296a79 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -92,6 +92,15 @@ namespace Resource } osg::Image* image = result.getImage(); + + // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), + // but OpenGL uses bottom left as the image origin. + // For some reason this doesn't concern DDS textures, which are already flipped when loaded. + if (ext != "dds") + { + image->flipVertical(); + } + osg::ref_ptr texture(new osg::Texture2D); texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); From 283b252142085fdb0c9f780e810fc7c650e4bc9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:24:35 +0200 Subject: [PATCH 0205/1812] Stub InputManager --- apps/openmw/CMakeLists.txt | 10 ++-- apps/openmw/engine.cpp | 13 ++--- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 18 +++---- apps/openmw/mwinput/inputmanagerimp.cpp | 53 +++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +- apps/openmw/mwrender/activatoranimation.cpp | 51 -------------------- apps/openmw/mwrender/activatoranimation.hpp | 24 ---------- apps/openmw/mwscript/interpretercontext.cpp | 2 - 9 files changed, 51 insertions(+), 125 deletions(-) delete mode 100644 apps/openmw/mwrender/activatoranimation.cpp delete mode 100644 apps/openmw/mwrender/activatoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 81cecc2c87..4a93daec75 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,15 +23,15 @@ add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface debugging rendermode bulletdebugdraw -# camera activatoranimation +# camera # localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction -# terrainstorage renderconst weaponanimation +# terrainstorage weaponanimation ) -#add_openmw_dir (mwinput -# inputmanagerimp -# ) +add_openmw_dir (mwinput + inputmanagerimp + ) add_openmw_dir (mwgui layout textinput widgets race class birth review windowmanagerimp console dialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 15fee0cb1f..5be9317eba 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -28,7 +28,7 @@ #include -//#include "mwinput/inputmanagerimp.hpp" +#include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" @@ -79,7 +79,7 @@ void OMW::Engine::frame(float frametime) mEnvironment.setFrameDuration (frametime); // update input - //MWBase::Environment::get().getInputManager()->update(frametime, false); + MWBase::Environment::get().getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. @@ -335,8 +335,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - //MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); - //mEnvironment.setInputManager (input); + // FIXME: shouldn't depend on Engine + MWInput::InputManager* input = new MWInput::InputManager (*this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); osg::ref_ptr guiRoot = new osg::Group; @@ -354,7 +355,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) { std::string logo = mFallbackMap["Movies_Company_Logo"]; if (!logo.empty()) - window->playVideo(logo, 1); + window->playVideo(logo, true); } // Create the world @@ -362,7 +363,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); - //input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); window->renderWorldMap(); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3b13ed5a9f..a7791d838f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -221,7 +221,7 @@ namespace MWGui mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - //MWBase::Environment::get().getInputManager()->update(0, true, true); + MWBase::Environment::get().getInputManager()->update(0, true, true); mViewer->frame(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 575d7045a6..ebca96b199 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -334,7 +334,7 @@ namespace MWGui // Set up visibility updateVisible(); - //MWBase::Environment::get().getInputManager()->changeInputMode(false); + MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::renderWorldMap() @@ -834,7 +834,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - //mRendering->getWindow()->update(); + mViewer->frame(); } } } @@ -1132,8 +1132,8 @@ namespace MWGui mGuiModes.push_back(mode); - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1173,8 +1173,8 @@ namespace MWGui if (!mGuiModes.empty()) mGuiModes.pop_back(); - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1190,8 +1190,8 @@ namespace MWGui ++it; } - //bool gameMode = !isGuiMode(); - //MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } @@ -1705,7 +1705,7 @@ namespace MWGui while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - //MWBase::Environment::get().getInputManager()->update(0, true, false); + MWBase::Environment::get().getInputManager()->update(0, true, false); mViewer->frame(); } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 88d891a028..442a5e8b2e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -14,8 +14,6 @@ #include -#include - #include "../engine.hpp" #include "../mwbase/world.hpp" @@ -98,16 +96,16 @@ namespace namespace MWInput { - InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, + InputManager::InputManager( OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) - : mOgre(ogre) + : mInputManager(NULL) , mPlayer(NULL) , mEngine(engine) , mMouseLookEnabled(false) - , mMouseX(ogre.getWindow()->getWidth ()/2.f) - , mMouseY(ogre.getWindow()->getHeight ()/2.f) + , mMouseX(0)//ogre.getWindow()->getWidth ()/2.f) + , mMouseY(0)//ogre.getWindow()->getHeight ()/2.f) , mMouseWheel(0) , mDragDrop(false) , mGuiCursorEnabled(true) @@ -131,17 +129,18 @@ namespace MWInput , mFakeDeviceID(1) { + /* Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow(), grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); + */ std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - adjustMouseRegion (window->getWidth(), window->getHeight()); + //adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); loadControllerDefaults(); @@ -199,7 +198,7 @@ namespace MWInput delete mInputBinder; - delete mInputManager; + //delete mInputManager; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -366,24 +365,24 @@ namespace MWInput void InputManager::updateCursorMode() { - bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) - && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; + //bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) + // && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; - bool was_relative = mInputManager->getMouseRelative(); + bool was_relative = 0;//mInputManager->getMouseRelative(); bool is_relative = !MWBase::Environment::get().getWindowManager()->isGuiMode(); // don't keep the pointer away from the window edge in gui mode // stop using raw mouse motions and switch to system cursor movements - mInputManager->setMouseRelative(is_relative); + //mInputManager->setMouseRelative(is_relative); //we let the mouse escape in the main menu - mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); + //mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); //we switched to non-relative mode, move our cursor to where the in-game //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -391,9 +390,9 @@ namespace MWInput { mControlsDisabled = disableControls; - mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); + //mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - mInputManager->capture(disableEvents); + //mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); @@ -427,7 +426,7 @@ namespace MWInput mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -668,6 +667,7 @@ namespace MWInput // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing // This assumes that SDL_TextInput events always come *after* the key event // (which is somewhat reasonable, and hopefully true for all SDL platforms) + /* OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) == arg.keysym.scancode @@ -685,6 +685,7 @@ namespace MWInput if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; + */ } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -697,11 +698,13 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + /* mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); + */ } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) @@ -827,9 +830,9 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); //esc, to leave initial movie screen - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + //bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + //setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -853,9 +856,9 @@ namespace MWInput else mInputBinder->buttonReleased(deviceID, arg); - //to escape initial movie - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + ///to escape initial movie + //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + //setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) @@ -885,7 +888,7 @@ namespace MWInput void InputManager::windowResized(int x, int y) { - mOgre.windowResized(x,y); + //mOgre.windowResized(x,y); } void InputManager::windowClosed() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5588010236..26a1fcb21e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -66,7 +66,7 @@ namespace MWInput public ICS::DetectingBindingListener { public: - InputManager(OEngine::Render::OgreRenderer &_ogre, + InputManager( OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -143,7 +143,6 @@ namespace MWInput private: bool mJoystickLastUsed; - OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp deleted file mode 100644 index 1ef68f619c..0000000000 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "activatoranimation.hpp" - -#include -#include - -#include - -#include "renderconst.hpp" - -namespace MWRender -{ - -ActivatorAnimation::~ActivatorAnimation() -{ -} - -ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr, const std::string& model) - : Animation(ptr, ptr.getRefData().getBaseNode()) -{ - if(!model.empty()) - { - setObjectRoot(model, false); - setRenderProperties(mObjectRoot, RV_Misc, RQG_Main, RQG_Alpha); - - addAnimSource(model); - } - else - { - // No model given. Create an object root anyway, so that lights can be added to it if needed. - mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); - } -} - -void ActivatorAnimation::addLight(const ESM::Light *light) -{ - addExtraLight(mInsert->getCreator(), mObjectRoot, light); -} - -void ActivatorAnimation::removeParticles() -{ - for (unsigned int i=0; imParticles.size(); ++i) - { - // Don't destroyParticleSystem, the ParticleSystemController is still holding a pointer to it. - // Don't setVisible, this could conflict with a VisController. - // The following will remove all spawned particles, then set the speed factor to zero so that no new ones will be spawned. - mObjectRoot->mParticles[i]->setSpeedFactor(0.f); - mObjectRoot->mParticles[i]->clear(); - } -} - -} diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp deleted file mode 100644 index a234defe7a..0000000000 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef GAME_RENDER_ACTIVATORANIMATION_H -#define GAME_RENDER_ACTIVATORANIMATION_H - -#include "animation.hpp" - -namespace MWWorld -{ - class Ptr; -} - -namespace MWRender -{ - class ActivatorAnimation : public Animation - { - public: - ActivatorAnimation(const MWWorld::Ptr& ptr, const std::string &model); - virtual ~ActivatorAnimation(); - - void addLight(const ESM::Light *light); - void removeParticles(); - }; -} - -#endif diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index fab65b1523..a8c04aa4bc 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,7 +270,6 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - /* MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) @@ -287,7 +286,6 @@ namespace MWScript return input->getActionKeyBindingName (*it); } } - */ return "None"; } From 157d8bfedd4b1ed4cbb0361891fea1f25da9286a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:26:12 +0200 Subject: [PATCH 0206/1812] Remove unused mygui files --- CMakeLists.txt | 1 - files/CMakeLists.txt | 1 + files/mygui/CMakeLists.txt | 2 -- files/mygui/black.png | Bin 103 -> 0 bytes files/mygui/white.png | Bin 118 -> 0 bytes 5 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 files/mygui/black.png delete mode 100644 files/mygui/white.png diff --git a/CMakeLists.txt b/CMakeLists.txt index d2a245366f..d1008d3136 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,7 +310,6 @@ endif() add_subdirectory(files/) -add_subdirectory(files/mygui) # Specify build paths diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index e69de29bb2..00cae86d26 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(mygui) diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 13d1a9e1a4..6023977437 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,8 +4,6 @@ set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) set(MYGUI_FILES - black.png - white.png core.skin core.xml core_layouteditor.xml diff --git a/files/mygui/black.png b/files/mygui/black.png deleted file mode 100644 index 69db2911a7fc479a8d7c1da556c72a2c18109ed4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^#^NA%Cx&(BWL^R}oCO|{#S9GG t!XV7ZFl&wkP>{#d#W95AdUAq<9FTW{fw3kzvlhr=@O1TaS?83{1OS+*6e9ot diff --git a/files/mygui/white.png b/files/mygui/white.png deleted file mode 100644 index 9bed5f523c6ec8ffcbcd4dd203ea8ee2bc56fed0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^&H|6fVg?3oVGw3ym^DWND9B#o z>FdgVk5ib>QlDk|1u>wIsHcl#2*>s0KmY&RGn*Ya(!k8)$H@?Og_$?;bw(Xf0fVQj KpUXO@geCy^jvCGY From 37e3118d21a5f44706812fe3e3a4e70c623b6f25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 17:52:50 +0200 Subject: [PATCH 0207/1812] FontLoader cleanup fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ebca96b199..c32f2bfe8a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -419,6 +419,8 @@ namespace MWGui cleanupGarbage(); + mFontLoader.reset(); + delete mGuiPlatform; } From 9de575ad42cd0170b514a10bf2bed4277f04f6e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 18:16:54 +0200 Subject: [PATCH 0208/1812] Use IncrementalCompileOperation to incrementally upload OpenGL objects during the loading screen For now, not much difference, but should result in a sizable speed up once MyGUI no longer needs the DYNAMIC flag (i.e. the loading screen truly renders in the background). --- apps/openmw/engine.cpp | 5 +---- apps/openmw/mwgui/loadingscreen.cpp | 9 ++++++++- apps/openmw/mwgui/loadingscreen.hpp | 1 + apps/openmw/mwrender/objects.cpp | 16 ++++++++++++++++ apps/openmw/mwrender/objects.hpp | 9 +++++++++ apps/openmw/mwrender/renderingmanager.cpp | 6 ++++++ 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5be9317eba..d7ad97e6e3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -391,8 +391,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); - //mOgre->getRoot()->addFrameListener (this); - // scripts if (mCompileAll) { @@ -466,13 +464,12 @@ void OMW::Engine::go() mViewer->setCameraManipulator(new osgGA::TrackballManipulator); mViewer->addEventHandler(new osgViewer::StatsHandler); - mViewer->realize(); osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); - //dt = std::min(dt, 0.2f); + //dt = std::min(dt, 0.2); frame(dt); mViewer->frame(/*simulationTime*/); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index a7791d838f..45bd5bf9d4 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,8 +30,9 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) - , mLastRenderTime(0.0) , mLastWallpaperChangeTime(0.0) + , mLastRenderTime(0.0) + , mLoadingOnTime(0.0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -97,6 +98,7 @@ namespace MWGui void LoadingScreen::loadingOn() { + mLoadingOnTime = mTimer.time_m(); // Early-out if already on if (mMainWidget->getVisible()) return; @@ -143,6 +145,7 @@ namespace MWGui void LoadingScreen::loadingOff() { + //std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl; setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); @@ -215,6 +218,8 @@ namespace MWGui changeWallpaper(); } + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(80); + // Turn off rendering except the GUI int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldCullMask = mViewer->getCamera()->getCullMask(); @@ -223,6 +228,8 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; + mViewer->frame(); // resume 3d rendering diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 4c9d45f668..7c49df0277 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -53,6 +53,7 @@ namespace MWGui double mLastWallpaperChangeTime; double mLastRenderTime; osg::Timer mTimer; + double mLoadingOnTime; size_t mProgress; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6f4f4ef79d..69311c1117 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -78,6 +80,11 @@ Objects::~Objects() mCellSceneNodes.clear(); } +void Objects::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) +{ + mIncrementalCompileOperation = ico; +} + void Objects::insertBegin(const MWWorld::Ptr& ptr) { osg::ref_ptr cellnode; @@ -108,6 +115,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + if (!allowLight) { RemoveParticlesVisitor visitor; @@ -130,6 +140,9 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -139,6 +152,9 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + if (mIncrementalCompileOperation && anim->getObjectRoot()) + mIncrementalCompileOperation->add(anim->getObjectRoot()); + mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 2acf10d105..fd6ceab544 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -12,6 +12,11 @@ namespace osg class Group; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { class ResourceSystem; @@ -41,10 +46,14 @@ class Objects{ Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mIncrementalCompileOperation; + public: Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); ~Objects(); + void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5cb7795453..4f13df8e76 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -95,6 +97,10 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mViewer.setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); + + mObjects->setIncrementalCompileOperation(mViewer.getIncrementalCompileOperation()); + mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); mViewer.setLightingMode(osgViewer::View::NO_LIGHT); From 5a759f8b0d9577a41d8c8ae81e23eba508e73bcd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 18:35:29 +0200 Subject: [PATCH 0209/1812] GUI cleanup fix --- apps/opencs/editor.cpp | 5 ----- apps/openmw/mwgui/mainmenu.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 11 +++++++---- components/fontloader/fontloader.cpp | 11 ++++++++++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 83fcb3e37b..56076dbe05 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -311,11 +311,6 @@ int CS::Editor::run() return QApplication::exec(); } - // for font used in overlays - //Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), - // "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - - void CS::Editor::documentAdded (CSMDoc::Document *document) { mViewManager.addView (document); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 48f9ee42ce..ef86666f43 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,7 +1,5 @@ #include "mainmenu.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c32f2bfe8a..abc19b3f9e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -30,6 +30,8 @@ #include +#include + #include #include @@ -180,8 +182,8 @@ namespace MWGui mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); mGuiPlatform->initialise(resourcePath, logpath); - MyGUI::Gui* gui = new MyGUI::Gui; - gui->initialise(""); + mGui = new MyGUI::Gui; + mGui->initialise(""); createTextures(); @@ -307,8 +309,8 @@ namespace MWGui std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds - //if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(hitFaderTexture)) - // hitFaderTexture = "textures\\player_hit_01.dds"; + if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) + hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); mScreenFader = new ScreenFader("black.png"); @@ -421,6 +423,7 @@ namespace MWGui mFontLoader.reset(); + delete mGui; delete mGuiPlatform; } diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 080c64c4c9..7635c43daf 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -438,7 +438,16 @@ namespace Gui font->deserialization(root, MyGUI::Version(3,2,0)); - MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); + for (std::vector::iterator it = mFonts.begin(); it != mFonts.end();) + { + if ((*it)->getResourceName() == font->getResourceName()) + { + MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); + it = mFonts.erase(it); + } + else + ++it; + } MyGUI::ResourceManager::getInstance().addResource(font); } From a37a83eaea0c5c543d71d49ba36ab41d8952e29e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 May 2015 22:15:53 +0200 Subject: [PATCH 0210/1812] Use interleaved vertex data in MyGUI render manager, avoiding redundant copies --- .../myguiplatform/myguirendermanager.cpp | 93 ++++++------------- 1 file changed, 29 insertions(+), 64 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 87464f22da..e63756ecd9 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -97,9 +97,7 @@ namespace osgMyGUI class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; - osg::ref_ptr mPositionArray; - osg::ref_ptr mColorArray; - osg::ref_ptr mTexCoordArray; + osg::ref_ptr mVertexArray; std::vector mLockedData; size_t mNeedVertexCount; @@ -150,71 +148,32 @@ MyGUI::Vertex *OSGVertexBuffer::lock() { MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); - // NOTE: Unfortunately, MyGUI wants the VBO data to be interleaved as a - // MyGUI::Vertex structure. However, OSG uses non-interleaved elements, so - // we have to give back a "temporary" structure array then copy it to the - // actual VBO arrays on unlock. This is extra unfortunate since the VBO may - // be backed by VRAM, meaning we could have up to 3 copies of the data - // (which we'll need to keep for VBOs that are continually updated). - mLockedData.resize(mNeedVertexCount, MyGUI::Vertex()); - return mLockedData.data(); + mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); + return (MyGUI::Vertex*)&(*mVertexArray)[0]; } void OSGVertexBuffer::unlock() { - osg::Vec3 *vec = &mPositionArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - vec->set(elem.x, elem.y, elem.z); - ++vec; - } - osg::Vec4ub *clr = &mColorArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - union { - MyGUI::uint32 ui; - unsigned char ub4[4]; - } val = { elem.colour }; - clr->set(val.ub4[0], val.ub4[1], val.ub4[2], val.ub4[3]); - ++clr; - } - osg::Vec2 *crds = &mTexCoordArray->front(); - for (std::vector::const_iterator it = mLockedData.begin(); it != mLockedData.end(); ++it) - { - const MyGUI::Vertex& elem = *it; - crds->set(elem.u, elem.v); - ++crds; - } - + mVertexArray->dirty(); mBuffer->dirty(); } void OSGVertexBuffer::destroy() { mBuffer = nullptr; - mPositionArray = nullptr; - mColorArray = nullptr; - mTexCoordArray = nullptr; - std::vector().swap(mLockedData); + mVertexArray = nullptr; } void OSGVertexBuffer::create() { MYGUI_PLATFORM_ASSERT(!mBuffer.valid(), "Vertex buffer already exist"); - mPositionArray = new osg::Vec3Array(mNeedVertexCount); - mColorArray = new osg::Vec4ubArray(mNeedVertexCount); - mTexCoordArray = new osg::Vec2Array(mNeedVertexCount); - mColorArray->setNormalize(true); + mVertexArray = new osg::UByteArray(mNeedVertexCount*sizeof(MyGUI::Vertex)); mBuffer = new osg::VertexBufferObject; mBuffer->setDataVariance(osg::Object::DYNAMIC); - mBuffer->setUsage(GL_STREAM_DRAW); - mBuffer->setArray(0, mPositionArray.get()); - mBuffer->setArray(1, mColorArray.get()); - mBuffer->setArray(2, mTexCoordArray.get()); + mBuffer->setUsage(GL_DYNAMIC_DRAW); + mBuffer->setArray(0, mVertexArray.get()); } // --------------------------------------------------------------------------- @@ -270,19 +229,10 @@ void RenderManager::initialise() camera->setRenderOrder(osg::Camera::POST_RENDER); camera->setClearMask(GL_NONE); osg::StateSet *state = new osg::StateSet; - state->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::OFF); - state->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::OFF); - state->setTextureMode(0, GL_TEXTURE_GEN_R, osg::StateAttribute::OFF); state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - state->setMode(GL_LIGHT0, osg::StateAttribute::OFF); state->setMode(GL_BLEND, osg::StateAttribute::ON); - state->setMode(GL_FOG, osg::StateAttribute::OFF); - state->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE)); - state->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT, osg::PolygonMode::FILL)); state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - state->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); @@ -317,6 +267,10 @@ void RenderManager::begin() { osg::State *state = mRenderInfo->getState(); state->disableAllVertexArrays(); + state->setClientActiveTextureUnit(0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) @@ -332,9 +286,21 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text state->applyTextureAttribute(0, tex); } - state->setVertexPointer(vbo->getArray(0)); - state->setColorPointer(vbo->getArray(1)); - state->setTexCoordPointer(0, vbo->getArray(2)); + osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + if (bufferobject) + { + state->bindVertexBufferObject(bufferobject); + + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); + } glDrawArrays(GL_TRIANGLES, 0, count); } @@ -342,10 +308,9 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text void RenderManager::end() { osg::State *state = mRenderInfo->getState(); - state->disableTexCoordPointer(0); - state->disableColorPointer(); - state->disableVertexPointer(); state->unbindVertexBufferObject(); + state->dirtyAllVertexArrays(); + state->disableAllVertexArrays(); } void RenderManager::drawFrame(osg::RenderInfo &renderInfo) From f0789352c630661ff3d53d024a8bc89701c67e50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 00:34:30 +0200 Subject: [PATCH 0211/1812] Silence error message --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c3932d388a..cbce86650e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -117,10 +117,10 @@ namespace MWGui mPreview.reset(NULL); mAvatarImage->setImageTexture(""); +#if 0 MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); if (tex) MyGUI::RenderManager::getInstance().destroyTexture(tex); -#if 0 mPreview.reset(new MWRender::InventoryPreview(mPtr)); mPreview->setup(); #endif From c1edc30ad718a631259ff69844232bd47fe0f294 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 03:29:12 +0200 Subject: [PATCH 0212/1812] Dead code removal --- CMakeLists.txt | 171 +--------------------- apps/launcher/CMakeLists.txt | 1 - apps/opencs/CMakeLists.txt | 2 - apps/openmw/CMakeLists.txt | 3 - apps/openmw/engine.cpp | 10 -- apps/openmw/mwgui/settingswindow.cpp | 20 --- apps/openmw/mwgui/settingswindow.hpp | 2 - files/mygui/openmw_settings_window.layout | 6 - files/settings-default.cfg | 2 - 9 files changed, 1 insertion(+), 216 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1008d3136..92023da2c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,12 +54,9 @@ endif (ANDROID) configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) -option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) -set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)") - option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools @@ -197,46 +194,9 @@ find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) -set(OGRE_PLUGIN_INCLUDE_DIRS "") -set(OGRE_STATIC_PLUGINS "") - -macro(add_static_ogre_plugin PLUGIN) - if(OGRE_${PLUGIN}_FOUND) - # strip RenderSystem_ or Plugin_ prefix from plugin name - string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) - string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME}) - - list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS}) - list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES}) - endif(OGRE_${PLUGIN}_FOUND) -endmacro(add_static_ogre_plugin) - -if(OGRE_STATIC) - # set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS - add_static_ogre_plugin(Plugin_OctreeSceneManager) - add_static_ogre_plugin(Plugin_ParticleFX) - find_package(Cg) - if(Cg_FOUND) - add_static_ogre_plugin(Plugin_CgProgramManager) - list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES}) - endif(Cg_FOUND) - -if (ANDROID) - add_static_ogre_plugin(RenderSystem_GLES2) -else () - add_static_ogre_plugin(RenderSystem_GL) -endif () - - if(WIN32) - add_static_ogre_plugin(RenderSystem_Direct3D9) - endif(WIN32) -endif(OGRE_STATIC) - include_directories("." ${LIBS_DIR} SYSTEM - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} - ${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR} + ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} @@ -252,31 +212,6 @@ if(MYGUI_STATIC) endif (MYGUI_STATIC) if (APPLE) - # List used Ogre plugins - SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} - ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) - - # Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's - # not reliable and equals TRUE even if there's no Ogre Cg plugin - if (Cg_FOUND) - set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS} - ${OGRE_Plugin_CgProgramManager_LIBRARY_REL}) - endif () - - 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 () - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist "${APP_BUNDLE_DIR}/Contents/Info.plist") @@ -287,28 +222,6 @@ endif (APPLE) # Set up DEBUG define set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) -# 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() - -if (APPLE AND OPENMW_OSX_DEPLOYMENT) - # make it empty so plugin loading code can check this and try to find plugins inside app bundle - add_definitions(-DOGRE_PLUGIN_DIR="") -else() - if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "") - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - else() - set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR}) - endif() - - add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") -endif() - - add_subdirectory(files/) # Specify build paths @@ -651,12 +564,6 @@ if (WIN32) 4987 # nonstandard extension used (triggered by setjmp.h) 4996 # Function was declared deprecated - # cause by ogre extensivly - 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' - 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' - 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' - 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) - # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -722,90 +629,14 @@ if (APPLE) set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") - set(ABSOLUTE_PLUGINS "") - - foreach (PLUGIN ${USED_OGRE_PLUGINS}) - get_filename_component(PLUGIN_ABS ${PLUGIN} REALPATH) - set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) - endforeach () - install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) include(BundleUtilities) " COMPONENT Runtime) - # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) - # and returns list of install paths for all installed plugins - function (install_plugins_for_bundle bundle_path plugins_var) - set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks") - - set(PLUGINS "") - set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") - - foreach (PLUGIN ${ABSOLUTE_PLUGINS}) - get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) - get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) - - set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}") - set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") - - install(CODE " - copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") - " COMPONENT Runtime) - endforeach () - - set(${plugins_var} ${PLUGINS} PARENT_SCOPE) - endfunction (install_plugins_for_bundle) - - install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) - install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) - #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail set(DIRS "") - # Overriding item resolving during installation, it needed if - # some library already has been "fixed up", i.e. its id name contains @executable_path, - # but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK. - # Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case. - # - # Current limitations: - # 1. Handles only frameworks, not simple libs - INSTALL(CODE " - cmake_policy(SET CMP0009 OLD) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH}) - - set(OPENMW_RESOLVED_ITEMS \"\") - - function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) - if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}}) - if (item MATCHES \"Frameworks\") # if it is a framework - # get last segment of path - get_filename_component(fname \"\${item}\" NAME_WE) - find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} \${CMAKE_SYSTEM_FRAMEWORK_PATH}) - if (ri) - string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item}) - set(ri \"\${ri}\${item_part}\") - set(\${resolved_item_var} \${ri} PARENT_SCOPE) - set(\${resolved_var} 1 PARENT_SCOPE) - endif() - else() - # code path for standard (non-framework) libs (ogre & qt pugins) - get_filename_component(fname \"\${item}\" NAME_WE) - string(REGEX REPLACE \"^lib\" \"\" fname \${fname}) - find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /usr/lib /usr/local/lib) - if (ri) - set(\${resolved_item_var} \${ri} PARENT_SCOPE) - set(\${resolved_var} 1 PARENT_SCOPE) - endif () - endif() - endif() - endfunction(gp_resolve_item_override) - - fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") - " COMPONENT Runtime) include(CPack) endif (APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 0de79f8f6b..76b6e46bd9 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -90,7 +90,6 @@ add_executable(openmw-launcher target_link_libraries(openmw-launcher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${SDL2_LIBRARY_ONLY} ${QT_LIBRARIES} components diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8347af6eeb..d7aafcf30e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -201,8 +201,6 @@ endif(APPLE) target_link_libraries(openmw-cs ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} - ${OGRE_Overlay_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${BULLET_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4a93daec75..d680f49d6d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -129,7 +129,6 @@ include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} - ${OGRE_STATIC_PLUGINS} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} @@ -144,13 +143,11 @@ target_link_libraries(openmw if (ANDROID) target_link_libraries(openmw - ${OGRE_STATIC_PLUGINS} EGL android log dl MyGUIEngineStatic - Plugin_StrangeButtonStatic cpufeatures BulletCollision BulletDynamics diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ac51eace8a..d91d32a287 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -277,16 +277,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setStateManager ( new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); - std::string renderSystem = settings.getString("render system", "Video"); - if (renderSystem == "") - { -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - renderSystem = "Direct3D9 Rendering Subsystem"; -#else - renderSystem = "OpenGL Rendering Subsystem"; -#endif - } - //OEngine::Render::WindowSettings windowSettings; //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); //windowSettings.window_border = settings.getBool("window border", "Video"); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 23cf2c62e1..c23e2bb948 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -75,11 +75,6 @@ namespace return MyGUI::utility::toString(xaspect) + " : " + MyGUI::utility::toString(yaspect); } - std::string hlslGlsl () - { - return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; - } - const char* checkButtonType = "CheckButton"; const char* sliderType = "Slider"; @@ -180,7 +175,6 @@ namespace MWGui getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); - getWidget(mShaderModeButton, "ShaderModeButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); @@ -207,7 +201,6 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); - mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); @@ -248,8 +241,6 @@ namespace MWGui mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); - if (!Settings::Manager::getBool("shaders", "Objects")) { mRefractionButton->setEnabled(false); @@ -398,17 +389,6 @@ namespace MWGui } } - void SettingsWindow::onShaderModeToggled(MyGUI::Widget* _sender) - { - std::string val = hlslGlsl(); - - _sender->castType()->setCaption(val); - - Settings::Manager::setString("shader mode", "General", val); - - apply(); - } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 1b970b8de5..7cebb10d13 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -37,7 +37,6 @@ namespace MWGui MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; - MyGUI::Button* mShaderModeButton; MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; @@ -59,7 +58,6 @@ namespace MWGui void onResolutionAccept(); void onResolutionCancel(); - void onShaderModeToggled(MyGUI::Widget* _sender); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2efd5841ed..cc9c3d1dc7 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -271,12 +271,6 @@ - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 862f9495ac..7f2185b62d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -59,8 +59,6 @@ anisotropy = 4 # Number of texture mipmaps to generate num mipmaps = 8 -shader mode = - screenshot format = png [Shadows] From e191f0e044f5f9b5ea9de737322f015737553a6a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 17:41:30 +0200 Subject: [PATCH 0213/1812] Rename MWRender::Debugging to MWRender::Pathgrid --- apps/openmw/CMakeLists.txt | 2 +- .../mwrender/{debugging.cpp => pathgrid.cpp} | 24 +++++++++---------- .../mwrender/{debugging.hpp => pathgrid.hpp} | 17 +++---------- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++---- apps/openmw/mwrender/renderingmanager.hpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 10 ++++++-- 6 files changed, 30 insertions(+), 37 deletions(-) rename apps/openmw/mwrender/{debugging.cpp => pathgrid.cpp} (92%) rename apps/openmw/mwrender/{debugging.hpp => pathgrid.hpp} (81%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d680f49d6d..e1de2a5563 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface debugging rendermode + creatureanimation effectmanager util renderinginterface pathgrid rendermode bulletdebugdraw # camera # localmap occlusionquery water shadows diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/pathgrid.cpp similarity index 92% rename from apps/openmw/mwrender/debugging.cpp rename to apps/openmw/mwrender/pathgrid.cpp index 9cbf94d46e..5e559eeed1 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -1,4 +1,4 @@ -#include "debugging.hpp" +#include "pathgrid.hpp" #include @@ -7,8 +7,6 @@ #include #include -#include - #include #include @@ -27,7 +25,7 @@ namespace MWRender static const int POINT_MESH_BASE = 35; -osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Pathgrid::createPathgridLines(const ESM::Pathgrid *pathgrid) { osg::ref_ptr geom = new osg::Geometry; @@ -62,7 +60,7 @@ osg::ref_ptr Debugging::createPathgridLines(const ESM::Pathgrid * return geom; } -osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) +osg::ref_ptr Pathgrid::createPathgridPoints(const ESM::Pathgrid *pathgrid) { osg::ref_ptr geom = new osg::Geometry; @@ -126,7 +124,7 @@ osg::ref_ptr Debugging::createPathgridPoints(const ESM::Pathgrid return geom; } -Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/) +Pathgrid::Pathgrid(osg::ref_ptr root) : mRootNode(root) , mPathgridEnabled(false) , mInteriorPathgridNode(NULL) @@ -134,7 +132,7 @@ Debugging::Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEn { } -Debugging::~Debugging() +Pathgrid::~Pathgrid() { if (mPathgridEnabled) { @@ -143,7 +141,7 @@ Debugging::~Debugging() } -bool Debugging::toggleRenderMode (int mode){ +bool Pathgrid::toggleRenderMode (int mode){ switch (mode) { case Render_Pathgrid: @@ -156,21 +154,21 @@ bool Debugging::toggleRenderMode (int mode){ return false; } -void Debugging::addCell(const MWWorld::CellStore *store) +void Pathgrid::addCell(const MWWorld::CellStore *store) { mActiveCells.push_back(store); if (mPathgridEnabled) enableCellPathgrid(store); } -void Debugging::removeCell(const MWWorld::CellStore *store) +void Pathgrid::removeCell(const MWWorld::CellStore *store) { mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end()); if (mPathgridEnabled) disableCellPathgrid(store); } -void Debugging::togglePathgrid() +void Pathgrid::togglePathgrid() { mPathgridEnabled = !mPathgridEnabled; if (mPathgridEnabled) @@ -201,7 +199,7 @@ void Debugging::togglePathgrid() } } -void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) +void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) { MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = @@ -242,7 +240,7 @@ void Debugging::enableCellPathgrid(const MWWorld::CellStore *store) } } -void Debugging::disableCellPathgrid(const MWWorld::CellStore *store) +void Pathgrid::disableCellPathgrid(const MWWorld::CellStore *store) { if (store->getCell()->isExterior()) { diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/pathgrid.hpp similarity index 81% rename from apps/openmw/mwrender/debugging.hpp rename to apps/openmw/mwrender/pathgrid.hpp index 4ec5bc41d3..39a6d71ed9 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/pathgrid.hpp @@ -14,14 +14,6 @@ namespace ESM struct Pathgrid; } -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - namespace osg { class Group; @@ -36,11 +28,8 @@ namespace MWWorld namespace MWRender { - class Debugging + class Pathgrid { - //OEngine::Physic::PhysicEngine* mEngine; - - // Path grid stuff bool mPathgridEnabled; void togglePathgrid(); @@ -63,8 +52,8 @@ namespace MWRender osg::ref_ptr createPathgridLines(const ESM::Pathgrid *pathgrid); osg::ref_ptr createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(osg::ref_ptr root /*, OEngine::Physic::PhysicEngine *engine*/); - ~Debugging(); + Pathgrid(osg::ref_ptr root); + ~Pathgrid(); bool toggleRenderMode (int mode); void addCell(const MWWorld::CellStore* store); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4f13df8e76..4d06d901a4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -29,7 +29,7 @@ #include "effectmanager.hpp" #include "npcanimation.hpp" #include "vismask.hpp" -#include "debugging.hpp" +#include "pathgrid.hpp" namespace MWRender { @@ -93,7 +93,7 @@ namespace MWRender mRootNode->addChild(lightRoot); - mDebugging.reset(new Debugging(mRootNode)); + mPathgrid.reset(new Pathgrid(mRootNode)); mObjects.reset(new Objects(mResourceSystem, lightRoot)); @@ -195,12 +195,12 @@ namespace MWRender void RenderingManager::addCell(const MWWorld::CellStore *store) { - mDebugging->addCell(store); + mPathgrid->addCell(store); } void RenderingManager::removeCell(const MWWorld::CellStore *store) { - mDebugging->removeCell(store); + mPathgrid->removeCell(store); mObjects->removeCell(store); } @@ -212,7 +212,7 @@ namespace MWRender bool RenderingManager::toggleRenderMode(RenderMode mode) { if (mode == Render_CollisionDebug || mode == Render_Pathgrid) - return mDebugging->toggleRenderMode(mode); + return mPathgrid->toggleRenderMode(mode); else if (mode == Render_Wireframe) { return false; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 334025096d..0dc0fe571e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -38,7 +38,7 @@ namespace MWRender class EffectManager; class SkyManager; class NpcAnimation; - class Debugging; + class Pathgrid; class RenderingManager : public MWRender::RenderingInterface { @@ -99,7 +99,7 @@ namespace MWRender osg::ref_ptr mSunLight; - std::auto_ptr mDebugging; + std::auto_ptr mPathgrid; std::auto_ptr mObjects; std::auto_ptr mSky; std::auto_ptr mEffectManager; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 464f2d605a..cb58f04969 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_WORLDIMP_H #define GAME_MWWORLD_WORLDIMP_H -#include "../mwrender/debugging.hpp" - #include #include @@ -23,6 +21,14 @@ #include +namespace OEngine +{ +namespace Physic +{ + class PhysicEngine; +} +} + namespace osg { class Group; From ee60df1e2717727998fb6a8de7452122df88ffd2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 May 2015 22:17:28 +0200 Subject: [PATCH 0214/1812] Split MyGUI rendering into Update, Cull and Draw stages --- .../myguiplatform/myguirendermanager.cpp | 222 ++++++++++++------ .../myguiplatform/myguirendermanager.hpp | 10 +- 2 files changed, 164 insertions(+), 68 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e63756ecd9..e1ebf781c7 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -46,23 +46,6 @@ namespace { -// Proxy to forward a Drawable's draw call to RenderManager::drawFrame -class Renderable : public osg::Drawable { - osgMyGUI::RenderManager *mParent; - - virtual void drawImplementation(osg::RenderInfo &renderInfo) const - { mParent->drawFrame(renderInfo); } - -public: - Renderable(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } - Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) - : osg::Drawable(copy, copyop) - , mParent(copy.mParent) - { } - - META_Object(osgMyGUI, Renderable) -}; - // Proxy to forward an OSG resize event to RenderManager::setViewSize class ResizeHandler : public osgGA::GUIEventHandler { osgMyGUI::RenderManager *mParent; @@ -94,6 +77,147 @@ public: namespace osgMyGUI { +class Drawable : public osg::Drawable { + osgMyGUI::RenderManager *mParent; + + // Stage 0: update widget animations and controllers. Run during the Update traversal. + class FrameUpdate : public osg::Drawable::UpdateCallback + { + public: + FrameUpdate() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual void update(osg::NodeVisitor*, osg::Drawable*) + { + if (mRenderManager) + mRenderManager->update(); + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 1: collect draw calls. Run during the Cull traversal. + class CollectDrawCalls : public osg::Drawable::CullCallback + { + public: + CollectDrawCalls() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const + { + if (!mRenderManager) + return false; + + mRenderManager->collectDrawCalls(); + return false; + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal of the next frame. + virtual void drawImplementation(osg::RenderInfo &renderInfo) const + { + osg::State *state = renderInfo.getState(); + state->disableAllVertexArrays(); + state->setClientActiveTextureUnit(0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + for (std::vector::const_iterator it = mBatchVector.begin(); it != mBatchVector.end(); ++it) + { + const Batch& batch = *it; + osg::VertexBufferObject *vbo = batch.mVertexBuffer; + osg::Texture2D* texture = batch.mTexture; + if(texture) + state->applyTextureAttribute(0, texture); + + osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + if (bufferobject) + { + state->bindVertexBufferObject(bufferobject); + + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); + } + + glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + } + + state->unbindVertexBufferObject(); + state->dirtyAllVertexArrays(); + state->disableAllVertexArrays(); + } + +public: + Drawable(osgMyGUI::RenderManager *parent = nullptr) : mParent(parent) + { + setSupportsDisplayList(false); + + osg::ref_ptr collectDrawCalls = new CollectDrawCalls; + collectDrawCalls->setRenderManager(mParent); + setCullCallback(collectDrawCalls); + + osg::ref_ptr frameUpdate = new Drawable::FrameUpdate; + frameUpdate->setRenderManager(mParent); + setUpdateCallback(frameUpdate); + } + Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Drawable(copy, copyop) + , mParent(copy.mParent) + { + } + + // Defines the necessary information for a draw call + struct Batch + { + // May be empty + osg::ref_ptr mTexture; + + osg::ref_ptr mVertexBuffer; + size_t mVertexCount; + }; + + void addBatch(const Batch& batch) + { + mBatchVector.push_back(batch); + } + + void clear() + { + mBatchVector.clear(); + } + + META_Object(osgMyGUI, Drawable) + +private: + std::vector mBatchVector; +}; + class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; @@ -213,13 +337,11 @@ void RenderManager::initialise() mUpdate = false; - osg::ref_ptr drawable = new Renderable(this); - drawable->setSupportsDisplayList(false); - drawable->setUseVertexBufferObjects(true); - drawable->setDataVariance(osg::Object::DYNAMIC); + mDrawable = new Drawable(this); + mDrawable->setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr geode = new osg::Geode; - geode->addDrawable(drawable.get()); + geode->addDrawable(mDrawable.get()); osg::ref_ptr camera = new osg::Camera(); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); @@ -265,61 +387,25 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) void RenderManager::begin() { - osg::State *state = mRenderInfo->getState(); - state->disableAllVertexArrays(); - state->setClientActiveTextureUnit(0); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) { - osg::State *state = mRenderInfo->getState(); - osg::VertexBufferObject *vbo = static_cast(buffer)->getBuffer(); - MYGUI_PLATFORM_ASSERT(vbo, "Vertex buffer is not created"); + Drawable::Batch batch; + batch.mVertexCount = count; + batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + if (texture) + batch.mTexture = static_cast(texture)->getTexture(); - if(texture) - { - osg::Texture2D *tex = static_cast(texture)->getTexture(); - MYGUI_PLATFORM_ASSERT(tex, "Texture is not created"); - state->applyTextureAttribute(0, tex); - } - - osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) - { - state->bindVertexBufferObject(bufferobject); - - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); - } - else - { - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); - } - - glDrawArrays(GL_TRIANGLES, 0, count); + mDrawable->addBatch(batch); } void RenderManager::end() { - osg::State *state = mRenderInfo->getState(); - state->unbindVertexBufferObject(); - state->dirtyAllVertexArrays(); - state->disableAllVertexArrays(); } -void RenderManager::drawFrame(osg::RenderInfo &renderInfo) +void RenderManager::update() { - MyGUI::Gui *gui = MyGUI::Gui::getInstancePtr(); - if(gui == nullptr) return; - - mRenderInfo = &renderInfo; - static MyGUI::Timer timer; static unsigned long last_time = timer.getMilliseconds(); unsigned long now_time = timer.getMilliseconds(); @@ -328,10 +414,12 @@ void RenderManager::drawFrame(osg::RenderInfo &renderInfo) onFrameEvent((float)((double)(time) / (double)1000)); last_time = now_time; +} - begin(); +void RenderManager::collectDrawCalls() +{ + mDrawable->clear(); onRenderToTarget(this, mUpdate); - end(); mUpdate = false; } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 05d0f9a5a0..342050d902 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -25,10 +25,13 @@ namespace osg namespace osgMyGUI { +class Drawable; + class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget { osg::ref_ptr mViewer; osg::ref_ptr mSceneRoot; + osg::ref_ptr mDrawable; Resource::TextureManager* mTextureManager; MyGUI::IntSize mViewSize; @@ -80,20 +83,25 @@ public: /** @see RenderManager::getTexture */ virtual MyGUI::ITexture* getTexture(const std::string &name); + // Called by the update traversal + void update(); + // Called by the cull traversal /** @see IRenderTarget::begin */ virtual void begin(); /** @see IRenderTarget::end */ virtual void end(); /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } bool checkTexture(MyGUI::ITexture* _texture); /*internal:*/ - void drawFrame(osg::RenderInfo &renderInfo); + + void collectDrawCalls(); void setViewSize(int width, int height); }; From 100d6e5fffd7700d12c79566847d74ef6f7cf2cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 May 2015 02:38:59 +0200 Subject: [PATCH 0215/1812] Render MyGUI in background thread, i.e. refactor to get rid of DYNAMIC DataVariance --- apps/openmw/mwrender/renderingmanager.cpp | 2 - .../myguiplatform/myguirendermanager.cpp | 37 +++++++++++++------ .../myguiplatform/myguirendermanager.hpp | 3 -- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4d06d901a4..853ba38349 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -144,8 +144,6 @@ namespace MWRender zNear = 5.f; zFar = mViewDistance; mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - - mViewer.getCamera()->setCullMask(mViewer.getCamera()->getCullMask() & (~Mask_GUI)); } RenderingManager::~RenderingManager() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e1ebf781c7..d1bf739047 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -7,10 +7,7 @@ #include #include -#include #include -#include -#include #include #include @@ -141,7 +138,9 @@ class Drawable : public osg::Drawable { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - for (std::vector::const_iterator it = mBatchVector.begin(); it != mBatchVector.end(); ++it) + mReadFrom = (mReadFrom+1)%2; + const std::vector& vec = mBatchVector[mReadFrom]; + for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { const Batch& batch = *it; osg::VertexBufferObject *vbo = batch.mVertexBuffer; @@ -174,7 +173,10 @@ class Drawable : public osg::Drawable { } public: - Drawable(osgMyGUI::RenderManager *parent = nullptr) : mParent(parent) + Drawable(osgMyGUI::RenderManager *parent = nullptr) + : mParent(parent) + , mWriteTo(0) + , mReadFrom(0) { setSupportsDisplayList(false); @@ -182,7 +184,7 @@ public: collectDrawCalls->setRenderManager(mParent); setCullCallback(collectDrawCalls); - osg::ref_ptr frameUpdate = new Drawable::FrameUpdate; + osg::ref_ptr frameUpdate = new FrameUpdate; frameUpdate->setRenderManager(mParent); setUpdateCallback(frameUpdate); } @@ -199,30 +201,35 @@ public: osg::ref_ptr mTexture; osg::ref_ptr mVertexBuffer; + // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array + osg::ref_ptr mArray; + size_t mVertexCount; }; void addBatch(const Batch& batch) { - mBatchVector.push_back(batch); + mBatchVector[mWriteTo].push_back(batch); } void clear() { - mBatchVector.clear(); + mWriteTo = (mWriteTo+1)%2; + mBatchVector[mWriteTo].clear(); } META_Object(osgMyGUI, Drawable) private: - std::vector mBatchVector; + std::vector mBatchVector[2]; + int mWriteTo; + mutable int mReadFrom; }; class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; osg::ref_ptr mVertexArray; - std::vector mLockedData; size_t mNeedVertexCount; @@ -241,6 +248,7 @@ public: void create(); osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } + osg::UByteArray *getArray() const { return mVertexArray.get(); } }; OSGVertexBuffer::OSGVertexBuffer() @@ -270,6 +278,12 @@ size_t OSGVertexBuffer::getVertexCount() MyGUI::Vertex *OSGVertexBuffer::lock() { + // Force recreating the buffer, to make sure we are not modifying a buffer currently + // queued for rendering in the last frame's draw thread. + // a more efficient solution might be double buffering + destroy(); + create(); + MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); @@ -297,6 +311,7 @@ void OSGVertexBuffer::create() mBuffer = new osg::VertexBufferObject; mBuffer->setDataVariance(osg::Object::DYNAMIC); mBuffer->setUsage(GL_DYNAMIC_DRAW); + // NB mBuffer does not own the array mBuffer->setArray(0, mVertexArray.get()); } @@ -338,7 +353,6 @@ void RenderManager::initialise() mUpdate = false; mDrawable = new Drawable(this); - mDrawable->setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(mDrawable.get()); @@ -394,6 +408,7 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text Drawable::Batch batch; batch.mVertexCount = count; batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + batch.mArray = static_cast(buffer)->getArray(); if (texture) batch.mTexture = static_cast(texture)->getTexture(); diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 342050d902..afb07eaa61 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -46,9 +46,6 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mGuiRoot; - // Only valid during drawFrame()! - osg::RenderInfo *mRenderInfo; - void destroyAllResources(); public: From f760aebc926432d364292c9e916e72c4f4f46623 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 May 2015 17:55:38 +0200 Subject: [PATCH 0216/1812] Disable MyGUI VBOs due to crashes (will look into proper fix) --- components/myguiplatform/myguirendermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index d1bf739047..e9a6f8c4e2 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -148,7 +148,7 @@ class Drawable : public osg::Drawable { if(texture) state->applyTextureAttribute(0, texture); - osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; if (bufferobject) { state->bindVertexBufferObject(bufferobject); From 604580d75dbb225005b91841dc09c66785c0692c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 21:17:15 +0200 Subject: [PATCH 0217/1812] Move toMatrix to Nif::Node --- components/nif/niftypes.hpp | 13 ++++ components/nifbullet/bulletnifloader.cpp | 93 +++++++----------------- components/nifbullet/bulletnifloader.hpp | 4 +- components/nifosg/nifloader.cpp | 22 +----- 4 files changed, 44 insertions(+), 88 deletions(-) diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 7fefb92a2b..d951801452 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #include +#include // Common types used in NIF files @@ -49,6 +50,18 @@ struct Transformation Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales float scale; + osg::Matrixf toMatrix() const + { + osg::Matrixf transform; + transform.setTrans(pos); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + transform(j,i) = rotation.mValues[i][j] * scale; // NB column/row major difference + + return transform; + } + static const Transformation& getIdentity() { static const Transformation identity = { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 1d07bea26e..0ddb6291ce 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -41,55 +41,16 @@ http://www.gnu.org/licenses/ . // For warning messages #include -// Extract a list of keyframe-controlled nodes from a .kf file -// FIXME: this is a similar copy of OgreNifLoader::loadKf -void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) +namespace { - if(kfFile->numRoots() < 1) - { - kfFile->warn("Found no root nodes in "+kfFile->getFilename()+"."); - return; - } - const Nif::Record *r = kfFile->getRoot(0); - assert(r != NULL); +osg::Matrixf getWorldTransform(const Nif::Node *node) +{ + if(node->parent != NULL) + return node->trafo.toMatrix() * getWorldTransform(node->parent); + return node->trafo.toMatrix(); +} - if(r->recType != Nif::RC_NiSequenceStreamHelper) - { - kfFile->warn("First root was not a NiSequenceStreamHelper, but a "+ - r->recName+"."); - return; - } - const Nif::NiSequenceStreamHelper *seq = static_cast(r); - - Nif::ExtraPtr extra = seq->extra; - if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) - { - kfFile->warn("First extra data was not a NiTextKeyExtraData, but a "+ - (extra.empty() ? std::string("nil") : extra->recName)+"."); - return; - } - - extra = extra->extra; - Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) - { - if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) - { - kfFile->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); - continue; - } - - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - - const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - - if(key->data.empty()) - continue; - controlled.insert(strdata->string); - } } namespace NifBullet @@ -133,7 +94,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) { Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - extractControlledNodes(kf, mControlledNodes); + //extractControlledNodes(kf, mControlledNodes); } Nif::Record *r = nif.getRoot(0); @@ -259,7 +220,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } else if(node->recType == Nif::RC_NiTriShape) { - handleNiTriShape(static_cast(node), flags, Ogre::Matrix4()/*node->getWorldTransform()*/, isAnimated); + handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated); } } @@ -276,7 +237,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) { assert(shape != NULL); @@ -312,18 +273,18 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int childMesh->preallocateVertices(data->vertices.size()); childMesh->preallocateIndices(data->triangles.size()); - //const std::vector &vertices = data->vertices; - //const std::vector &triangles = data->triangles; + const std::vector &vertices = data->vertices; + const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - //Ogre::Vector3 b1 = vertices[triangles[i+0]]; - //Ogre::Vector3 b2 = vertices[triangles[i+1]]; - //Ogre::Vector3 b3 = vertices[triangles[i+2]]; - //childMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + osg::Vec3f b1 = vertices[triangles[i+0]]; + osg::Vec3f b2 = vertices[triangles[i+1]]; + osg::Vec3f b3 = vertices[triangles[i+2]]; + childMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); } - //TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -332,15 +293,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int parent = parent->parent; scale *= parent->trafo.scale; } - //Ogre::Quaternion q = transform.extractQuaternion(); - //Ogre::Vector3 v = transform.getTrans(); - //childShape->setLocalScaling(btVector3(scale, scale, scale)); + osg::Quat q = transform.getRotate(); + osg::Vec3f v = transform.getTrans(); + childShape->setLocalScaling(btVector3(scale, scale, scale)); - //btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); + btTransform trans(btQuaternion(q.x(), q.y(), q.z(), q.w()), btVector3(v.x(), v.y(), v.z())); - //mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); - //mCompoundShape->addChildShape(trans, childShape); + mCompoundShape->addChildShape(trans, childShape); } else { @@ -349,17 +310,15 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - //const std::vector &vertices = data->vertices; - //const std::vector &triangles = data->triangles; + const std::vector &vertices = data->vertices; + const std::vector &triangles = data->triangles; for(size_t i = 0;i < data->triangles.size();i+=3) { - /* osg::Vec3f b1 = transform*vertices[triangles[i+0]]; osg::Vec3f b2 = transform*vertices[triangles[i+1]]; osg::Vec3f b3 = transform*vertices[triangles[i+2]]; - mStaticMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); - */ + mStaticMesh->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/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 3ffb6ac8f4..733e9264be 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -32,6 +32,8 @@ #include #include +#include + // For warning messages #include @@ -117,7 +119,7 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool isAnimated); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); std::string mResourceName; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 936f266dd1..adf7e94b4c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -49,24 +49,6 @@ namespace { - osg::Matrixf toMatrix(const Nif::Transformation& nifTrafo) - { - osg::Matrixf transform; - transform.setTrans(nifTrafo.pos); - - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - transform(j,i) = nifTrafo.rotation.mValues[i][j] * nifTrafo.scale; // NB column/row major difference - - return transform; - } - - osg::Matrixf getWorldTransform(const Nif::Node* node) - { - if(node->parent != NULL) - return toMatrix(node->trafo) * getWorldTransform(node->parent); - return toMatrix(node->trafo); - } void getAllNiNodes(const Nif::Node* node, std::vector& outIndices) { @@ -467,7 +449,7 @@ namespace NifOsg static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); + osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); if (nifNode->recType == Nif::RC_NiBillboardNode) { @@ -1072,7 +1054,7 @@ namespace NifOsg std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); influence.mWeights.insert(indexWeight); } - influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); + influence.mInvBindMatrix = data->bones[i].trafo.toMatrix(); influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); From 77f733362c1c393f55e1c3faafed3051114ea17b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 21:57:02 +0200 Subject: [PATCH 0218/1812] Add stats graphs for Script, Mechanics and Physics timings --- apps/openmw/engine.cpp | 40 +++++++++++++++++++++-- apps/openmw/engine.hpp | 2 ++ apps/openmw/mwrender/objects.cpp | 5 --- apps/openmw/mwrender/objects.hpp | 3 -- apps/openmw/mwrender/renderingmanager.cpp | 1 - 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d91d32a287..368af216ff 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -76,6 +76,7 @@ void OMW::Engine::frame(float frametime) { try { + mStartTick = mViewer->getStartTick(); mEnvironment.setFrameDuration (frametime); // update input @@ -99,6 +100,7 @@ void OMW::Engine::frame(float frametime) // update game state MWBase::Environment::get().getStateManager()->update (frametime); + osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) { @@ -120,15 +122,17 @@ void OMW::Engine::frame(float frametime) MWBase::Environment::get().getWorld()->advanceTime( frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); } - + osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors + osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getMechanicsManager()->update(frametime, guiActive); } + osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) @@ -139,11 +143,13 @@ void OMW::Engine::frame(float frametime) } // update world + osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getWorld()->update(frametime, guiActive); } + osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI MWBase::Environment::get().getWindowManager()->onFrame(frametime); @@ -155,6 +161,21 @@ void OMW::Engine::frame(float frametime) #endif MWBase::Environment::get().getWindowManager()->update(); } + + int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); + osg::Stats* stats = mViewer->getViewerStats(); + stats->setAttribute(frameNumber, "script_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeScriptTick)); + stats->setAttribute(frameNumber, "script_time_taken", osg::Timer::instance()->delta_s(beforeScriptTick, afterScriptTick)); + stats->setAttribute(frameNumber, "script_time_end", osg::Timer::instance()->delta_s(mStartTick, afterScriptTick)); + + stats->setAttribute(frameNumber, "mechanics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeMechanicsTick)); + stats->setAttribute(frameNumber, "mechanics_time_taken", osg::Timer::instance()->delta_s(beforeMechanicsTick, afterMechanicsTick)); + stats->setAttribute(frameNumber, "mechanics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterMechanicsTick)); + + stats->setAttribute(frameNumber, "physics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforePhysicsTick)); + stats->setAttribute(frameNumber, "physics_time_taken", osg::Timer::instance()->delta_s(beforePhysicsTick, afterPhysicsTick)); + stats->setAttribute(frameNumber, "physics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterPhysicsTick)); + } catch (const std::exception& e) { @@ -194,6 +215,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError())); } } + + mStartTick = osg::Timer::instance()->tick(); } OMW::Engine::~Engine() @@ -430,7 +453,7 @@ void OMW::Engine::go() { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); } - else if (0)// !mSkipMenu) + else if (!mSkipMenu) { // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); @@ -452,7 +475,18 @@ void OMW::Engine::go() // Start the main rendering loop mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - mViewer->addEventHandler(new osgViewer::StatsHandler); + + osg::ref_ptr statshandler = new osgViewer::StatsHandler; + + statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); + statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); + statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); + + mViewer->addEventHandler(statshandler); + osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index b47a7bb766..e94b5e3ff5 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -96,6 +96,8 @@ namespace OMW bool mScriptBlacklistUse; bool mNewGame; + osg::Timer_t mStartTick; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 69311c1117..17fbbe5494 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -198,11 +198,6 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::update(float dt) -{ - -} - void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { /* diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index fd6ceab544..e920869b90 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -63,9 +63,6 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - void update (float dt); - ///< per-frame update - //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 853ba38349..c9bf220099 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -248,7 +248,6 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { - mObjects->update(dt); mEffectManager->update(dt); mSky->update(dt); } From 00f4f7871730e43a9ee0cc0c12fff8fe3e5b1071 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 23:08:52 +0200 Subject: [PATCH 0219/1812] Give a name to video streams for logging purposes --- apps/openmw/mwgui/videowidget.cpp | 2 +- extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 4 ++-- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 3 ++- extern/osg-ffmpeg-videoplayer/videostate.cpp | 8 +++----- extern/osg-ffmpeg-videoplayer/videostate.hpp | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 13fabfeed5..2c9b1c97ef 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -30,7 +30,7 @@ void VideoWidget::playVideo(const std::string &video) { mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(mVFS->get(video)); + mPlayer->playVideo(mVFS->get(video), video); osg::ref_ptr texture = mPlayer->getVideoTexture(); if (!texture) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 1336e45a36..9bd4a2df3f 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -25,7 +25,7 @@ void VideoPlayer::setAudioFactory(MovieAudioFactory *factory) mAudioFactory.reset(factory); } -void VideoPlayer::playVideo(boost::shared_ptr inputstream) +void VideoPlayer::playVideo(boost::shared_ptr inputstream, const std::string& name) { if(mState) close(); @@ -33,7 +33,7 @@ void VideoPlayer::playVideo(boost::shared_ptr inputstream) try { mState = new VideoState; mState->setAudioFactory(mAudioFactory.get()); - mState->init(inputstream); + mState->init(inputstream, name); // wait until we have the first picture while (mState->video_st && !mState->mTexture.get()) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index 261246f39b..b886257e75 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -41,7 +41,8 @@ namespace Video /// Play the given video. If a video is already playing, the old video is closed first. /// @note The video will be unpaused by default. Use the pause() and play() methods to control pausing. - void playVideo (boost::shared_ptr inputstream); + /// @param name A name for the video stream - only used for logging purposes. + void playVideo (boost::shared_ptr inputstream, const std::string& name); /// Get the current playback time position in the video, in seconds double getCurrentTime(); diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 72fc82f860..4dd6188587 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -602,7 +602,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) return 0; } -void VideoState::init(boost::shared_ptr inputstream) +void VideoState::init(boost::shared_ptr inputstream, const std::string &name) { int video_index = -1; int audio_index = -1; @@ -622,8 +622,6 @@ void VideoState::init(boost::shared_ptr inputstream) if(this->format_ctx) this->format_ctx->pb = ioCtx; - std::string videoName; - // Open video file /// /// format_ctx->pb->buffer must be freed by hand, @@ -631,7 +629,7 @@ void VideoState::init(boost::shared_ptr inputstream) /// /// https://trac.ffmpeg.org/ticket/1357 /// - if(!this->format_ctx || avformat_open_input(&this->format_ctx, videoName.c_str(), NULL, NULL)) + if(!this->format_ctx || avformat_open_input(&this->format_ctx, name.c_str(), NULL, NULL)) { if (this->format_ctx != NULL) { @@ -655,7 +653,7 @@ void VideoState::init(boost::shared_ptr inputstream) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, videoName.c_str(), 0); + av_dump_format(this->format_ctx, 0, name.c_str(), 0); for(i = 0;i < this->format_ctx->nb_streams;i++) { diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 40925e0141..4a4f2fc6b3 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -84,7 +84,7 @@ struct VideoState { void setAudioFactory(MovieAudioFactory* factory); - void init(boost::shared_ptr inputstream); + void init(boost::shared_ptr inputstream, const std::string& name); void deinit(); void setPaused(bool isPaused); From 483dc9de45d63184879cfe6a781bfb4a2d115e11 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 May 2015 23:17:30 +0200 Subject: [PATCH 0220/1812] Stop viewer threading before changing MyGUI textures --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++++ components/myguiplatform/myguitexture.hpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6421df8241..40180d700e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1092,7 +1092,11 @@ namespace MWGui else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); else if (it->first == "GUI" && it->second == "menu transparency") + { + mViewer->stopThreading(); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); + mViewer->startThreading(); + } } } diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index de385e94d6..109858bc8b 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -42,6 +42,8 @@ namespace osgMyGUI virtual void destroy(); + /// @warning If you intend to change a texture during the frame update, you must either declare the texture with DataVariance::DYNAMIC + /// or temporarily stop the viewer threading, to prevent race conditions with the draw thread. virtual void* lock(MyGUI::TextureUsage access); virtual void unlock(); virtual bool isLocked(); From cf0fc4300408b2b5c5d91574c3ada05a2dffe402 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 15:10:17 +0200 Subject: [PATCH 0221/1812] GUI shutdown fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 40180d700e..9c7a9de20a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -423,7 +423,10 @@ namespace MWGui mFontLoader.reset(); + mGui->shutdown(); delete mGui; + + mGuiPlatform->shutdown(); delete mGuiPlatform; } From 5db0639983f759103ae157b9e4351fef49ed3802 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 16:20:40 +0200 Subject: [PATCH 0222/1812] IncrementalCompileOperation tweak --- apps/openmw/mwgui/loadingscreen.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 45bd5bf9d4..d56c77bdd1 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -103,6 +103,13 @@ namespace MWGui if (mMainWidget->getVisible()) return; + if (mViewer->getIncrementalCompileOperation()) + { + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(200); + // keep this in sync with loadingScreenFps + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(1.0/120.0); + } + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -218,8 +225,6 @@ namespace MWGui changeWallpaper(); } - mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(80); - // Turn off rendering except the GUI int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldCullMask = mViewer->getCamera()->getCullMask(); @@ -228,8 +233,6 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); - //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; - mViewer->frame(); // resume 3d rendering From c8eb77c55740331bf6249e7bf05cbe1f9e006248 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 16:22:42 +0200 Subject: [PATCH 0223/1812] Move StatsHandler construction to allow profiling of loading screen --- apps/openmw/engine.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 368af216ff..59c3667a4d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -435,6 +435,17 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; + osg::ref_ptr statshandler = new osgViewer::StatsHandler; + + statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); + statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); + statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), + "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); + + mViewer->addEventHandler(statshandler); + Settings::Manager settings; std::string settingspath; @@ -476,18 +487,6 @@ void OMW::Engine::go() // Start the main rendering loop mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - osg::ref_ptr statshandler = new osgViewer::StatsHandler; - - statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); - statshandler->addUserStatsLine("Mechanics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "mechanics_time_taken", 1000.0, true, false, "mechanics_time_begin", "mechanics_time_end", 10000); - statshandler->addUserStatsLine("Physics", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), - "physics_time_taken", 1000.0, true, false, "physics_time_begin", "physics_time_end", 10000); - - mViewer->addEventHandler(statshandler); - - osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { From 7a2a7633d5d0f2c8b42a66d1bb5ccfb461d3e7b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 17:11:40 +0200 Subject: [PATCH 0224/1812] Fix videoplayer destruction issue that valgrind complained about --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 4dd6188587..dea08de92c 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -721,7 +721,12 @@ void VideoState::deinit() avformat_close_input(&this->format_ctx); } - mTexture = NULL; + if (mTexture) + { + // reset Image separately, it's pointing to *this and there might still be outside references to mTexture + mTexture->setImage(NULL); + mTexture = NULL; + } } double VideoState::get_external_clock() From af7cbb2e3ba0828322f9c654987d30165f6b9004 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 May 2015 17:52:35 +0200 Subject: [PATCH 0225/1812] Leak fix --- components/resource/resourcesystem.cpp | 5 +++++ components/resource/resourcesystem.hpp | 4 ++++ components/resource/scenemanager.cpp | 5 +++++ components/resource/scenemanager.hpp | 4 ++++ components/resource/texturemanager.cpp | 5 +++++ components/resource/texturemanager.hpp | 4 ++++ 6 files changed, 27 insertions(+) diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index acde8f5d2d..bd6824079e 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -13,6 +13,11 @@ namespace Resource mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); } + ResourceSystem::~ResourceSystem() + { + // this has to be defined in the .cpp file as we can't delete incomplete types + } + SceneManager* ResourceSystem::getSceneManager() { return mSceneManager.get(); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 3bb4547854..7c00a11eef 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -21,6 +21,7 @@ namespace Resource { public: ResourceSystem(const VFS::Manager* vfs); + ~ResourceSystem(); SceneManager* getSceneManager(); TextureManager* getTextureManager(); @@ -32,6 +33,9 @@ namespace Resource std::auto_ptr mTextureManager; const VFS::Manager* mVFS; + + ResourceSystem(const ResourceSystem&); + void operator = (const ResourceSystem&); }; } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 393f322d7d..8a0d526fa0 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -70,6 +70,11 @@ namespace Resource { } + SceneManager::~SceneManager() + { + // this has to be defined in the .cpp file as we can't delete incomplete types + } + osg::ref_ptr SceneManager::getTemplate(const std::string &name) { std::string normalized = name; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 6a52dfb21a..9f3c5387e7 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -32,6 +32,7 @@ namespace Resource { public: SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); + ~SceneManager(); /// Get a read-only copy of this scene "template" osg::ref_ptr getTemplate(const std::string& name); @@ -69,6 +70,9 @@ namespace Resource typedef std::map > KeyframeIndex; KeyframeIndex mKeyframeIndex; + + SceneManager(const SceneManager&); + void operator = (const SceneManager&); }; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index ee75296a79..b9b9fad5fa 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -42,6 +42,11 @@ namespace Resource } + TextureManager::~TextureManager() + { + + } + void TextureManager::setUnRefImageDataAfterApply(bool unref) { mUnRefImageDataAfterApply = unref; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index d44d47d243..851a55166e 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -21,6 +21,7 @@ namespace Resource { public: TextureManager(const VFS::Manager* vfs); + ~TextureManager(); // TODO: texture filtering settings @@ -48,6 +49,9 @@ namespace Resource osg::ref_ptr mWarningTexture; bool mUnRefImageDataAfterApply; + + TextureManager(const TextureManager&); + void operator = (const TextureManager&); }; } From 52a4456cf70669d7bf127730ee6432695d913354 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:02:38 +0200 Subject: [PATCH 0226/1812] LoadingScreen update --- apps/openmw/mwgui/loadingscreen.cpp | 24 ++++++++++++++---------- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index d56c77bdd1..cdb2d6bdff 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,6 +30,7 @@ namespace MWGui : WindowBase("openmw_loading_screen.layout") , mVFS(vfs) , mViewer(viewer) + , mTargetFrameRate(120.0) , mLastWallpaperChangeTime(0.0) , mLastRenderTime(0.0) , mLoadingOnTime(0.0) @@ -52,6 +53,10 @@ namespace MWGui findSplashScreens(); } + LoadingScreen::~LoadingScreen() + { + } + void LoadingScreen::findSplashScreens() { const std::map& index = mVFS->getIndex(); @@ -86,10 +91,6 @@ namespace MWGui mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mLoadingBox->getTop()); } - LoadingScreen::~LoadingScreen() - { - } - void LoadingScreen::setVisible(bool visible) { WindowBase::setVisible(visible); @@ -105,9 +106,8 @@ namespace MWGui if (mViewer->getIncrementalCompileOperation()) { - mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(200); - // keep this in sync with loadingScreenFps - mViewer->getIncrementalCompileOperation()->setTargetFrameRate(1.0/120.0); + mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100); + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate); } bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() @@ -212,9 +212,7 @@ namespace MWGui void LoadingScreen::draw() { - const float loadingScreenFps = 120.f; - - if (mTimer.time_m() > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) { bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); @@ -233,7 +231,12 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); + //osg::Timer timer; mViewer->frame(); + //std::cout << "frame took " << timer.time_m() << std::endl; + + //if (mViewer->getIncrementalCompileOperation()) + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; // resume 3d rendering mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); @@ -242,4 +245,5 @@ namespace MWGui mLastRenderTime = mTimer.time_m(); } } + } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 7c49df0277..a1e6e4d213 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -50,6 +50,8 @@ namespace MWGui const VFS::Manager* mVFS; osg::ref_ptr mViewer; + double mTargetFrameRate; + double mLastWallpaperChangeTime; double mLastRenderTime; osg::Timer mTimer; From d432a3ed08c84d1d7993df2b1bfffbd9f6e26e87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:13:22 +0200 Subject: [PATCH 0227/1812] Fix MyGUI rendering not taking DataVariance of textures into account --- components/myguiplatform/myguirendermanager.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e9a6f8c4e2..442b6be786 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -401,6 +401,9 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) void RenderManager::begin() { + mDrawable->clear(); + // variance will be recomputed based on textures being rendered in this frame + mDrawable->setDataVariance(osg::Object::STATIC); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) @@ -410,7 +413,11 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text batch.mVertexBuffer = static_cast(buffer)->getBuffer(); batch.mArray = static_cast(buffer)->getArray(); if (texture) + { batch.mTexture = static_cast(texture)->getTexture(); + if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC) + mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin() + } mDrawable->addBatch(batch); } @@ -433,8 +440,9 @@ void RenderManager::update() void RenderManager::collectDrawCalls() { - mDrawable->clear(); + begin(); onRenderToTarget(this, mUpdate); + end(); mUpdate = false; } From 0da1e0e905ce0554897b45e0199bba9699c7bfaf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 00:17:08 +0200 Subject: [PATCH 0228/1812] Add comment --- components/myguiplatform/myguirendermanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 442b6be786..3a36a3b103 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -148,6 +148,7 @@ class Drawable : public osg::Drawable { if(texture) state->applyTextureAttribute(0, texture); + // VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909 osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; if (bufferobject) { From 48ffeab191714b62ec679400c883803e3a7961df Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 May 2015 01:06:55 +0200 Subject: [PATCH 0229/1812] Remove old BulletShapeManager --- apps/openmw/mwworld/physicssystem.cpp | 5 +- .../myguiplatform/myguirendermanager.cpp | 4 + components/nifbullet/bulletnifloader.cpp | 9 -- components/nifbullet/bulletnifloader.hpp | 9 +- libs/openengine/bullet/BulletShapeLoader.cpp | 88 ------------------- libs/openengine/bullet/BulletShapeLoader.h | 78 ---------------- libs/openengine/bullet/physic.cpp | 33 +++---- libs/openengine/bullet/physic.hpp | 31 ++----- 8 files changed, 25 insertions(+), 232 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 6a08e8e1f3..a43ca91780 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -533,9 +533,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { - // Create physics. shapeLoader is deleted by the physic engine - //NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(0);//shapeLoader); + mEngine = new OEngine::Physic::PhysicEngine; } PhysicsSystem::~PhysicsSystem() @@ -543,7 +541,6 @@ namespace MWWorld if (mWaterCollisionObject.get()) mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); delete mEngine; - //delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } bool PhysicsSystem::toggleDebugRendering() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3a36a3b103..3caa61548e 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -168,6 +168,10 @@ class Drawable : public osg::Drawable { glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); } + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + state->unbindVertexBufferObject(); state->dirtyAllVertexArrays(); state->disableAllVertexArrays(); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 0ddb6291ce..b80bbb83f2 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -323,15 +323,6 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int } } -void ManualBulletShapeLoader::load(const std::string &name,const std::string &group) -{ - // Check if the resource already exists - Ogre::ResourcePtr ptr = OEngine::Physic::BulletShapeManager::getSingleton().getByName(name, group); - if (!ptr.isNull()) - return; - OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); -} - bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) { if(node->hasBounds) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 733e9264be..b3e30cbd91 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -66,7 +66,7 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape /** *Load bulletShape from NIF files. */ -class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader +class ManualBulletShapeLoader { public: ManualBulletShapeLoader(bool showMarkers=false) @@ -96,13 +96,6 @@ public: */ void loadResource(Ogre::Resource *resource); - /** - *This function load a new bulletShape from a NIF file into the BulletShapeManager. - *When the file is loaded, you can then use BulletShapeManager::getByName() to retrive the bulletShape. - *Warning: this function will just crash if the resourceGroup doesn't exist! - */ - void load(const std::string &name,const std::string &group); - private: btVector3 getbtVector(Ogre::Vector3 const &v); diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 26b6caa0ed..d164b9b238 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -62,93 +62,5 @@ size_t BulletShape::calculateSize() const return 1; } - - -//============================================================================================================= -BulletShapeManager *BulletShapeManager::sThis = 0; - -BulletShapeManager *BulletShapeManager::getSingletonPtr() -{ - return sThis; -} - -BulletShapeManager &BulletShapeManager::getSingleton() -{ - assert(sThis); - return(*sThis); -} - -BulletShapeManager::BulletShapeManager() -{ - assert(!sThis); - sThis = this; - - mResourceType = "BulletShape"; - - // low, because it will likely reference other resources - mLoadOrder = 30.0f; - - // this is how we register the ResourceManager with OGRE - Ogre::ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this); -} - -BulletShapeManager::~BulletShapeManager() -{ - // and this is how we unregister it - Ogre::ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType); - - sThis = 0; -} - -BulletShapePtr BulletShapeManager::getByName(const Ogre::String& name, const Ogre::String& groupName) -{ - return getResourceByName(name, groupName).staticCast(); -} - -BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre::String& group, - bool isManual, Ogre::ManualResourceLoader* loader, - const Ogre::NameValuePairList* createParams) -{ - return createResource(name,group,isManual,loader,createParams).staticCast(); -} - -Ogre::ResourcePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group, - bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, - bool backgroundThread) -{ - return this->load(name, group); -} - -BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) -{ - BulletShapePtr textf = getByName(name); - - if (textf.isNull()) - textf = create(name, group); - - textf->load(); - return textf; -} - -Ogre::Resource *BulletShapeManager::createImpl(const Ogre::String &name, Ogre::ResourceHandle handle, - const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader, - const Ogre::NameValuePairList *createParams) -{ - BulletShape* res = new BulletShape(this, name, handle, group, isManual, loader); - //if(isManual) - //{ - //loader->loadResource(res); - //} - return res; -} - - -//==================================================================== -void BulletShapeLoader::loadResource(Ogre::Resource *resource) -{} - -void BulletShapeLoader::load(const std::string &name,const std::string &group) -{} - } } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 472efac6d4..a856e8153d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -53,84 +53,6 @@ public: */ typedef Ogre::SharedPtr BulletShapePtr; - -/** -*Hold any BulletShape that was created by the ManualBulletShapeLoader. -* -*To get a bulletShape, you must load it first. -*First, create a manualBulletShapeLoader. Then call ManualBulletShapeManager->load(). This create an "empty" resource. -*Then use BulletShapeManager->load(). This will fill the resource with the required info. -*To get the resource,use BulletShapeManager::getByName. -*When you use the resource no more, just use BulletShapeManager->unload(). It won't completly delete the resource, but it will -*"empty" it.This allow a better management of memory: when you are leaving a cell, just unload every useless shape. -* -*Alternatively, you can call BulletShape->load() in order to actually load the resource. -*When you are finished with it, just call BulletShape->unload(). -* -*IMO: prefere the first methode, i am not completly sure about the 2nd. -* -*Important Note: i have no idea of what happen if you try to load two time the same resource without unloading. -*It won't crash, but it might lead to memory leaks(I don't know how Ogre handle this). So don't do it! -*/ -class BulletShapeManager : public Ogre::ResourceManager -{ -protected: - - // must implement this from ResourceManager's interface - Ogre::Resource *createImpl(const Ogre::String &name, Ogre::ResourceHandle handle, - const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader, - const Ogre::NameValuePairList *createParams); - - static BulletShapeManager *sThis; - -private: - /** \brief Explicit private copy constructor. This is a forbidden operation.*/ - BulletShapeManager(const BulletShapeManager &); - - /** \brief Private operator= . This is a forbidden operation. */ - BulletShapeManager& operator=(const BulletShapeManager &); - - // Not intended to be used, declared here to keep the compiler from complaining - // about hidden virtual methods. - virtual Ogre::ResourcePtr load(const Ogre::String &name, const Ogre::String &group, - bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, - bool backgroundThread); - -public: - - BulletShapeManager(); - virtual ~BulletShapeManager(); - - - /// Get a resource by name - /// @see ResourceManager::getByName - BulletShapePtr getByName(const Ogre::String& name, - const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); - - /// Create a new shape - /// @see ResourceManager::createResource - BulletShapePtr create (const Ogre::String& name, const Ogre::String& group, - bool isManual = false, Ogre::ManualResourceLoader* loader = 0, - const Ogre::NameValuePairList* createParams = 0); - - virtual BulletShapePtr load(const Ogre::String &name, const Ogre::String &group); - - static BulletShapeManager &getSingleton(); - static BulletShapeManager *getSingletonPtr(); -}; - -class BulletShapeLoader : public Ogre::ManualResourceLoader -{ -public: - - BulletShapeLoader(){}; - virtual ~BulletShapeLoader() {} - - virtual void loadResource(Ogre::Resource *resource); - - virtual void load(const std::string &name,const std::string &group); -}; - } } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 889986339c..391d266df4 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -235,27 +235,25 @@ namespace Physic - PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) + PhysicEngine::PhysicEngine() { // Set up the collision configuration and dispatcher - collisionConfiguration = new btDefaultCollisionConfiguration(); - dispatcher = new btCollisionDispatcher(collisionConfiguration); + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); // The actual physics solver - solver = new btSequentialImpulseConstraintSolver; + mSolver = new btSequentialImpulseConstraintSolver; - broadphase = new btDbvtBroadphase(); + mBroadphase = new btDbvtBroadphase(); // The world. - mDynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration); + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. mDynamicsWorld->setForceUpdateAllAabbs(false); mDynamicsWorld->setGravity(btVector3(0,0,-10)); - - mShapeLoader = shapeLoader; } PhysicEngine::~PhysicEngine() @@ -294,11 +292,10 @@ namespace Physic } delete mDynamicsWorld; - delete solver; - delete collisionConfiguration; - delete dispatcher; - delete broadphase; - delete mShapeLoader; + delete mSolver; + delete mCollisionConfiguration; + delete mDispatcher; + delete mBroadphase; } void PhysicEngine::addHeightField(float* heights, @@ -382,9 +379,8 @@ namespace Physic std::string outputstring = mesh + sid; //get the shape from the .nif - mShapeLoader->load(outputstring,"General"); - BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); - BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + //mShapeLoader->load(outputstring,"General"); + //BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } @@ -397,9 +393,8 @@ namespace Physic std::string outputstring = mesh + sid; //get the shape from the .nif - mShapeLoader->load(outputstring,"General"); - BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); - BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + //mShapeLoader->load(outputstring,"General"); + BulletShapePtr shape;// = BulletShapeManager::getSingleton().getByName(outputstring,"General"); // TODO: add option somewhere to enable collision for placeable meshes diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6322105e8e..691ccbfd61 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -197,7 +197,7 @@ namespace Physic /** * Note that the shapeLoader IS destroyed by the phyic Engine!! */ - PhysicEngine(BulletShapeLoader* shapeLoader); + PhysicEngine(); /** * It DOES destroy the shape loader! @@ -290,15 +290,12 @@ namespace Physic btCollisionObject *object); //Bullet Stuff - btBroadphaseInterface* broadphase; - btDefaultCollisionConfiguration* collisionConfiguration; - btSequentialImpulseConstraintSolver* solver; - btCollisionDispatcher* dispatcher; + btBroadphaseInterface* mBroadphase; + btDefaultCollisionConfiguration* mCollisionConfiguration; + btSequentialImpulseConstraintSolver* mSolver; + btCollisionDispatcher* mDispatcher; btDiscreteDynamicsWorld* mDynamicsWorld; - //the NIF file loader. - BulletShapeLoader* mShapeLoader; - typedef std::map HeightFieldContainer; HeightFieldContainer mHeightFieldMap; @@ -318,24 +315,6 @@ namespace Physic }; - struct MyRayResultCallback : public btCollisionWorld::RayResultCallback - { - virtual btScalar addSingleResult( btCollisionWorld::LocalRayResult& rayResult, bool bNormalInWorldSpace) - { - results.push_back( std::make_pair(rayResult.m_hitFraction, rayResult.m_collisionObject) ); - return rayResult.m_hitFraction; - } - - static bool cmp( const std::pair& i, const std::pair& j ) - { - if( i.first > j.first ) return false; - if( j.first > i.first ) return true; - return false; - } - - std::vector < std::pair > results; - }; - }} #endif From c843cfc8e26e692ff4ee805d313d70d36c5e0fc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 00:28:51 +0200 Subject: [PATCH 0230/1812] Physics stub in preparation for rewrite --- CMakeLists.txt | 4 - apps/openmw/engine.cpp | 2 - apps/openmw/mwworld/physicssystem.cpp | 200 ++--- apps/openmw/mwworld/physicssystem.hpp | 12 - apps/openmw/mwworld/worldimp.cpp | 45 +- components/CMakeLists.txt | 6 +- components/myguiplatform/myguiloglistener.hpp | 4 +- components/nifbullet/bulletnifloader.hpp | 12 +- libs/openengine/.gitignore | 3 - libs/openengine/CMakeLists.txt | 17 - libs/openengine/README | 12 - libs/openengine/bullet/BulletShapeLoader.cpp | 66 -- libs/openengine/bullet/BulletShapeLoader.h | 59 -- libs/openengine/bullet/physic.cpp | 709 ------------------ libs/openengine/bullet/physic.hpp | 320 -------- libs/openengine/bullet/trace.cpp | 133 ---- libs/openengine/bullet/trace.h | 33 - 17 files changed, 80 insertions(+), 1557 deletions(-) delete mode 100644 libs/openengine/.gitignore delete mode 100644 libs/openengine/CMakeLists.txt delete mode 100644 libs/openengine/README delete mode 100644 libs/openengine/bullet/BulletShapeLoader.cpp delete mode 100644 libs/openengine/bullet/BulletShapeLoader.h delete mode 100644 libs/openengine/bullet/physic.cpp delete mode 100644 libs/openengine/bullet/physic.hpp delete mode 100644 libs/openengine/bullet/trace.cpp delete mode 100644 libs/openengine/bullet/trace.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 92023da2c3..2fa9cb8219 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -455,10 +455,6 @@ if(WIN32) include(CPack) endif(WIN32) -# Libs -include_directories(libs) -add_subdirectory(libs/openengine) - # Extern add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59c3667a4d..4c6d1585bf 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -24,8 +24,6 @@ #include #include -#include - #include #include "mwinput/inputmanagerimp.hpp" diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a43ca91780..7c1a44e486 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -2,20 +2,8 @@ #include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include -//#include - #include #include @@ -33,20 +21,18 @@ #include "../mwrender/bulletdebugdraw.hpp" //#include "../apps/openmw/mwrender/animation.hpp" -#include "../apps/openmw/mwbase/world.hpp" -#include "../apps/openmw/mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "ptr.hpp" #include "class.hpp" -using namespace Ogre; - namespace { +/* void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) { - /* for (std::map::iterator it = map.begin(); it != map.end(); ++it) { @@ -87,41 +73,11 @@ void animateCollisionShapes (std::mapupdateSingleAabb(it->first); } +} */ -} } -namespace BtOgre -{ -//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory. -class Convert -{ -public: - Convert() {}; - ~Convert() {}; - - static btQuaternion toBullet(const Ogre::Quaternion &q) - { - return btQuaternion(q.x, q.y, q.z, q.w); - } - static btVector3 toBullet(const Ogre::Vector3 &v) - { - return btVector3(v.x, v.y, v.z); - } - - static Ogre::Quaternion toOgre(const btQuaternion &q) - { - return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z()); - } - static Ogre::Vector3 toOgre(const btVector3 &v) - { - return Ogre::Vector3(v.x(), v.y(), v.z()); - } -}; -} - - namespace MWWorld { @@ -188,6 +144,8 @@ namespace MWWorld * +--+ +-------- * ============================================== */ + return false; +#if 0 OEngine::Physic::ActorTracer tracer, stepper; stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine); @@ -243,6 +201,7 @@ namespace MWWorld // moved between 0 and just under sStepSize distance but slope was too great, // or moved full sStepSize distance (FIXME: is this a bug?) +#endif return false; } @@ -266,6 +225,8 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); + return position; +#if 0 OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if (!physicActor) return position; @@ -302,6 +263,7 @@ namespace MWWorld return tracer.mEndPos; } +#endif } static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, @@ -311,7 +273,8 @@ namespace MWWorld { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); - + return position; +#if 0 // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -526,21 +489,20 @@ namespace MWWorld newPosition.z -= halfExtents.z; // remove what was added at the beginning return newPosition; +#endif } }; PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : - mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) + mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) { - mEngine = new OEngine::Physic::PhysicEngine; } PhysicsSystem::~PhysicsSystem() { - if (mWaterCollisionObject.get()) - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); - delete mEngine; + //if (mWaterCollisionObject.get()) + // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } bool PhysicsSystem::toggleDebugRendering() @@ -549,25 +511,22 @@ namespace MWWorld if (mDebugDrawEnabled && !mDebugDrawer.get()) { - mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); - mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); - mDebugDrawer->setDebugMode(mDebugDrawEnabled); + //mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); + //mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + //mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) mDebugDrawer->setDebugMode(mDebugDrawEnabled); return mDebugDrawEnabled; } - OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() - { - return mEngine; - } - std::pair PhysicsSystem::getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orient, float queryDistance) { + return std::make_pair(std::string(), Ogre::Vector3()); + /* const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(), @@ -589,22 +548,28 @@ namespace MWWorld if(!result.first) return std::make_pair(std::string(), Ogre::Vector3(&result.second[0])); return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0])); + */ } - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool ignoreHeightMap) + bool PhysicsSystem::castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool ignoreHeightMap) { + return false; + /* btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); return !(result.first == ""); + */ } std::pair PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len) { + return std::make_pair(false, Ogre::Vector3()); + /* Ogre::Ray ray = Ogre::Ray(orig, dir); Ogre::Vector3 to = ray.getPoint(len); @@ -616,125 +581,42 @@ namespace MWWorld return std::make_pair(false, Ogre::Vector3()); } return std::make_pair(true, ray.getPoint(len * test.second)); + */ } std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) { - return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); + return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) { - return MovementSolver::traceDown(ptr, mEngine, maxHeight); + return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) { - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); } void PhysicsSystem::removeHeightField (int x, int y) { - mEngine->removeHeightField(x, y); } void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - /* - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - handleToMesh[node->getName()] = mesh; - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); - */ + } void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - /* - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - //TODO:optimize this. Searching the std::map isn't very efficient i think. - mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); - */ - } - void PhysicsSystem::removeObject (const std::string& handle) - { - mEngine->removeCharacter(handle); - mEngine->removeRigidBody(handle); - mEngine->deleteRigidBody(handle); - } - - void PhysicsSystem::moveObject (const Ptr& ptr) - { - Ogre::SceneNode *node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - const Ogre::Vector3 &position = node->getPosition(); - - if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) - { - body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } - - // Actors update their AABBs every frame (DISABLE_DEACTIVATION), so no need to do it manually - if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) - physact->setPosition(position); - } - - void PhysicsSystem::rotateObject (const Ptr& ptr) - { - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - const Ogre::Quaternion &rotation = node->getOrientation(); - - // TODO: map to MWWorld::Ptr for faster access - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - act->setRotation(rotation); - } - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - if(dynamic_cast(body->getCollisionShape()) == NULL) - body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); - else - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); - mEngine->mDynamicsWorld->updateSingleAabb(body); - } - } - - void PhysicsSystem::scaleObject (const Ptr& ptr) - { - Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld(); - const std::string &handle = node->getName(); - if(handleToMesh.find(handle) != handleToMesh.end()) - { - std::string model = ptr.getClass().getModel(ptr); - //model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model - - bool placeable = false; - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - placeable = body->mPlaceable; - removeObject(handle); - addObject(ptr, model, placeable); - } - - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - float scale = ptr.getCellRef().getScale(); - osg::Vec3f scaleVec (scale,scale,scale); - if (!ptr.getClass().isNpc()) - // NOTE: Ignoring Npc::adjustScale (race height) on purpose. This is a bug in MW and must be replicated for compatibility reasons - ptr.getClass().adjustScale(ptr, scaleVec); - act->setScale(scaleVec.x()); - } } bool PhysicsSystem::toggleCollisionMode() { + /* for(std::map::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it) { if (it->first=="player") @@ -756,6 +638,8 @@ namespace MWWorld } throw std::logic_error ("can't find player"); + */ + return false; } void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) @@ -791,6 +675,8 @@ namespace MWWorld mCollisions.clear(); mStandingCollisions.clear(); + /* + const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -831,6 +717,8 @@ namespace MWWorld mMovementResults.push_back(std::make_pair(iter->first, newpos)); } + */ + mTimeAccum = 0.0f; } mMovementQueue.clear(); @@ -840,9 +728,9 @@ namespace MWWorld void PhysicsSystem::stepSimulation(float dt) { - animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); + //animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); - mEngine->stepSimulation(dt); + //mEngine->stepSimulation(dt); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -932,7 +820,7 @@ namespace MWWorld { if (mWaterCollisionObject.get()) { - mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + //mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -941,7 +829,7 @@ namespace MWWorld mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, - OEngine::Physic::CollisionType_Actor); + //mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, + // OEngine::Physic::CollisionType_Actor); } } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1fc0e0e768..018ea0a28e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -55,15 +55,6 @@ namespace MWWorld void removeHeightField (int x, int y); - // have to keep this as handle for now as unloadcell only knows scenenode names - void removeObject (const std::string& handle); - - void moveObject (const MWWorld::Ptr& ptr); - - void rotateObject (const MWWorld::Ptr& ptr); - - void scaleObject (const MWWorld::Ptr& ptr); - bool toggleCollisionMode(); void stepSimulation(float dt); @@ -82,8 +73,6 @@ namespace MWWorld std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - OEngine::Physic::PhysicEngine* getEngine(); - /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); @@ -117,7 +106,6 @@ namespace MWWorld bool mDebugDrawEnabled; - OEngine::Physic::PhysicEngine* mEngine; std::map handleToMesh; // Tracks all movement collisions happening during a single frame. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 04fd82e80a..7047978ff5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -13,9 +13,6 @@ #include -#include -#include - #include #include @@ -59,8 +56,6 @@ #include "contentloader.hpp" #include "esmloader.hpp" -using namespace Ogre; - namespace { @@ -1402,7 +1397,7 @@ namespace MWWorld cellY = static_cast(std::floor(y / cellSize)); } - void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) + void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity) { //mPhysics->queueObjectMovement(ptr, velocity); } @@ -1630,7 +1625,9 @@ namespace MWWorld void World::updateSoundListener() { + /* Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -1638,6 +1635,7 @@ namespace MWWorld Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(), playerOrient.zAxis()); + */ } void World::updateWindowManager () @@ -1654,7 +1652,7 @@ namespace MWWorld Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { - Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); + Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } @@ -1746,11 +1744,11 @@ namespace MWWorld MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) - return Vector2(0, 1); + return Ogre::Vector2(0, 1); Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Vector3 dir = orient * Ogre::Vector3(0,1,0); - Vector2 d = Vector2(dir.x, dir.y); + Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0); + Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y); return d; } @@ -2002,9 +2000,9 @@ namespace MWWorld && isLevitationEnabled()) return true; - const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); - if(!actor || !actor->getCollisionMode()) - return true; + //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); + //if(!actor || !actor->getCollisionMode()) + // return true; return false; } @@ -2042,10 +2040,10 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); - if (actor) + //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); + //if (actor) { - pos.z += heightRatio*2*actor->getHalfExtents().z; + // pos.z += heightRatio*2*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); @@ -2071,6 +2069,8 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { + return true; + /* //RefData &refdata = ptr.getRefData(); OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); @@ -2096,6 +2096,7 @@ namespace MWWorld else return false; } + */ } bool World::vanityRotateCamera(float * rot) @@ -2371,6 +2372,7 @@ namespace MWWorld if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) return false; // not in active cell + /* OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); @@ -2387,12 +2389,15 @@ namespace MWWorld std::pair result = mPhysEngine->rayTest(from, to,false); if(result.first == "") return true; + */ return false; } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) { + return 0; + /* btVector3 btFrom(from.x, from.y, from.z); btVector3 btTo = btVector3(dir.x, dir.y, dir.z); btTo.normalize(); @@ -2402,13 +2407,16 @@ namespace MWWorld if(result.second == -1) return maxDist; else return result.second*(btTo-btFrom).length(); + */ } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { + /* OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor) physicActor->enableCollisionBody(enable); + */ } bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) @@ -3235,7 +3243,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, + void World::explodeSpell(const Ogre::Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3350,9 +3358,12 @@ namespace MWWorld bool World::isWalkingOnWater(const Ptr &actor) { + return false; + /* OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; + */ } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1f9bd337b1..931d84e26c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -add_component_dir (nifbullet - bulletnifloader - ) +#add_component_dir (nifbullet +# bulletnifloader +# ) add_component_dir (to_utf8 to_utf8 diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp index 3da4d3c525..70dfc4ecfd 100644 --- a/components/myguiplatform/myguiloglistener.hpp +++ b/components/myguiplatform/myguiloglistener.hpp @@ -1,5 +1,5 @@ -#ifndef OPENENGINE_MYGUI_LOGLISTENER_H -#define OPENENGINE_MYGUI_LOGLISTENER_H +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H +#define OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H #include #include diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index b3e30cbd91..2a2e914e35 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -26,11 +26,11 @@ #include #include +#include #include #include #include #include -#include #include @@ -70,8 +70,7 @@ class ManualBulletShapeLoader { public: ManualBulletShapeLoader(bool showMarkers=false) - : mShape(NULL) - , mCompoundShape(NULL) + : mCompoundShape(NULL) , mStaticMesh(NULL) , mBoundingBox(NULL) , mShowMarkers(showMarkers) @@ -91,11 +90,6 @@ public: abort(); } - /** - *This function should not be called manualy. Use load instead. (this is called by the BulletShapeManager when you use load). - */ - void loadResource(Ogre::Resource *resource); - private: btVector3 getbtVector(Ogre::Vector3 const &v); @@ -116,7 +110,7 @@ private: std::string mResourceName; - OEngine::Physic::BulletShape* mShape;//current shape + //OEngine::Physic::BulletShape* mShape;//current shape btCompoundShape* mCompoundShape; diff --git a/libs/openengine/.gitignore b/libs/openengine/.gitignore deleted file mode 100644 index 23a5e931b8..0000000000 --- a/libs/openengine/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*~ -*.o -*_test diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt deleted file mode 100644 index 52c12a84ad..0000000000 --- a/libs/openengine/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(OENGINE_BULLET - bullet/physic.cpp - bullet/physic.hpp - bullet/BulletShapeLoader.cpp - bullet/BulletShapeLoader.h - bullet/trace.cpp - bullet/trace.h -) - -set(OENGINE_ALL ${OENGINE_BULLET}) - -set(OENGINE_LIBRARY "oengine") -set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) - -source_group(oengine FILES ${OENGINE_ALL}) - -add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL}) diff --git a/libs/openengine/README b/libs/openengine/README deleted file mode 100644 index 621fe8d60c..0000000000 --- a/libs/openengine/README +++ /dev/null @@ -1,12 +0,0 @@ -OpenEngine README -================= - -OpenEngine is a bunch of stand-alone game engine modules collected from the OpenMW project (see http://github.com/korslund/openmw or http://openmw.com ) and from certain other projects. - -It is currently a very early work in progress, and development will follow OpenMW closely for a while forward. - -OpenEngine will depend heavily on Mangle ( http://github.com/korslund/mangle/ ) and will thus aim to be backend agnostic. When finished it should work with a variety for free and commercial middleware libraries as backends for graphics, sound, physics, input and so on. - -All questions can be directed to Nicolay Korslund at korslund@gmail.com - -- Nicolay diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp deleted file mode 100644 index d164b9b238..0000000000 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "BulletShapeLoader.h" - -namespace OEngine { -namespace Physic -{ - -BulletShape::BulletShape(Ogre::ResourceManager* creator, const Ogre::String &name, - Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual, - Ogre::ManualResourceLoader *loader) : -Ogre::Resource(creator, name, handle, group, isManual, loader) -{ - /* If you were storing a pointer to an object, then you would set that pointer to NULL here. - */ - - /* For consistency with StringInterface, but we don't add any parameters here - That's because the Resource implementation of StringInterface is to - list all the options that need to be set before loading, of which - we have none as such. Full details can be set through scripts. - */ - mCollisionShape = NULL; - mAutogenerated = true; - createParamDictionary("BulletShape"); -} - -BulletShape::~BulletShape() -{ - deleteShape(mCollisionShape); -} - -// farm out to BulletShapeLoader -void BulletShape::loadImpl() -{ - mLoader->loadResource(this); -} - -void BulletShape::deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - } - delete shape; - } -} - -void BulletShape::unloadImpl() -{ - deleteShape(mCollisionShape); - mCollisionShape = NULL; -} - -//TODO:change this? -size_t BulletShape::calculateSize() const -{ - return 1; -} - -} -} diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h deleted file mode 100644 index a856e8153d..0000000000 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef OPENMW_BULLET_SHAPE_LOADER_H_ -#define OPENMW_BULLET_SHAPE_LOADER_H_ - -#include -#include -#include -#include - -#include -#include - -namespace OEngine { -namespace Physic -{ - -/** -*Define a new resource which describe a Shape usable by bullet.See BulletShapeManager for how to get/use them. -*/ -class BulletShape : public Ogre::Resource -{ -protected: - void loadImpl(); - void unloadImpl(); - size_t calculateSize() const; - - void deleteShape(btCollisionShape* shape); - -public: - - BulletShape(Ogre::ResourceManager *creator, const Ogre::String &name, - Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual = false, - Ogre::ManualResourceLoader *loader = 0); - - virtual ~BulletShape(); - - // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape - // will be a btCompoundShape (which consists of one or more child shapes). - // In this map, for each animated collision shape, - // we store the node's record index mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; - - btCollisionShape* mCollisionShape; - - // Does this .nif have an autogenerated collision mesh? - bool mAutogenerated; - - osg::Vec3f mBoxTranslation; - osg::Quat mBoxRotation; -}; - -/** -* -*/ - -typedef Ogre::SharedPtr BulletShapePtr; -} -} - -#endif diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp deleted file mode 100644 index 391d266df4..0000000000 --- a/libs/openengine/bullet/physic.cpp +++ /dev/null @@ -1,709 +0,0 @@ -#include "physic.hpp" - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -namespace -{ - -// Create a copy of the given collision shape (responsibility of user to delete the returned shape). -btCollisionShape *duplicateCollisionShape(btCollisionShape *shape) -{ - if(shape->isCompound()) - { - btCompoundShape *comp = static_cast(shape); - btCompoundShape *newShape = new btCompoundShape; - - int numShapes = comp->getNumChildShapes(); - for(int i = 0;i < numShapes;i++) - { - btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); - btTransform trans = comp->getChildTransform(i); - newShape->addChildShape(trans, child); - } - - return newShape; - } - - if(btBvhTriangleMeshShape *trishape = dynamic_cast(shape)) - { - btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); - btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true); - - return newShape; - } - - throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); -} - -void deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - } - delete shape; - } -} - -} - -namespace OEngine { -namespace Physic -{ - - PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) - : mCanWaterWalk(false), mWalkingOnWater(false) - , mBody(0), mScale(scale), mForce(0.0f), mOnGround(false) - , mInternalCollisionMode(true) - , mExternalCollisionMode(true) - , mMesh(mesh), mName(name), mEngine(engine) - { - /* - if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) - { - mHalfExtents = Ogre::Vector3(0.f); - mMeshTranslation = Ogre::Vector3(0.f); - mMeshOrientation = Ogre::Quaternion::IDENTITY; - } - */ - /* - // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) - if (std::abs(mHalfExtents.x-mHalfExtents.y)= mHalfExtents.x) - { - // Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work) - mShape.reset(new btCylinderShapeZ(BtOgre::Convert::toBullet(mHalfExtents))); - } - else - mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents))); - */ - - mShape->setLocalScaling(btVector3(scale,scale,scale)); - - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,0, mShape.get()); - mBody = new RigidBody(CI, name); - mBody->mPlaceable = false; - mBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - mBody->setActivationState(DISABLE_DEACTIVATION); - - setPosition(position); - setRotation(rotation); - - updateCollisionMask(); - } - - PhysicActor::~PhysicActor() - { - if(mBody) - { - mEngine->mDynamicsWorld->removeRigidBody(mBody); - delete mBody; - } - } - - void PhysicActor::enableCollisionMode(bool collision) - { - mInternalCollisionMode = collision; - } - - void PhysicActor::enableCollisionBody(bool collision) - { - if (mExternalCollisionMode != collision) - { - mExternalCollisionMode = collision; - updateCollisionMask(); - } - } - - void PhysicActor::updateCollisionMask() - { - mEngine->mDynamicsWorld->removeRigidBody(mBody); - int collisionMask = CollisionType_World | CollisionType_HeightMap; - if (mExternalCollisionMode) - collisionMask |= CollisionType_Actor | CollisionType_Projectile; - if (mCanWaterWalk) - collisionMask |= CollisionType_Water; - mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, collisionMask); - } - - const Ogre::Vector3& PhysicActor::getPosition() const - { - return mPosition; - } - - void PhysicActor::setPosition(const Ogre::Vector3 &position) - { - assert(mBody); - - mPosition = position; - - //btTransform tr = mBody->getWorldTransform(); - //Ogre::Quaternion meshrot = mMeshOrientation; - //Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale); - //Ogre::Vector3 newPosition = transrot + position; - - //tr.setOrigin(BtOgre::Convert::toBullet(newPosition)); - //mBody->setWorldTransform(tr); - } - - void PhysicActor::setRotation (const Ogre::Quaternion& rotation) - { - //btTransform tr = mBody->getWorldTransform(); - //tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation)); - //mBody->setWorldTransform(tr); - } - - void PhysicActor::setScale(float scale) - { - mScale = scale; - mShape->setLocalScaling(btVector3(scale,scale,scale)); - setPosition(mPosition); - } - - Ogre::Vector3 PhysicActor::getHalfExtents() const - { - return mHalfExtents * mScale; - } - - void PhysicActor::setInertialForce(const Ogre::Vector3 &force) - { - mForce = force; - } - - void PhysicActor::setOnGround(bool grounded) - { - mOnGround = grounded; - } - - bool PhysicActor::isWalkingOnWater() const - { - return mWalkingOnWater; - } - - void PhysicActor::setWalkingOnWater(bool walkingOnWater) - { - mWalkingOnWater = walkingOnWater; - } - - void PhysicActor::setCanWaterWalk(bool waterWalk) - { - if (waterWalk != mCanWaterWalk) - { - mCanWaterWalk = waterWalk; - updateCollisionMask(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) - : btRigidBody(CI) - , mName(name) - , mPlaceable(false) - { - } - - RigidBody::~RigidBody() - { - delete getMotionState(); - } - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////// - - - - PhysicEngine::PhysicEngine() - { - // Set up the collision configuration and dispatcher - mCollisionConfiguration = new btDefaultCollisionConfiguration(); - mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - - // The actual physics solver - mSolver = new btSequentialImpulseConstraintSolver; - - mBroadphase = new btDbvtBroadphase(); - - // The world. - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); - - // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. - // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. - mDynamicsWorld->setForceUpdateAllAabbs(false); - - mDynamicsWorld->setGravity(btVector3(0,0,-10)); - } - - PhysicEngine::~PhysicEngine() - { - for (std::map::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it) - deleteShape(it->second.mCompound); - - HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); - for (; hf_it != mHeightFieldMap.end(); ++hf_it) - { - mDynamicsWorld->removeRigidBody(hf_it->second.mBody); - delete hf_it->second.mShape; - delete hf_it->second.mBody; - } - - RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); - for (; rb_it != mCollisionObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } - - PhysicActorContainer::iterator pa_it = mActorMap.begin(); - for (; pa_it != mActorMap.end(); ++pa_it) - { - if (pa_it->second != NULL) - { - delete pa_it->second; - pa_it->second = NULL; - } - } - - delete mDynamicsWorld; - delete mSolver; - delete mCollisionConfiguration; - delete mDispatcher; - delete mBroadphase; - } - - void PhysicEngine::addHeightField(float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - // find the minimum and maximum heights (needed for bullet) - float minh = heights[0]; - float maxh = heights[0]; - for (int i=0; imaxh) maxh = h; - if (h(sqrtVerts), static_cast(sqrtVerts), heights, 1, - minh, maxh, 2, - PHY_FLOAT,true); - - hfShape->setUseDiamondSubdivision(true); - - btVector3 scl(triSize, triSize, 1); - hfShape->setLocalScaling(scl); - - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); - RigidBody* body = new RigidBody(CI,name); - body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); - - HeightField hf; - hf.mBody = body; - hf.mShape = hfShape; - - mHeightFieldMap [name] = hf; - - mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, - CollisionType_Actor|CollisionType_Projectile); - } - - void PhysicEngine::removeHeightField(int x, int y) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - HeightFieldContainer::iterator it = mHeightFieldMap.find(name); - if (it == mHeightFieldMap.end()) - return; - - const HeightField& hf = it->second; - - mDynamicsWorld->removeRigidBody(hf.mBody); - delete hf.mShape; - delete hf.mBody; - - mHeightFieldMap.erase(it); - } - - void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation) - { - btTransform tr; - Ogre::Quaternion boxrot = rotation * boxRotation; - Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; - Ogre::Vector3 newPosition = transrot + position; - - tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); - body->setWorldTransform(tr); - } - void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - //get the shape from the .nif - //mShapeLoader->load(outputstring,"General"); - //BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - - //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - } - - RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool placeable) - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - //get the shape from the .nif - //mShapeLoader->load(outputstring,"General"); - BulletShapePtr shape;// = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - - // TODO: add option somewhere to enable collision for placeable meshes - - if (placeable && shape->mCollisionShape) - return NULL; - - if (!shape->mCollisionShape) - return NULL; - - btCollisionShape* collisionShape = shape->mCollisionShape; - - // If this is an animated compound shape, we must duplicate it so we can animate - // multiple instances independently. - if (!shape->mAnimatedShapes.empty()) - collisionShape = duplicateCollisionShape(collisionShape); - - collisionShape->setLocalScaling( btVector3(scale,scale,scale)); - - //create the real body - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,0, collisionShape); - RigidBody* body = new RigidBody(CI,name); - body->mPlaceable = placeable; - - if (!shape->mAnimatedShapes.empty()) - { - AnimatedShapeInstance instance; - instance.mAnimatedShapes = shape->mAnimatedShapes; - instance.mCompound = collisionShape; - mAnimatedShapes[body] = instance; - } - - //if(scaledBoxTranslation != 0) - // *scaledBoxTranslation = shape->mBoxTranslation * scale; - //if(boxRotation != 0) - // *boxRotation = shape->mBoxRotation; - - //adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); - - assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); - mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); - - return body; - } - - void PhysicEngine::removeRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } - } - - void PhysicEngine::deleteRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - if (mAnimatedShapes.find(body) != mAnimatedShapes.end()) - deleteShape(mAnimatedShapes[body].mCompound); - mAnimatedShapes.erase(body); - - delete body; - } - mCollisionObjectMap.erase(it); - } - } - - RigidBody* PhysicEngine::getRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = mCollisionObjectMap[name]; - return body; - } - else - { - return NULL; - } - } - - class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - public: - std::vector mResult; - - // added in bullet 2.81 - // this is just a quick hack, as there does not seem to be a BULLET_VERSION macro? -#if defined(BT_COLLISION_OBJECT_WRAPPER_H) - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) - { - const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); - if (body) - mResult.push_back(body->mName); - - return 0.f; - } -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const RigidBody* body = dynamic_cast(col0); - if (body) - mResult.push_back(body->mName); - - return 0.f; - } -#endif - }; - - class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - const std::string &mFilter; - // Store the real origin, since the shape's origin is its center - btVector3 mOrigin; - - public: - const RigidBody *mObject; - btVector3 mContactPoint; - btScalar mLeastDistSqr; - - DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin) - : mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0), - mLeastDistSqr(std::numeric_limits::max()) - { } - -#if defined(BT_COLLISION_OBJECT_WRAPPER_H) - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) - { - const RigidBody* body = dynamic_cast(col1Wrap->m_collisionObject); - if(body && body->mName != mFilter) - { - btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); - if(!mObject || distsqr < mLeastDistSqr) - { - mObject = body; - mLeastDistSqr = distsqr; - mContactPoint = cp.getPositionWorldOnA(); - } - } - - return 0.f; - } -#else - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObject* col0, int partId0, int index0, - const btCollisionObject* col1, int partId1, int index1) - { - const RigidBody* body = dynamic_cast(col1); - if(body && body->mName != mFilter) - { - btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); - if(!mObject || distsqr < mLeastDistSqr) - { - mObject = body; - mLeastDistSqr = distsqr; - mContactPoint = cp.getPositionWorldOnA(); - } - } - - return 0.f; - } -#endif - }; - - - std::vector PhysicEngine::getCollisions(const std::string& name, int collisionGroup, int collisionMask) - { - RigidBody* body = getRigidBody(name); - ContactTestResultCallback callback; - callback.m_collisionFilterGroup = collisionGroup; - callback.m_collisionFilterMask = collisionMask; - mDynamicsWorld->contactTest(body, callback); - return callback.mResult; - } - - - std::pair PhysicEngine::getFilteredContact(const std::string &filter, - const btVector3 &origin, - btCollisionObject *object) - { - DeepestNotMeContactTestResultCallback callback(filter, origin); - callback.m_collisionFilterGroup = CollisionType_Actor; - callback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; - mDynamicsWorld->contactTest(object, callback); - return std::make_pair(callback.mObject, callback.mContactPoint); - } - - void PhysicEngine::stepSimulation(double deltaT) - { - // This seems to be needed for character controller objects - mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); - } - - void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, - const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation) - { - // Remove character with given name, so we don't make memory - // leak when character would be added twice - removeCharacter(name); - - PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale); - - mActorMap[name] = newActor; - } - - void PhysicEngine::removeCharacter(const std::string &name) - { - PhysicActorContainer::iterator it = mActorMap.find(name); - if (it != mActorMap.end() ) - { - PhysicActor* act = it->second; - if(act != NULL) - { - delete act; - } - mActorMap.erase(it); - } - } - - PhysicActor* PhysicEngine::getCharacter(const std::string &name) - { - PhysicActorContainer::iterator it = mActorMap.find(name); - if (it != mActorMap.end() ) - { - PhysicActor* act = mActorMap[name]; - return act; - } - else - { - return 0; - } - } - - std::pair PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool ignoreHeightMap, Ogre::Vector3* normal) - { - std::string name = ""; - float d = -1; - - btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterGroup = 0xff; - resultCallback1.m_collisionFilterMask = CollisionType_World; - - if(!ignoreHeightMap) - resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; - mDynamicsWorld->rayTest(from, to, resultCallback1); - if (resultCallback1.hasHit()) - { - name = static_cast(*resultCallback1.m_collisionObject).mName; - d = resultCallback1.m_closestHitFraction; - if (normal) - *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), - resultCallback1.m_hitNormalWorld.y(), - resultCallback1.m_hitNormalWorld.z()); - } - - return std::pair(name,d); - } - - // callback that ignores player in results - struct OurClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback - { - public: - OurClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) - : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld) {} - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) - { - if (const RigidBody* body = dynamic_cast(convexResult.m_hitCollisionObject)) - if (body->mName == "player") - return 0; - return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - } - }; - - std::pair PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to) - { - OurClosestConvexResultCallback callback(from, to); - callback.m_collisionFilterGroup = 0xff; - callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap; - - btSphereShape shape(radius); - const btQuaternion btrot(0.0f, 0.0f, 0.0f); - - btTransform from_ (btrot, from); - btTransform to_ (btrot, to); - - mDynamicsWorld->convexSweepTest(&shape, from_, to_, callback); - - if (callback.hasHit()) - return std::make_pair(true, callback.m_closestHitFraction); - else - return std::make_pair(false, 1.0f); - } - -} -} diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp deleted file mode 100644 index 691ccbfd61..0000000000 --- a/libs/openengine/bullet/physic.hpp +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef OENGINE_BULLET_PHYSIC_H -#define OENGINE_BULLET_PHYSIC_H - -#include -#include "BulletCollision/CollisionDispatch/btGhostObject.h" -#include -#include -#include -#include "BulletShapeLoader.h" -#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" -#include - -class btRigidBody; -class btBroadphaseInterface; -class btDefaultCollisionConfiguration; -class btSequentialImpulseConstraintSolver; -class btCollisionDispatcher; -class btDiscreteDynamicsWorld; -class btHeightfieldTerrainShape; - -namespace BtOgre -{ - class DebugDrawer; -} - -namespace Ogre -{ - class SceneManager; -} - -namespace MWWorld -{ - class World; -} - - -namespace OEngine { -namespace Physic -{ - struct PhysicEvent; - class PhysicEngine; - class RigidBody; - - enum CollisionType { - CollisionType_Nothing = 0, // mShape; - - OEngine::Physic::RigidBody* mBody; - - Ogre::Quaternion mMeshOrientation; - Ogre::Vector3 mMeshTranslation; - Ogre::Vector3 mHalfExtents; - - float mScale; - Ogre::Vector3 mPosition; - - Ogre::Vector3 mForce; - bool mOnGround; - bool mInternalCollisionMode; - bool mExternalCollisionMode; - - std::string mMesh; - std::string mName; - PhysicEngine *mEngine; - - PhysicActor(const PhysicActor&); - PhysicActor& operator=(const PhysicActor&); - }; - - - struct HeightField - { - btHeightfieldTerrainShape* mShape; - RigidBody* mBody; - }; - - struct AnimatedShapeInstance - { - btCollisionShape* mCompound; - - // Maps node record index to child index in the compound shape - std::map mAnimatedShapes; - }; - - /** - * The PhysicEngine class contain everything which is needed for Physic. - * It's needed that Ogre Resources are set up before the PhysicEngine is created. - * Note:deleting it WILL NOT delete the RigidBody! - * TODO:unload unused resources? - */ - class PhysicEngine - { - public: - /** - * Note that the shapeLoader IS destroyed by the phyic Engine!! - */ - PhysicEngine(); - - /** - * It DOES destroy the shape loader! - */ - ~PhysicEngine(); - - /** - * Creates a RigidBody. It does not add it to the simulation. - * After created, the body is set to the correct rotation, position, and scale - */ - RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, - float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool placeable=false); - - /** - * Adjusts a rigid body to the right position and rotation - */ - - void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO, - const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY); - /** - Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. - */ - void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); - /** - * Add a HeightField to the simulation - */ - void addHeightField(float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts); - - /** - * Remove a HeightField from the simulation - */ - void removeHeightField(int x, int y); - - /** - * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. - */ - void removeRigidBody(const std::string &name); - - /** - * Delete a RigidBody, and remove it from RigidBodyMap. - */ - void deleteRigidBody(const std::string &name); - - /** - * Return a pointer to a given rigid body. - */ - RigidBody* getRigidBody(const std::string &name); - - /** - * Create and add a character to the scene, and add it to the ActorMap. - */ - void addCharacter(const std::string &name, const std::string &mesh, - const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); - - /** - * Remove a character from the scene. - */ - void removeCharacter(const std::string &name); - - /** - * Return a pointer to a character - */ - PhysicActor* getCharacter(const std::string &name); - - /** - * This step the simulation of a given time. - */ - void stepSimulation(double deltaT); - - /** - * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). - * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) - */ - std::pair rayTest(const btVector3& from,const btVector3& to, - bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); - - std::pair sphereCast (float radius, btVector3& from, btVector3& to); - ///< @return (hit, relative distance) - - std::vector getCollisions(const std::string& name, int collisionGroup, int collisionMask); - - // Get the nearest object that's inside the given object, filtering out objects of the - // provided name - std::pair getFilteredContact(const std::string &filter, - const btVector3 &origin, - btCollisionObject *object); - - //Bullet Stuff - btBroadphaseInterface* mBroadphase; - btDefaultCollisionConfiguration* mCollisionConfiguration; - btSequentialImpulseConstraintSolver* mSolver; - btCollisionDispatcher* mDispatcher; - btDiscreteDynamicsWorld* mDynamicsWorld; - - typedef std::map HeightFieldContainer; - HeightFieldContainer mHeightFieldMap; - - typedef std::map RigidBodyContainer; - RigidBodyContainer mCollisionObjectMap; - - // Compound shapes that must be animated each frame based on bone positions - // the index refers to an element in mCollisionObjectMap - std::map mAnimatedShapes; - - typedef std::map PhysicActorContainer; - PhysicActorContainer mActorMap; - - private: - PhysicEngine(const PhysicEngine&); - PhysicEngine& operator=(const PhysicEngine&); - }; - - -}} - -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp deleted file mode 100644 index c0f653dae7..0000000000 --- a/libs/openengine/bullet/trace.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -#include "trace.h" - -#include - -#include -#include - -#include "physic.hpp" - - -namespace OEngine -{ -namespace Physic -{ - -class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback -{ -public: - ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot) - : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), - mMe(me), mUp(up), mMinSlopeDot(minSlopeDot) - { - } - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) - { - if(convexResult.m_hitCollisionObject == mMe) - return btScalar( 1 ); - - btVector3 hitNormalWorld; - if(normalInWorldSpace) - hitNormalWorld = convexResult.m_hitNormalLocal; - else - { - ///need to transform normal into worldspace - hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; - } - - // NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box... - - btScalar dotUp = mUp.dot(hitNormalWorld); - if(dotUp < mMinSlopeDot) - return btScalar(1); - - return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - } - -protected: - btCollisionObject *mMe; - const btVector3 mUp; - const btScalar mMinSlopeDot; -}; - - -void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass) -{ - const btVector3 btstart(start.x, start.y, start.z); - const btVector3 btend(end.x, end.y, end.z); - - const btTransform &trans = actor->getWorldTransform(); - btTransform from(trans); - btTransform to(trans); - from.setOrigin(btstart); - to.setOrigin(btend); - - ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0)); - // Inherit the actor's collision group and mask - newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup; - newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask; - - btCollisionShape *shape = actor->getCollisionShape(); - assert(shape->isConvex()); - enginePass->mDynamicsWorld->convexSweepTest(static_cast(shape), - from, to, newTraceCallback); - - // Copy the hit data over to our trace results struct: - if(newTraceCallback.hasHit()) - { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); - mEndPos = (end-start)*mFraction + start; - mHitObject = newTraceCallback.m_hitCollisionObject; - } - else - { - mEndPos = end; - mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - mFraction = 1.0f; - mHitObject = NULL; - } -} - -void ActorTracer::findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass) -{ - const btVector3 btstart(start.x, start.y, start.z+1.0f); - const btVector3 btend(end.x, end.y, end.z+1.0f); - - const btTransform &trans = actor->getCollisionBody()->getWorldTransform(); - btTransform from(trans.getBasis(), btstart); - btTransform to(trans.getBasis(), btend); - - ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionBody(), btstart-btend, btScalar(0.0)); - // Inherit the actor's collision group and mask - newTraceCallback.m_collisionFilterGroup = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterGroup; - newTraceCallback.m_collisionFilterMask = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterMask; - newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor; - - btVector3 halfExtents(actor->getHalfExtents().x, actor->getHalfExtents().y, actor->getHalfExtents().z); - - halfExtents[2] = 1.0f; - btCylinderShapeZ base(halfExtents); - - enginePass->mDynamicsWorld->convexSweepTest(&base, from, to, newTraceCallback); - if(newTraceCallback.hasHit()) - { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); - mEndPos = (end-start)*mFraction + start; - mEndPos[2] += 1.0f; - } - else - { - mEndPos = end; - mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - mFraction = 1.0f; - } -} - -} -} diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h deleted file mode 100644 index f499f4a27c..0000000000 --- a/libs/openengine/bullet/trace.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef OENGINE_BULLET_TRACE_H -#define OENGINE_BULLET_TRACE_H - -#include - - -class btCollisionObject; - - -namespace OEngine -{ -namespace Physic -{ - class PhysicEngine; - class PhysicActor; - - struct ActorTracer - { - Ogre::Vector3 mEndPos; - Ogre::Vector3 mPlaneNormal; - const btCollisionObject* mHitObject; - - float mFraction; - - void doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, - const PhysicEngine *enginePass); - void findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, - const PhysicEngine *enginePass); - }; -} -} - -#endif From fe15f31f3e415c2a427bc43bce8bedf4558e6f97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 00:36:04 +0200 Subject: [PATCH 0231/1812] Remove strings.h wrapper --- CMakeLists.txt | 2 +- apps/bsatool/bsatool.cpp | 1 + components/bsa/bsa_file.hpp | 5 ++--- components/vfs/registerarchives.cpp | 3 +++ libs/platform/strings.h | 18 ------------------ 5 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 libs/platform/strings.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa9cb8219..fae7ff6836 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) -include_directories("." ${LIBS_DIR} +include_directories("." SYSTEM ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 2ea736db72..7f305052b1 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 8a7576f923..8ed63f35da 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -25,12 +25,11 @@ #define BSA_BSA_FILE_H #include -#include #include #include #include -#include +#include #include @@ -74,7 +73,7 @@ private: struct iltstr { bool operator()(const char *s1, const char *s2) const - { return strcasecmp(s1,s2) < 0; } + { return Misc::StringUtils::ciLess(s1, s2); } }; /** A map used for fast file name lookup. The value is the index into diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index 69d4498bb5..aeda3191d1 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -1,5 +1,8 @@ #include "registerarchives.hpp" +#include +#include + #include #include #include diff --git a/libs/platform/strings.h b/libs/platform/strings.h deleted file mode 100644 index c0fbb1a1b2..0000000000 --- a/libs/platform/strings.h +++ /dev/null @@ -1,18 +0,0 @@ -// Wrapper for MSVC/GCC -#ifndef _STRINGS_WRAPPER_H -#define _STRINGS_WRAPPER_H - - -// For GCC, just use strings.h (this applies to mingw too) -#if defined(__GNUC__) -# include -#elif defined(MSVC) || defined(_MSC_VER) -# pragma warning(disable: 4996) -# define strcasecmp stricmp -# define snprintf _snprintf -#else -# warning "Unable to determine your compiler, you should probably take a look here." -# include // Just take a guess -#endif - -#endif /* _STRINGS_WRAPPER_H */ From c31b416ba127044f7de60ec81b4064d42398ea20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 01:09:00 +0200 Subject: [PATCH 0232/1812] Move physicssystem to a new mwphysics module --- apps/opencs/CMakeLists.txt | 1 - apps/opencs/view/render/object.hpp | 5 ---- apps/openmw/CMakeLists.txt | 5 +++- apps/openmw/mwclass/activator.cpp | 5 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 4 +-- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 4 +-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 +-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 +-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 4 +-- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 4 +-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 4 +-- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 4 +-- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 4 +-- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 4 +-- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 +-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 +-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 +-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/static.cpp | 4 +-- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 +-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 8 ------ .../{mwworld => mwphysics}/physicssystem.cpp | 28 +++++++++---------- .../{mwworld => mwphysics}/physicssystem.hpp | 18 +++--------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 8 ++++-- apps/openmw/mwworld/scene.cpp | 17 +++++------ apps/openmw/mwworld/scene.hpp | 10 +++++-- apps/openmw/mwworld/worldimp.cpp | 4 +-- apps/openmw/mwworld/worldimp.hpp | 12 +------- components/CMakeLists.txt | 1 - 49 files changed, 102 insertions(+), 126 deletions(-) rename apps/openmw/{mwworld => mwphysics}/physicssystem.cpp (97%) rename apps/openmw/{mwworld => mwphysics}/physicssystem.hpp (93%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d7aafcf30e..5a74fa48f7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -199,7 +199,6 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index d18a199ff2..9f411ffc6d 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -27,11 +27,6 @@ namespace CSMWorld struct CellRef; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Object diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e1de2a5563..bcfc24053b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,6 +73,10 @@ add_openmw_dir (mwworld # projectilemanager ) +add_openmw_dir (mwphysics + physicssystem + ) + add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door ingredient creaturelevlist itemlevlist light lockpick misc probe repair static @@ -127,7 +131,6 @@ endif () include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw - ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 2621f5e522..4cf33ceb85 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -11,11 +11,12 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/physicssystem.hpp" #include "../mwworld/action.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -38,7 +39,7 @@ namespace MWClass } } - void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index e79318a55e..646bb79bb2 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -19,7 +19,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2abd071bd0..55209764a1 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -11,7 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" @@ -33,7 +33,7 @@ namespace MWClass } } - void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 2ab0a47e3b..94e998e488 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -21,7 +21,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 686f5af619..ec3658b3d9 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -15,7 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" @@ -38,7 +38,7 @@ namespace MWClass } } - void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 21d711a0d3..ec32908783 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index a9c96e7c7d..e71dd6769a 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -12,7 +12,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -35,7 +35,7 @@ namespace MWClass } } - void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 05ff88bb2e..8dcae731a2 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index b387a3e9f1..39025227cb 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -13,7 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -35,7 +35,7 @@ namespace MWClass } } - void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 5700543481..adb3491580 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index ac23744e8f..862ae6c5d9 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -18,7 +18,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/actionopen.hpp" #include "../mwworld/actiontrap.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwgui/tooltips.hpp" @@ -97,7 +97,7 @@ namespace MWClass } } - void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 52873374e4..3268d45d13 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -21,7 +21,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a85c648f45..7d4fcf5d60 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -25,7 +25,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/renderinginterface.hpp" @@ -169,7 +169,7 @@ namespace MWClass objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } - void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5585835fd2..7a50968bf8 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,7 +47,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f46ede730d..36f7b021c6 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -17,7 +17,7 @@ #include "../mwworld/actiondoor.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actiontrap.hpp" #include "../mwworld/customdata.hpp" @@ -56,7 +56,7 @@ namespace MWClass } } - void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index c5f258d3e0..9cfb465098 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -22,7 +22,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index de43e818e9..9b35b85304 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -11,7 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/actioneat.hpp" #include "../mwworld/nullaction.hpp" @@ -39,7 +39,7 @@ namespace MWClass } } - void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index a4681f4621..69dd70743f 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 2cf31d996d..7ea5ae1be3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -17,7 +17,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" @@ -41,7 +41,7 @@ namespace MWClass renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } - void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 8658375b77..6161f18997 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 478c50301d..e1e774755e 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -12,7 +12,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -34,7 +34,7 @@ namespace MWClass } } - void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 293a40be11..3f2c004f8f 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index f5daafeec2..df28daee91 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -13,7 +13,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionsoulgem.hpp" @@ -51,7 +51,7 @@ namespace MWClass } } - void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 23160d41c6..66699f9df7 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 8be551dd22..6f969146b4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -32,7 +32,7 @@ #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/objects.hpp" @@ -412,7 +412,7 @@ namespace MWClass renderingInterface.getObjects().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { physics.addActor(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b745463956..e0ebbec2b2 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index ee299ab4f8..98bb703cbc 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -13,7 +13,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -37,7 +37,7 @@ namespace MWClass } } - void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 32e3901156..091d291953 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index da22e9be6c..fb96bff5ad 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -12,7 +12,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -34,7 +34,7 @@ namespace MWClass } } - void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index bb90ac1531..e39e43c270 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index c02146f122..9ddc36ff90 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -10,7 +10,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionrepair.hpp" @@ -33,7 +33,7 @@ namespace MWClass } } - void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 2589a4af35..295b9d4f15 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 834ce129e3..6438046ded 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -4,7 +4,7 @@ #include #include "../mwworld/ptr.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/cellstore.hpp" #include "../mwrender/objects.hpp" @@ -24,7 +24,7 @@ namespace MWClass } } - void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model); diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index a94dff394d..3d78f949bc 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a484ad6683..bbe81f370e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -13,7 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -37,7 +37,7 @@ namespace MWClass } } - void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const + void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) physics.addObject(ptr, model, true); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 47f1c52514..47c1157a02 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -18,7 +18,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 26a1fcb21e..cd80ed460b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -9,14 +9,6 @@ #include "../mwbase/inputmanager.hpp" #include -namespace OEngine -{ - namespace Render - { - class OgreRenderer; - } -} - namespace MWWorld { class Player; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp similarity index 97% rename from apps/openmw/mwworld/physicssystem.cpp rename to apps/openmw/mwphysics/physicssystem.cpp index 7c1a44e486..f57a8fbff4 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -24,8 +24,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "ptr.hpp" -#include "class.hpp" +#include "../mwworld/class.hpp" namespace { @@ -78,7 +77,7 @@ void animateCollisionShapes (std::map& collisionTracker , std::map& standingCollisionTracker) { @@ -584,7 +582,7 @@ namespace MWWorld */ } - std::vector PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask) + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) { return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } @@ -604,12 +602,12 @@ namespace MWWorld { } - void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) { } - void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) + void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { } @@ -642,7 +640,7 @@ namespace MWWorld return false; } - void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) + void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -736,7 +734,7 @@ namespace MWWorld mDebugDrawer->step(); } - bool PhysicsSystem::isActorStandingOn(const Ptr &actor, const Ptr &object) const + bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -750,7 +748,7 @@ namespace MWWorld return false; } - void PhysicsSystem::getActorsStandingOn(const Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { const std::string& objectHandle = object.getRefData().getHandle(); @@ -762,7 +760,7 @@ namespace MWWorld } } - bool PhysicsSystem::isActorCollidingWith(const Ptr &actor, const Ptr &object) const + bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -776,7 +774,7 @@ namespace MWWorld return false; } - void PhysicsSystem::getActorsCollidingWith(const Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { const std::string& objectHandle = object.getRefData().getHandle(); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp similarity index 93% rename from apps/openmw/mwworld/physicssystem.hpp rename to apps/openmw/mwphysics/physicssystem.hpp index 018ea0a28e..e04ac1b518 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -9,31 +9,21 @@ #include -#include "ptr.hpp" +#include "../mwworld/ptr.hpp" namespace osg { class Group; } -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - namespace MWRender { class DebugDrawer; } -namespace MWWorld +namespace MWPhysics { - class World; - - typedef std::vector > PtrVelocityList; + typedef std::vector > PtrVelocityList; class PhysicsSystem { @@ -75,7 +65,7 @@ namespace MWWorld /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. - void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); + void queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity); /// Apply all queued movements, then clear the list. const PtrVelocityList& applyQueuedMovement(float dt); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 79444e1109..0ab18699dd 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -43,7 +43,7 @@ namespace MWWorld } - void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const + void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f65af05c2..15058294f3 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -24,6 +24,11 @@ namespace MWRender class RenderingInterface; } +namespace MWPhysics +{ + class PhysicsSystem; +} + namespace MWMechanics { class CreatureStats; @@ -45,7 +50,6 @@ namespace MWWorld { class ContainerStore; class InventoryStore; - class PhysicsSystem; class CellStore; class Action; @@ -84,7 +88,7 @@ namespace MWWorld /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; - virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). virtual std::string getName (const Ptr& ptr) const = 0; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ccbc6b555..0e17dad749 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -18,7 +18,8 @@ #include "../mwrender/renderingmanager.hpp" -#include "physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" @@ -29,7 +30,7 @@ namespace { - void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); @@ -40,7 +41,7 @@ namespace ptr.getClass().insertObject (ptr, model, physics); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -63,7 +64,7 @@ namespace } } - void updateObjectScale(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + void updateObjectScale(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { if (ptr.getRefData().getBaseNode() != NULL) @@ -80,17 +81,17 @@ namespace MWWorld::CellStore& mCell; bool mRescale; Loading::Listener& mLoadingListener; - MWWorld::PhysicsSystem& mPhysics; + MWPhysics::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, - MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering); + MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, - Loading::Listener& loadingListener, MWWorld::PhysicsSystem& physics, + Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), mPhysics (physics), @@ -436,7 +437,7 @@ namespace MWWorld } //We need the ogre renderer and a scene node. - Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) + Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index f7ef9b2764..24ffdf07b9 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -39,9 +39,13 @@ namespace MWRender class RenderingManager; } -namespace MWWorld +namespace MWPhysics { class PhysicsSystem; +} + +namespace MWWorld +{ class Player; class CellStore; @@ -56,7 +60,7 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; - PhysicsSystem *mPhysics; + MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; bool mNeedMapUpdate; @@ -70,7 +74,7 @@ namespace MWWorld public: - Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics); + Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics); ~Scene(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7047978ff5..72423f4765 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -51,7 +51,7 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" -#include "physicssystem.hpp" +#include "../mwphysics/physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -156,7 +156,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new PhysicsSystem(rootNode); + mPhysics = new MWPhysics::PhysicsSystem(rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index cb58f04969..efb9b88c6f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -21,14 +21,6 @@ #include -namespace OEngine -{ -namespace Physic -{ - class PhysicEngine; -} -} - namespace osg { class Group; @@ -89,15 +81,13 @@ namespace MWWorld MWWorld::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals mGlobalVariables; - MWWorld::PhysicsSystem *mPhysics; + MWPhysics::PhysicsSystem *mPhysics; bool mSky; Cells mCells; std::string mCurrentWorldSpace; - OEngine::Physic::PhysicEngine* mPhysEngine; - boost::shared_ptr mProjectileManager; bool mGodMode; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 931d84e26c..417164f2db 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -170,7 +170,6 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} - ${OENGINE_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES} # For MyGUI platform ${OPENGL_gl_LIBRARY} From 54c1f19c183350c2b55965ff0f197db52c7559ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 10 May 2015 02:08:25 +0200 Subject: [PATCH 0233/1812] Readded height fields --- apps/openmw/mwphysics/physicssystem.cpp | 132 ++++++++++++++++++++---- apps/openmw/mwphysics/physicssystem.hpp | 26 ++++- apps/openmw/mwworld/scene.cpp | 10 +- 3 files changed, 137 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f57a8fbff4..8ae4fc853b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include @@ -187,7 +189,7 @@ namespace MWPhysics if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors - if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) + if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) return false; // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing @@ -246,7 +248,7 @@ namespace MWPhysics btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; - resultCallback1.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; engine->mDynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && @@ -437,14 +439,14 @@ namespace MWPhysics Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f)); tracer.doTrace(colobj, from, to, engine); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope - && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != OEngine::Physic::CollisionType_Actor) + && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } - if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Water) + if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); if (!isFlying) @@ -457,7 +459,7 @@ namespace MWPhysics // standing on actors is not allowed (see above). // in addition to that, apply a sliding effect away from the center of the actor, // so that we do not stay suspended in air indefinitely. - if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) + if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) { if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) { @@ -492,15 +494,94 @@ namespace MWPhysics }; - PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) : - mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode) + // --------------------------------------------------------------- + + class HeightField { + public: + HeightField(float* heights, int x, int y, float triSize, float sqrtVerts) + { + // find the minimum and maximum heights (needed for bullet) + float minh = heights[0]; + float maxh = heights[0]; + for(int i = 1;i < sqrtVerts*sqrtVerts;++i) + { + float h = heights[i]; + if(h > maxh) maxh = h; + if(h < minh) minh = h; + } + + mShape = new btHeightfieldTerrainShape( + sqrtVerts, sqrtVerts, heights, 1, + minh, maxh, 2, + PHY_FLOAT, true + ); + mShape->setUseDiamondSubdivision(true); + mShape->setLocalScaling(btVector3(triSize, triSize, 1)); + + btTransform transform(btQuaternion::getIdentity(), + btVector3((x+0.5f) * triSize * (sqrtVerts-1), + (y+0.5f) * triSize * (sqrtVerts-1), + (maxh+minh)*0.5f)); + + mCollisionObject = new btCollisionObject; + mCollisionObject->setCollisionShape(mShape); + mCollisionObject->setWorldTransform(transform); + } + ~HeightField() + { + delete mCollisionObject; + delete mShape; + } + btCollisionObject* getCollisionObject() + { + return mCollisionObject; + } + + private: + btHeightfieldTerrainShape* mShape; + btCollisionObject* mCollisionObject; + }; + + // --------------------------------------------------------------- + + + PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) + : mTimeAccum(0.0f) + , mWaterEnabled(false) + , mWaterHeight(0) + , mDebugDrawEnabled(false) + , mParentNode(parentNode) + { + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); + mSolver = new btSequentialImpulseConstraintSolver; + mBroadphase = new btDbvtBroadphase(); + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); + + // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. + // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. + mDynamicsWorld->setForceUpdateAllAabbs(false); + + mDynamicsWorld->setGravity(btVector3(0,0,-10)); } PhysicsSystem::~PhysicsSystem() { - //if (mWaterCollisionObject.get()) - // mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + if (mWaterCollisionObject.get()) + mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + + for (HeightFieldMap::iterator it = mHeightFields.begin(); it != mHeightFields.end(); ++it) + { + mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + delete it->second; + } + + delete mDynamicsWorld; + delete mSolver; + delete mCollisionConfiguration; + delete mDispatcher; + delete mBroadphase; } bool PhysicsSystem::toggleDebugRendering() @@ -509,9 +590,9 @@ namespace MWPhysics if (mDebugDrawEnabled && !mDebugDrawer.get()) { - //mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld)); - //mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); - //mDebugDrawer->setDebugMode(mDebugDrawEnabled); + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mDynamicsWorld)); + mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) mDebugDrawer->setDebugMode(mDebugDrawEnabled); @@ -592,14 +673,24 @@ namespace MWPhysics return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); } - void PhysicsSystem::addHeightField (float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) { + HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); + mHeightFields[std::make_pair(x,y)] = heightfield; + + mDynamicsWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, + CollisionType_Actor|CollisionType_Projectile); } void PhysicsSystem::removeHeightField (int x, int y) { + HeightFieldMap::iterator heightfield = mHeightFields.find(std::make_pair(x,y)); + if(heightfield != mHeightFields.end()) + { + mDynamicsWorld->removeCollisionObject(heightfield->second->getCollisionObject()); + delete heightfield->second; + mHeightFields.erase(heightfield); + } } void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) @@ -726,9 +817,10 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - //animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld); + //animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); - //mEngine->stepSimulation(dt); + // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. + mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -818,7 +910,7 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - //mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -827,7 +919,7 @@ namespace MWPhysics mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - //mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water, - // OEngine::Physic::CollisionType_Actor); + mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, + CollisionType_Actor); } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index e04ac1b518..4dbecdb7c6 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -21,10 +21,23 @@ namespace MWRender class DebugDrawer; } +class btSequentialImpulseConstraintSolver; +class btDiscreteDynamicsWorld; + namespace MWPhysics { typedef std::vector > PtrVelocityList; + enum CollisionType { + CollisionType_World = 1<<0, + CollisionType_Actor = 1<<1, + CollisionType_HeightMap = 1<<2, + CollisionType_Projectile = 1<<4, + CollisionType_Water = 1<<5 + }; + + class HeightField; + class PhysicsSystem { public: @@ -39,9 +52,7 @@ namespace MWPhysics void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); - void addHeightField (float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts); + void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); void removeHeightField (int x, int y); @@ -94,6 +105,15 @@ namespace MWPhysics void updateWater(); + btBroadphaseInterface* mBroadphase; + btDefaultCollisionConfiguration* mCollisionConfiguration; + btSequentialImpulseConstraintSolver* mSolver; + btCollisionDispatcher* mDispatcher; + btDiscreteDynamicsWorld* mDynamicsWorld; + + typedef std::map, HeightField*> HeightFieldMap; + HeightFieldMap mHeightFields; + bool mDebugDrawEnabled; std::map handleToMesh; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0e17dad749..6a994f0cdb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -246,14 +246,8 @@ namespace MWWorld const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; if (!land->isDataLoaded(flags)) land->loadData(flags); - mPhysics->addHeightField ( - land->mLandData->mHeights, - cell->getCell()->getGridX(), - cell->getCell()->getGridY(), - 0, - worldsize / (verts-1), - verts) - ; + mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + worldsize / (verts-1), verts); } } From 47758c11cd1096c7060c2dbe0310eb2c6e53e4f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 03:02:15 +0200 Subject: [PATCH 0234/1812] Readded collision objects and movement physics --- apps/opencs/CMakeLists.txt | 3 +- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 5 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 73 ++-- apps/openmw/mwmechanics/movement.hpp | 7 + apps/openmw/mwphysics/actor.cpp | 152 +++++++ apps/openmw/mwphysics/actor.hpp | 125 ++++++ apps/openmw/mwphysics/collisiontype.hpp | 17 + apps/openmw/mwphysics/convert.hpp | 35 ++ apps/openmw/mwphysics/physicssystem.cpp | 420 +++++++++++++------- apps/openmw/mwphysics/physicssystem.hpp | 56 ++- apps/openmw/mwphysics/trace.cpp | 128 ++++++ apps/openmw/mwphysics/trace.h | 27 ++ apps/openmw/mwscript/aiextensions.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 4 +- apps/openmw/mwworld/cellfunctors.hpp | 18 +- apps/openmw/mwworld/scene.cpp | 24 +- apps/openmw/mwworld/weather.cpp | 8 +- apps/openmw/mwworld/weather.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 46 +-- apps/openmw/mwworld/worldimp.hpp | 4 +- components/CMakeLists.txt | 7 +- components/nifbullet/bulletnifloader.cpp | 306 ++++++++------ components/nifbullet/bulletnifloader.hpp | 113 +++--- components/nifbullet/bulletshapemanager.cpp | 47 +++ components/nifbullet/bulletshapemanager.hpp | 37 ++ 38 files changed, 1238 insertions(+), 473 deletions(-) create mode 100644 apps/openmw/mwphysics/actor.cpp create mode 100644 apps/openmw/mwphysics/actor.hpp create mode 100644 apps/openmw/mwphysics/collisiontype.hpp create mode 100644 apps/openmw/mwphysics/convert.hpp create mode 100644 apps/openmw/mwphysics/trace.cpp create mode 100644 apps/openmw/mwphysics/trace.h create mode 100644 components/nifbullet/bulletshapemanager.cpp create mode 100644 components/nifbullet/bulletshapemanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5a74fa48f7..1b71cf0ed5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -151,7 +151,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -set(BOOST_COMPONENTS system filesystem program_options thread wave) +set(BOOST_COMPONENTS system filesystem program_options thread) if(WIN32) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) endif(WIN32) @@ -202,7 +202,6 @@ target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} - ${BULLET_LIBRARIES} ${QT_LIBRARIES} components ) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bcfc24053b..95875de10b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwworld ) add_openmw_dir (mwphysics - physicssystem + physicssystem trace collisiontype actor convert ) add_openmw_dir (mwclass @@ -101,9 +101,9 @@ add_openmw_dir (mwbase # Main executable if (ANDROID) - set(BOOST_COMPONENTS system filesystem program_options thread wave atomic) + set(BOOST_COMPONENTS system filesystem program_options thread atomic) else () - set(BOOST_COMPONENTS system filesystem program_options thread wave) + set(BOOST_COMPONENTS system filesystem program_options thread) endif () if(WIN32) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4ccbfc784c..7cc0a6e5ee 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -302,7 +302,7 @@ namespace MWBase virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; ///< Convert position to cell numbers - virtual void queueMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity) = 0; + virtual void queueMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) = 0; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. @@ -555,7 +555,7 @@ namespace MWBase virtual bool isInStorm() const = 0; /// @see MWWorld::WeatherManager::getStormDirection - virtual Ogre::Vector3 getStormDirection() const = 0; + virtual osg::Vec3f getStormDirection() const = 0; /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors() = 0; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 55209764a1..6f11a36c79 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -35,8 +35,7 @@ namespace MWClass void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index ec3658b3d9..04c98e437f 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -40,8 +40,7 @@ namespace MWClass void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index e71dd6769a..2c20435b2f 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -37,8 +37,7 @@ namespace MWClass void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 39025227cb..8964b65e04 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -37,8 +37,7 @@ namespace MWClass void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9b35b85304..fb409cb55b 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -41,8 +41,7 @@ namespace MWClass void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7ea5ae1be3..4d0c0cba99 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -47,8 +47,9 @@ namespace MWClass ptr.get(); assert (ref->mBase != NULL); - if(!model.empty()) - physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0); + // TODO: add option somewhere to enable collision for placeable objects + if ((ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) + physics.addObject(ptr, model); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index e1e774755e..8f22c3fa13 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -36,8 +36,7 @@ namespace MWClass void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index df28daee91..b7c39b50a7 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -53,8 +53,7 @@ namespace MWClass void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 98bb703cbc..647f83f676 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -39,8 +39,7 @@ namespace MWClass void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index fb96bff5ad..cb43ccce6a 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -36,8 +36,7 @@ namespace MWClass void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 9ddc36ff90..0bc64a99e1 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -35,8 +35,7 @@ namespace MWClass void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index bbe81f370e..8c3d7fb10e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -39,8 +39,7 @@ namespace MWClass void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { - if(!model.empty()) - physics.addObject(ptr, model, true); + // TODO: add option somewhere to enable collision for placeable objects } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index adcfb57a47..5769138fad 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1346,7 +1346,7 @@ void CharacterController::update(float duration) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = mPtr.getClass(); - Ogre::Vector3 movement(0.0f); + osg::Vec3f movement(0.f, 0.f, 0.f); updateMagicEffects(); @@ -1403,23 +1403,23 @@ void CharacterController::update(float duration) } } - Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); - vec.normalise(); + osg::Vec3f vec(cls.getMovementSettings(mPtr).asVec3()); + vec.normalize(); if(mHitState != CharState_None && mJumpState == JumpState_None) - vec = Ogre::Vector3(0.0f); + vec = osg::Vec3f(0.f, 0.f, 0.f); Ogre::Vector3 rot = cls.getRotationVector(mPtr); mMovementSpeed = cls.getSpeed(mPtr); - vec.x *= mMovementSpeed; - vec.y *= mMovementSpeed; + vec.x() *= mMovementSpeed; + vec.y() *= mMovementSpeed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; bool forcestateupdate = false; - mHasMovedInXY = std::abs(vec[0])+std::abs(vec[1]) > 0.0f; + mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; isrunning = isrunning && mHasMovedInXY; @@ -1482,7 +1482,7 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).setFatigue(fatigue); if(sneak || inwater || flying) - vec.z = 0.0f; + vec.z() = 0.0f; if (inwater || flying) cls.getCreatureStats(mPtr).land(); @@ -1505,22 +1505,23 @@ void CharacterController::update(float duration) static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f; factor = std::min(1.f, factor); - vec.x *= factor; - vec.y *= factor; - vec.z = 0.0f; + vec.x() *= factor; + vec.y() *= factor; + vec.z() = 0.0f; } - else if(vec.z > 0.0f && mJumpState == JumpState_None) + else if(vec.z() > 0.0f && mJumpState == JumpState_None) { // Started a jump. float z = cls.getJump(mPtr); if (z > 0) { - if(vec.x == 0 && vec.y == 0) - vec = Ogre::Vector3(0.0f, 0.0f, z); + if(vec.x() == 0 && vec.y() == 0) + vec = osg::Vec3f(0.0f, 0.0f, z); else { - Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); - vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + osg::Vec3f lat (vec.x(), vec.y(), 0.0f); + lat.normalize(); + vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f; } // advance acrobatics @@ -1544,7 +1545,7 @@ void CharacterController::update(float duration) { forcestateupdate = true; mJumpState = JumpState_Landing; - vec.z = 0.0f; + vec.z() = 0.0f; float height = cls.getCreatureStats(mPtr).land(); float healthLost = getFallDamage(mPtr, height); @@ -1575,28 +1576,28 @@ void CharacterController::update(float duration) else { mJumpState = JumpState_None; - vec.z = 0.0f; + vec.z() = 0.0f; inJump = false; - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) { - if(vec.x > 0.0f) + if(vec.x() > 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight))); - else if(vec.x < 0.0f) + else if(vec.x() < 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft))); } - else if(vec.y != 0.0f) + else if(vec.y() != 0.0f) { - if(vec.y > 0.0f) + if(vec.y() > 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward))); - else if(vec.y < 0.0f) + else if(vec.y() < 0.0f) movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); @@ -1676,7 +1677,7 @@ void CharacterController::update(float duration) } else // We must always queue movement, even if there is none, to apply gravity. - world->queueMovement(mPtr, Ogre::Vector3(0.0f)); + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); movement = vec; cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0; @@ -1688,7 +1689,7 @@ void CharacterController::update(float duration) } else if(cls.getCreatureStats(mPtr).isDead()) { - world->queueMovement(mPtr, Ogre::Vector3(0.0f)); + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration); @@ -1702,15 +1703,15 @@ void CharacterController::update(float duration) { float l = moved.length(); - if((movement.x < 0.0f && movement.x < moved.x()*2.0f) || - (movement.x > 0.0f && movement.x > moved.x()*2.0f)) - moved.x() = movement.x; - if((movement.y < 0.0f && movement.y < moved.y()*2.0f) || - (movement.y > 0.0f && movement.y > moved.y()*2.0f)) - moved.y() = movement.y; - if((movement.z < 0.0f && movement.z < moved.z()*2.0f) || - (movement.z > 0.0f && movement.z > moved.z()*2.0f)) - moved.z() = movement.z; + if((movement.x() < 0.0f && movement.x() < moved.x()*2.0f) || + (movement.x() > 0.0f && movement.x() > moved.x()*2.0f)) + moved.x() = movement.x(); + if((movement.y() < 0.0f && movement.y() < moved.y()*2.0f) || + (movement.y() > 0.0f && movement.y() > moved.y()*2.0f)) + moved.y() = movement.y(); + if((movement.z() < 0.0f && movement.z() < moved.z()*2.0f) || + (movement.z() > 0.0f && movement.z() > moved.z()*2.0f)) + moved.z() = movement.z(); // but keep the original speed float newLength = moved.length(); if (newLength > 0) @@ -1722,7 +1723,7 @@ void CharacterController::update(float duration) // Update movement if(mMovementAnimationControlled && mPtr.getClass().isActor()) - world->queueMovement(mPtr, Ogre::Vector3(moved.x(), moved.y(), moved.z())); + world->queueMovement(mPtr, moved); mSkipAnim = false; diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 6c9a4b7589..c12b615388 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_MOVEMENT_H #define GAME_MWMECHANICS_MOVEMENT_H +#include + namespace MWMechanics { /// Desired movement for an actor @@ -14,6 +16,11 @@ namespace MWMechanics mPosition[0] = mPosition[1] = mPosition[2] = 0.0f; mRotation[0] = mRotation[1] = mRotation[2] = 0.0f; } + + osg::Vec3f asVec3() + { + return osg::Vec3f(mPosition[0], mPosition[1], mPosition[2]); + } }; } diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp new file mode 100644 index 0000000000..edad7e196b --- /dev/null +++ b/apps/openmw/mwphysics/actor.cpp @@ -0,0 +1,152 @@ +#include "actor.hpp" +#include + +#include + +#include + +#include "../mwworld/class.hpp" + +#include + +#include "convert.hpp" +#include "collisiontype.hpp" + +namespace MWPhysics +{ + + +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world) + : mCanWaterWalk(false), mWalkingOnWater(false) + , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) + , mInternalCollisionMode(true) + , mExternalCollisionMode(true) + , mDynamicsWorld(world) +{ + mPtr = ptr; + + mHalfExtents = shape->mCollisionBoxHalfExtents; + mMeshTranslation = shape->mCollisionBoxTranslate; + + // Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it) + if (std::abs(mHalfExtents.x()-mHalfExtents.y())= mHalfExtents.x()) + { + // Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work) + mShape.reset(new btCylinderShapeZ(toBullet(mHalfExtents))); + } + else + mShape.reset(new btBoxShape(toBullet(mHalfExtents))); + + mCollisionObject.reset(new btCollisionObject); + mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + mCollisionObject->setActivationState(DISABLE_DEACTIVATION); + mCollisionObject->setCollisionShape(mShape.get()); + mCollisionObject->setUserPointer(static_cast(this)); + + updateRotation(); + updateScale(); + // already called by updateScale() + //updatePosition(); + + updateCollisionMask(); +} + +Actor::~Actor() +{ + if (mCollisionObject.get()) + mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); +} + +void Actor::enableCollisionMode(bool collision) +{ + mInternalCollisionMode = collision; +} + +void Actor::enableCollisionBody(bool collision) +{ + if (mExternalCollisionMode != collision) + { + mExternalCollisionMode = collision; + updateCollisionMask(); + } +} + +void Actor::updateCollisionMask() +{ + mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); + int collisionMask = CollisionType_World | CollisionType_HeightMap; + if (mExternalCollisionMode) + collisionMask |= CollisionType_Actor | CollisionType_Projectile; + if (mCanWaterWalk) + collisionMask |= CollisionType_Water; + mDynamicsWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); +} + +void Actor::updatePosition() +{ + osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); + + btTransform tr = mCollisionObject->getWorldTransform(); + osg::Vec3f scaledTranslation = osg::componentMultiply(mMeshTranslation, mScale); + osg::Vec3f newPosition = scaledTranslation + position; + + tr.setOrigin(toBullet(newPosition)); + mCollisionObject->setWorldTransform(tr); +} + +void Actor::updateRotation () +{ + btTransform tr = mCollisionObject->getWorldTransform(); + tr.setRotation(toBullet(mPtr.getRefData().getBaseNode()->getAttitude())); + mCollisionObject->setWorldTransform(tr); +} + +void Actor::updateScale() +{ + float scale = mPtr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale,scale,scale); + + if (!mPtr.getClass().isNpc()) + mPtr.getClass().adjustScale(mPtr, scaleVec); + + mScale = scaleVec; + mShape->setLocalScaling(toBullet(mScale)); + + updatePosition(); +} + +osg::Vec3f Actor::getHalfExtents() const +{ + return osg::componentMultiply(mHalfExtents, mScale); +} + +void Actor::setInertialForce(const osg::Vec3f &force) +{ + mForce = force; +} + +void Actor::setOnGround(bool grounded) +{ + mOnGround = grounded; +} + +bool Actor::isWalkingOnWater() const +{ + return mWalkingOnWater; +} + +void Actor::setWalkingOnWater(bool walkingOnWater) +{ + mWalkingOnWater = walkingOnWater; +} + +void Actor::setCanWaterWalk(bool waterWalk) +{ + if (waterWalk != mCanWaterWalk) + { + mCanWaterWalk = waterWalk; + updateCollisionMask(); + } +} + +} diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp new file mode 100644 index 0000000000..ec1d81fd9d --- /dev/null +++ b/apps/openmw/mwphysics/actor.hpp @@ -0,0 +1,125 @@ +#ifndef OPENMW_MWPHYSICS_ACTOR_H +#define OPENMW_MWPHYSICS_ACTOR_H + +#include + +#include "../mwworld/ptr.hpp" + +#include +#include + +class btDynamicsWorld; +class btCollisionShape; +class btCollisionObject; + +namespace NifBullet +{ + class BulletShapeInstance; +} + +namespace MWPhysics +{ + + class PtrHolder + { + public: + virtual ~PtrHolder() {} + + protected: + MWWorld::Ptr mPtr; + }; + + class Actor : public PtrHolder + { + public: + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world); + ~Actor(); + + /** + * Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry. + */ + void enableCollisionMode(bool collision); + + bool getCollisionMode() const + { + return mInternalCollisionMode; + } + + /** + * Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor. + */ + void enableCollisionBody(bool collision); + + void updateScale(); + void updateRotation(); + void updatePosition(); + + /** + * Returns the (scaled) half extents + */ + osg::Vec3f getHalfExtents() const; + + /** + * Sets the current amount of inertial force (incl. gravity) affecting this physic actor + */ + void setInertialForce(const osg::Vec3f &force); + + /** + * Gets the current amount of inertial force (incl. gravity) affecting this physic actor + */ + const osg::Vec3f &getInertialForce() const + { + return mForce; + } + + void setOnGround(bool grounded); + + bool getOnGround() const + { + return mInternalCollisionMode && mOnGround; + } + + btCollisionObject* getCollisionObject() const + { + return mCollisionObject.get(); + } + + /// Sets whether this actor should be able to collide with the water surface + void setCanWaterWalk(bool waterWalk); + + /// Sets whether this actor has been walking on the water surface in the last frame + void setWalkingOnWater(bool walkingOnWater); + bool isWalkingOnWater() const; + + private: + /// Removes then re-adds the collision object to the dynamics world + void updateCollisionMask(); + + bool mCanWaterWalk; + bool mWalkingOnWater; + + std::auto_ptr mShape; + + std::auto_ptr mCollisionObject; + + osg::Vec3f mMeshTranslation; + osg::Vec3f mHalfExtents; + + osg::Vec3f mScale; + osg::Vec3f mPosition; + + osg::Vec3f mForce; + bool mOnGround; + bool mInternalCollisionMode; + bool mExternalCollisionMode; + + btDynamicsWorld* mDynamicsWorld; + + Actor(const Actor&); + Actor& operator=(const Actor&); + }; + +} + + +#endif diff --git a/apps/openmw/mwphysics/collisiontype.hpp b/apps/openmw/mwphysics/collisiontype.hpp new file mode 100644 index 0000000000..0f083ab352 --- /dev/null +++ b/apps/openmw/mwphysics/collisiontype.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_MWPHYSICS_COLLISIONTYPE_H +#define OPENMW_MWPHYSICS_COLLISIONTYPE_H + +namespace MWPhysics +{ + +enum CollisionType { + CollisionType_World = 1<<0, + CollisionType_Actor = 1<<1, + CollisionType_HeightMap = 1<<2, + CollisionType_Projectile = 1<<4, + CollisionType_Water = 1<<5 +}; + +} + +#endif diff --git a/apps/openmw/mwphysics/convert.hpp b/apps/openmw/mwphysics/convert.hpp new file mode 100644 index 0000000000..c5075a2c33 --- /dev/null +++ b/apps/openmw/mwphysics/convert.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_MWPHYSICS_CONVERT_H +#define OPENMW_MWPHYSICS_CONVERT_H + +#include +#include + +#include +#include + +namespace MWPhysics +{ + + inline btVector3 toBullet(const osg::Vec3f& vec) + { + return btVector3(vec.x(), vec.y(), vec.z()); + } + + inline btQuaternion toBullet(const osg::Quat& quat) + { + return btQuaternion(quat.x(), quat.y(), quat.z(), quat.w()); + } + + inline osg::Vec3f toOsg(const btVector3& vec) + { + return osg::Vec3f(vec.x(), vec.y(), vec.z()); + } + + inline osg::Quat toOsg(const btQuaternion& quat) + { + return osg::Quat(quat.x(), quat.y(), quat.z(), quat.w()); + } + +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8ae4fc853b..6d429f3e54 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -3,15 +3,17 @@ #include #include +#include #include +#include #include #include #include -#include "../mwbase/world.hpp" // FIXME +#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -28,6 +30,11 @@ #include "../mwworld/class.hpp" +#include "collisiontype.hpp" +#include "actor.hpp" +#include "convert.hpp" +#include "trace.h" + namespace { @@ -89,16 +96,17 @@ namespace MWPhysics // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; + // FIXME: move to a separate file class MovementSolver { private: - static float getSlope(const Ogre::Vector3 &normal) + static float getSlope(const osg::Vec3f &normal) { - return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); + return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } - static bool stepMove(btCollisionObject *colobj, Ogre::Vector3 &position, - const Ogre::Vector3 &toMove, float &remainingTime /*, OEngine::Physic::PhysicEngine *engine*/) + static bool stepMove(btCollisionObject *colobj, osg::Vec3f &position, + const osg::Vec3f &toMove, float &remainingTime, btDynamicsWorld* dynamicsWorld) { /* * Slide up an incline or set of stairs. Should be called only after a @@ -144,11 +152,9 @@ namespace MWPhysics * +--+ +-------- * ============================================== */ - return false; -#if 0 - OEngine::Physic::ActorTracer tracer, stepper; + ActorTracer tracer, stepper; - stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine); + stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), dynamicsWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) @@ -166,7 +172,7 @@ namespace MWPhysics * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, engine); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, dynamicsWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -185,7 +191,7 @@ namespace MWPhysics * +--+ +--+ * ============================================== */ - stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSizeDown), engine); + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), dynamicsWorld); if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors @@ -201,41 +207,39 @@ namespace MWPhysics // moved between 0 and just under sStepSize distance but slope was too great, // or moved full sStepSize distance (FIXME: is this a bug?) -#endif return false; } ///Project a vector u on another vector v - static inline Ogre::Vector3 project(const Ogre::Vector3 u, const Ogre::Vector3 &v) + static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v) { - return v * u.dotProduct(v); + return v * (u * v); + // ^ dot product } ///Helper for computing the character sliding - static inline Ogre::Vector3 slide(Ogre::Vector3 direction, const Ogre::Vector3 &planeNormal) + static inline osg::Vec3f slide(const osg::Vec3f& direction, const osg::Vec3f &planeNormal) { return direction - project(direction, planeNormal); } + static inline osg::Vec3f reflect(const osg::Vec3& velocity, const osg::Vec3f& normal) + { + return (normal * (normal * velocity)) * 2 - velocity; + } + public: - static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, /*OEngine::Physic::PhysicEngine *engine,*/ float maxHeight) + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btDynamicsWorld* dynamicsWorld, float maxHeight) { - const ESM::Position &refpos = ptr.getRefData().getPosition(); - Ogre::Vector3 position(refpos.pos); + osg::Vec3f position(ptr.getRefData().getPosition().asVec3()); - return position; -#if 0 - OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); - if (!physicActor) - return position; - - OEngine::Physic::ActorTracer tracer; - tracer.findGround(physicActor, position, position-Ogre::Vector3(0,0,maxHeight), engine); + ActorTracer tracer; + tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), dynamicsWorld); if(tracer.mFraction >= 1.0f) { - physicActor->setOnGround(false); + actor->setOnGround(false); return position; } else @@ -243,79 +247,73 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = BtOgre::Convert::toBullet(position); + btVector3 from = toBullet(position); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); resultCallback1.m_collisionFilterGroup = 0xff; resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; - engine->mDynamicsWorld->rayTest(from, to, resultCallback1); + dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - (BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld).distance(tracer.mEndPos) > 30 + ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) { - physicActor->setOnGround(getSlope(BtOgre::Convert::toOgre(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); - return BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld) + Ogre::Vector3(0,0,1.f); + actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); + return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f); } - physicActor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope); + actor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope); return tracer.mEndPos; } -#endif } - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, - bool isFlying, float waterlevel, float slowFall /*, OEngine::Physic::PhysicEngine *engine*/ + static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, + bool isFlying, float waterlevel, float slowFall, btDynamicsWorld* dynamicsWorld , std::map& collisionTracker , std::map& standingCollisionTracker) { - const ESM::Position &refpos = ptr.getRefData().getPosition(); - Ogre::Vector3 position(refpos.pos); - return position; -#if 0 + const ESM::Position& refpos = ptr.getRefData().getPosition(); + osg::Vec3f position(refpos.asVec3()); + // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) return position; - OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); - if (!physicActor) - return position; - // Reset per-frame data physicActor->setWalkingOnWater(false); // Anything to collide with? if(!physicActor->getCollisionMode()) { - return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) - * movement * time; + return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1)) + ) * movement * time; } - btCollisionObject *colobj = physicActor->getCollisionBody(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - position.z += halfExtents.z; + btCollisionObject *colobj = physicActor->getCollisionObject(); + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z - (halfExtents.z * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); - OEngine::Physic::ActorTracer tracer; - Ogre::Vector3 inertia = physicActor->getInertialForce(); - Ogre::Vector3 velocity; + ActorTracer tracer; + osg::Vec3f inertia = physicActor->getInertialForce(); + osg::Vec3f velocity; - if(position.z < swimlevel || isFlying) + if(position.z() < swimlevel || isFlying) { - velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* - Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; + velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; } else { - velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; + velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; - if (velocity.z > 0.f) + if (velocity.z() > 0.f) inertia = velocity; if(!physicActor->getOnGround()) { @@ -327,16 +325,16 @@ namespace MWPhysics // Now that we have the effective movement vector, apply wind forces to it if (MWBase::Environment::get().getWorld()->isInStorm()) { - Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - Ogre::Degree angle = stormDirection.angleBetween(velocity); + osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity)); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fStromWalkMult")->getFloat(); - velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f)); + velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); } - Ogre::Vector3 origVelocity = velocity; + osg::Vec3f origVelocity = velocity; - Ogre::Vector3 newPosition = position; + osg::Vec3f newPosition = position; /* * A loop to find newPosition using tracer, if successful different from the starting position. * nextpos is the local variable used to find potential newPosition, using velocity and remainingTime @@ -345,27 +343,27 @@ namespace MWPhysics float remainingTime = time; for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) { - Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; + osg::Vec3f nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - if(newPosition.z < swimlevel && + if(newPosition.z() < swimlevel && !isFlying && // can't fly - nextpos.z > swimlevel && // but about to go above water - newPosition.z <= swimlevel) + nextpos.z() > swimlevel && // but about to go above water + newPosition.z() <= swimlevel) { - const Ogre::Vector3 down(0,0,-1); - Ogre::Real movelen = velocity.normalise(); - Ogre::Vector3 reflectdir = velocity.reflect(down); - reflectdir.normalise(); + const osg::Vec3f down(0,0,-1); + float movelen = velocity.normalize(); + osg::Vec3f reflectdir = reflect(velocity, down); + reflectdir.normalize(); velocity = slide(reflectdir, down)*movelen; // NOTE: remainingTime is unchanged before the loop continues continue; // velocity updated, calculate nextpos again } - if(newPosition.squaredDistance(nextpos) > 0.0001) + if((newPosition - nextpos).length2() > 0.0001) { // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, engine); + tracer.doTrace(colobj, newPosition, nextpos, dynamicsWorld); // check for obstructions if(tracer.mFraction >= 1.0f) @@ -375,11 +373,13 @@ namespace MWPhysics } else { + /* const btCollisionObject* standingOn = tracer.mHitObject; if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { collisionTracker[ptr.getRefData().getHandle()] = body->mName; } + */ } } else @@ -395,62 +395,68 @@ namespace MWPhysics } - Ogre::Vector3 oldPosition = newPosition; + osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, engine); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, dynamicsWorld); if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent - result = stepMove(colobj, newPosition, velocity.normalisedCopy()*10.f, remainingTime, engine); + { + osg::Vec3f normalizedVelocity = velocity; + normalizedVelocity.normalize(); + result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, dynamicsWorld); + } if(result) { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z + halfExtents.z > waterlevel) + && newPosition.z() + halfExtents.z() > waterlevel) newPosition = oldPosition; } else { // Can't move this way, try to find another spot along the plane - Ogre::Vector3 direction = velocity; - Ogre::Real movelen = direction.normalise(); - Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal); - reflectdir.normalise(); + osg::Vec3f direction = velocity; + float movelen = direction.normalize(); + osg::Vec3f reflectdir = reflect(velocity, tracer.mPlaneNormal); + reflectdir.normalize(); - Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; - if ((newVelocity-velocity).squaredLength() < 0.01) - break; - if (velocity.dotProduct(origVelocity) <= 0.f) + osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + if ((newVelocity-velocity).length2() < 0.01) break; + if ((velocity * origVelocity) <= 0.f) + break; // ^ dot product velocity = newVelocity; // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. - if(!(newPosition.z < swimlevel || isFlying)) - velocity.z = std::min(velocity.z, 0.0f); + if(!(newPosition.z() < swimlevel || isFlying)) + velocity.z() = std::min(velocity.z(), 0.0f); } } bool isOnGround = false; - if (!(inertia.z > 0.f) && !(newPosition.z < swimlevel)) + if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel)) { - Ogre::Vector3 from = newPosition; - Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ? - Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f)); - tracer.doTrace(colobj, from, to, engine); + osg::Vec3f from = newPosition; + osg::Vec3f to = newPosition - (physicActor->getOnGround() ? + osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); + tracer.doTrace(colobj, from, to, dynamicsWorld); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { + /* const btCollisionObject* standingOn = tracer.mHitObject; + if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); - + */ if (!isFlying) - newPosition.z = tracer.mEndPos.z + 1.0f; + newPosition.z() = tracer.mEndPos.z() + 1.0f; isOnGround = true; } @@ -461,13 +467,13 @@ namespace MWPhysics // so that we do not stay suspended in air indefinitely. if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) { - if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) + if (osg::Vec3f(velocity.x(), velocity.y(), 0).length2() < 100.f*100.f) { btVector3 aabbMin, aabbMax; tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); btVector3 center = (aabbMin + aabbMax) / 2.f; - inertia = Ogre::Vector3(position.x - center.x(), position.y - center.y(), 0); - inertia.normalise(); + inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0); + inertia.normalize(); inertia *= 100; } } @@ -476,20 +482,19 @@ namespace MWPhysics } } - if(isOnGround || newPosition.z < swimlevel || isFlying) - physicActor->setInertialForce(Ogre::Vector3(0.0f)); + if(isOnGround || newPosition.z() < swimlevel || isFlying) + physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); else { - inertia.z += time * -627.2f; - if (inertia.z < 0) - inertia.z *= slowFall; + inertia.z() += time * -627.2f; + if (inertia.z() < 0) + inertia.z() *= slowFall; physicActor->setInertialForce(inertia); } physicActor->setOnGround(isOnGround); - newPosition.z -= halfExtents.z; // remove what was added at the beginning + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning return newPosition; -#endif } }; @@ -543,11 +548,62 @@ namespace MWPhysics btCollisionObject* mCollisionObject; }; + // -------------------------------------------------------------- + + class Object : public PtrHolder + { + public: + Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) + : mShapeInstance(shapeInstance) + { + mPtr = ptr; + + mCollisionObject.reset(new btCollisionObject); + mCollisionObject->setCollisionShape(shapeInstance->getCollisionShape()); + + mCollisionObject->setUserPointer(static_cast(this)); + + setScale(ptr.getCellRef().getScale()); + setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + const float* pos = ptr.getRefData().getPosition().pos; + setOrigin(btVector3(pos[0], pos[1], pos[2])); + } + + void updatePtr(const MWWorld::Ptr& updated) + { + mPtr = updated; + } + + void setScale(float scale) + { + mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); + } + + void setRotation(const btQuaternion& quat) + { + mCollisionObject->getWorldTransform().setRotation(quat); + } + + void setOrigin(const btVector3& vec) + { + mCollisionObject->getWorldTransform().setOrigin(vec); + } + + btCollisionObject* getCollisionObject() + { + return mCollisionObject.get(); + } + + private: + std::auto_ptr mCollisionObject; + osg::ref_ptr mShapeInstance; + }; + // --------------------------------------------------------------- - - PhysicsSystem::PhysicsSystem(osg::ref_ptr parentNode) - : mTimeAccum(0.0f) + PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr parentNode) + : mShapeManager(new NifBullet::BulletShapeManager(vfs)) + , mTimeAccum(0.0f) , mWaterEnabled(false) , mWaterHeight(0) , mDebugDrawEnabled(false) @@ -577,6 +633,17 @@ namespace MWPhysics delete it->second; } + for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + { + mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + delete it->second; + } + + for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it) + { + delete it->second; + } + delete mDynamicsWorld; delete mSolver; delete mCollisionConfiguration; @@ -668,9 +735,13 @@ namespace MWPhysics return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); } - Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) + osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) { - return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight); + ActorMap::iterator found = mActors.find(ptr); + if (found == mActors.end()) + return ptr.getRefData().getPosition().asVec3(); + else + return MovementSolver::traceDown(ptr, found->second, mDynamicsWorld, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) @@ -693,45 +764,115 @@ namespace MWPhysics } } - void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) { + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + if (!shapeInstance->getCollisionShape()) + return; + Object *obj = new Object(ptr, shapeInstance); + mObjects.insert(std::make_pair(ptr, obj)); + + mDynamicsWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); + } + + void PhysicsSystem::remove(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + mDynamicsWorld->removeCollisionObject(found->second->getCollisionObject()); + delete found->second; + mObjects.erase(found); + } + + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + delete foundActor->second; + mActors.erase(foundActor); + } + } + + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + float scale = ptr.getCellRef().getScale(); + if (found != mObjects.end()) + { + found->second->setScale(scale); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updateScale(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } + } + + void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updateRotation(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } + } + + void PhysicsSystem::updatePosition(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + { + found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); + mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + return; + } + ActorMap::iterator foundActor = mActors.find(ptr); + if (foundActor != mActors.end()) + { + foundActor->second->updatePosition(); + // no aabb update needed (DISABLE_DEACTIVATION) + return; + } } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + Actor* actor = new Actor(ptr, shapeInstance, mDynamicsWorld); + mActors.insert(std::make_pair(ptr, actor)); } bool PhysicsSystem::toggleCollisionMode() { - /* - for(std::map::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it) + ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr()); + if (found != mActors.end()) { - if (it->first=="player") - { - OEngine::Physic::PhysicActor* act = it->second; - - bool cmode = act->getCollisionMode(); - if(cmode) - { - act->enableCollisionMode(false); - return false; - } - else - { - act->enableCollisionMode(true); - return true; - } - } + bool cmode = found->second->getCollisionMode(); + cmode = !cmode; + found->second->enableCollisionMode(cmode); + return cmode; } - throw std::logic_error ("can't find player"); - */ return false; } - void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement) + void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -764,8 +905,6 @@ namespace MWPhysics mCollisions.clear(); mStandingCollisions.clear(); - /* - const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -786,19 +925,20 @@ namespace MWPhysics Ogre::Vector3(iter->first.getRefData().getPosition().pos))) waterCollision = true; - OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle()); - if (!physicActor) // actor was already removed from the scene + ActorMap::iterator foundActor = mActors.find(iter->first); + if (foundActor == mActors.end()) // actor was already removed from the scene continue; + Actor* physicActor = foundActor->second; physicActor->setCanWaterWalk(waterCollision); // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, + osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions); + waterlevel, slowFall, mDynamicsWorld, mCollisions, mStandingCollisions); - float heightDiff = newpos.z - oldHeight; + float heightDiff = newpos.z() - oldHeight; if (heightDiff < 0) iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); @@ -806,8 +946,6 @@ namespace MWPhysics mMovementResults.push_back(std::make_pair(iter->first, newpos)); } - */ - mTimeAccum = 0.0f; } mMovementQueue.clear(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4dbecdb7c6..e6bfd7cd2f 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H -#define GAME_MWWORLD_PHYSICSSYSTEM_H +#ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H +#define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H #include @@ -21,34 +21,48 @@ namespace MWRender class DebugDrawer; } +namespace NifBullet +{ + class BulletShapeManager; +} + +namespace VFS +{ + class Manager; +} + class btSequentialImpulseConstraintSolver; class btDiscreteDynamicsWorld; namespace MWPhysics { - typedef std::vector > PtrVelocityList; - - enum CollisionType { - CollisionType_World = 1<<0, - CollisionType_Actor = 1<<1, - CollisionType_HeightMap = 1<<2, - CollisionType_Projectile = 1<<4, - CollisionType_Water = 1<<5 - }; + typedef std::vector > PtrVelocityList; class HeightField; + class Object; + class Actor; class PhysicsSystem { public: - PhysicsSystem (osg::ref_ptr parentNode); + PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable=false); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + + // Object or Actor + void remove (const MWWorld::Ptr& ptr); + + void updateScale (const MWWorld::Ptr& ptr); + void updateRotation (const MWWorld::Ptr& ptr); + void updatePosition (const MWWorld::Ptr& ptr); + + // TODO + //void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -61,7 +75,7 @@ namespace MWPhysics void stepSimulation(float dt); std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with - Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, float maxHeight); + osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const std::string &name, const Ogre::Vector3 &origin, @@ -76,7 +90,7 @@ namespace MWPhysics /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. - void queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity); + void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); /// Apply all queued movements, then clear the list. const PtrVelocityList& applyQueuedMovement(float dt); @@ -111,6 +125,14 @@ namespace MWPhysics btCollisionDispatcher* mDispatcher; btDiscreteDynamicsWorld* mDynamicsWorld; + std::auto_ptr mShapeManager; + + typedef std::map ObjectMap; + ObjectMap mObjects; + + typedef std::map ActorMap; + ActorMap mActors; + typedef std::map, HeightField*> HeightFieldMap; HeightFieldMap mHeightFields; @@ -121,9 +143,9 @@ namespace MWPhysics // Tracks all movement collisions happening during a single frame. // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, // stepping up small objects, etc. - std::map mCollisions; + std::map mCollisions; // FIXME: reimplement - std::map mStandingCollisions; + std::map mStandingCollisions; // FIXME: reimplement PtrVelocityList mMovementQueue; PtrVelocityList mMovementResults; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp new file mode 100644 index 0000000000..ddb984821f --- /dev/null +++ b/apps/openmw/mwphysics/trace.cpp @@ -0,0 +1,128 @@ +#include "trace.h" + +#include + +#include +#include + +#include "collisiontype.hpp" +#include "actor.hpp" +#include "convert.hpp" + +namespace MWPhysics +{ + +class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback +{ +public: + ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot) + : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), + mMe(me), mUp(up), mMinSlopeDot(minSlopeDot) + { + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) + { + if(convexResult.m_hitCollisionObject == mMe) + return btScalar( 1 ); + + btVector3 hitNormalWorld; + if(normalInWorldSpace) + hitNormalWorld = convexResult.m_hitNormalLocal; + else + { + ///need to transform normal into worldspace + hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; + } + + btScalar dotUp = mUp.dot(hitNormalWorld); + if(dotUp < mMinSlopeDot) + return btScalar(1); + + return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + } + +protected: + btCollisionObject *mMe; + const btVector3 mUp; + const btScalar mMinSlopeDot; +}; + + +void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +{ + const btVector3 btstart = toBullet(start); + const btVector3 btend = toBullet(end); + + const btTransform &trans = actor->getWorldTransform(); + btTransform from(trans); + btTransform to(trans); + from.setOrigin(btstart); + to.setOrigin(btend); + + ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0)); + // Inherit the actor's collision group and mask + newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup; + newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask; + + btCollisionShape *shape = actor->getCollisionShape(); + assert(shape->isConvex()); + world->convexSweepTest(static_cast(shape), + from, to, newTraceCallback); + + // Copy the hit data over to our trace results struct: + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + mFraction = newTraceCallback.m_closestHitFraction; + mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mEndPos = (end-start)*mFraction + start; + mHitObject = newTraceCallback.m_hitCollisionObject; + } + else + { + mEndPos = end; + mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); + mFraction = 1.0f; + mHitObject = NULL; + } +} + +void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +{ + const btVector3 btstart(start.x(), start.y(), start.z()+1.0f); + const btVector3 btend(end.x(), end.y(), end.z()+1.0f); + + const btTransform &trans = actor->getCollisionObject()->getWorldTransform(); + btTransform from(trans.getBasis(), btstart); + btTransform to(trans.getBasis(), btend); + + ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionObject(), btstart-btend, btScalar(0.0)); + // Inherit the actor's collision group and mask + newTraceCallback.m_collisionFilterGroup = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup; + newTraceCallback.m_collisionFilterMask = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask; + newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor; + + btVector3 halfExtents = toBullet(actor->getHalfExtents()); + + halfExtents[2] = 1.0f; + btCylinderShapeZ base(halfExtents); + + world->convexSweepTest(&base, from, to, newTraceCallback); + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + mFraction = newTraceCallback.m_closestHitFraction; + mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mEndPos = (end-start)*mFraction + start; + mEndPos[2] += 1.0f; + } + else + { + mEndPos = end; + mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); + mFraction = 1.0f; + } +} + +} diff --git a/apps/openmw/mwphysics/trace.h b/apps/openmw/mwphysics/trace.h new file mode 100644 index 0000000000..02f9ebdd1c --- /dev/null +++ b/apps/openmw/mwphysics/trace.h @@ -0,0 +1,27 @@ +#ifndef OENGINE_BULLET_TRACE_H +#define OENGINE_BULLET_TRACE_H + +#include + +class btCollisionObject; +class btDynamicsWorld; + + +namespace MWPhysics +{ + class Actor; + + struct ActorTracer + { + osg::Vec3f mEndPos; + osg::Vec3f mPlaneNormal; + const btCollisionObject* mHitObject; + + float mFraction; + + void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + }; +} + +#endif diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index f0cb8a9677..4a7952c446 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -425,7 +425,7 @@ namespace MWScript MWWorld::Ptr targetPtr; if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { - if (targetPtr.getRefData().getHandle() == testedTargetId) + if (targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index ce74c0c9f3..9fe23ff14d 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -811,10 +811,10 @@ namespace MWScript const std::string script = ptr.getClass().getScript(ptr); if(script.empty()) - str<< ptr.getCellRef().getRefId()<<" ("<getLocals(script); diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index cf6f7bf567..c7fdc793cc 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -6,25 +6,21 @@ #include "ptr.hpp" -namespace ESM -{ - class CellRef; -} namespace MWWorld { - /// List all (Ogre-)handles, then reset RefData::mBaseNode to 0. - struct ListAndResetHandles + struct ListAndResetObjects { - std::vector mHandles; + std::vector mObjects; bool operator() (MWWorld::Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); - if (handle) - mHandles.push_back (handle); + if (ptr.getRefData().getBaseNode()) + { + ptr.getRefData().setBaseNode(NULL); + mObjects.push_back (ptr); + } - ptr.getRefData().setBaseNodeOld(0); return true; } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6a994f0cdb..81e2406986 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -60,7 +60,7 @@ namespace rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); rendering.rotateObject(ptr, rot * worldRotQuat); - //physics.rotateObject(ptr); + physics.updateRotation(ptr); } } @@ -190,14 +190,13 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListAndResetHandles functor; + ListAndResetObjects functor; - (*iter)->forEach(functor); - for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2) + (*iter)->forEach(functor); + for (std::vector::const_iterator iter2 (functor.mObjects.begin()); + iter2!=functor.mObjects.end(); ++iter2) { - //Ogre::SceneNode* node = *iter2; - //mPhysics->removeObject (node->getName()); + mPhysics->remove(*iter2); } if ((*iter)->getCell()->isExterior()) @@ -258,17 +257,16 @@ namespace MWWorld insertCell (*cell, true, loadingListener); mRendering.addCell(cell); -#if 0 bool waterEnabled = cell->getCell()->hasWater(); - mRendering.setWaterEnabled(waterEnabled); + //mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { mPhysics->enableWater(cell->getWaterLevel()); - mRendering.setWaterHeight(cell->getWaterLevel()); + //mRendering.setWaterHeight(cell->getWaterLevel()); } else mPhysics->disableWater(); -#endif + if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); } @@ -564,8 +562,8 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - //mPhysics->removeObject (ptr.getRefData().getHandle()); - //mRendering.removeObject (ptr); + mPhysics->remove(ptr); + //Rendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b9d16993f3..b37a383530 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -415,11 +415,11 @@ void WeatherManager::update(float duration, bool paused) if (mIsStorm) { MWWorld::Ptr player = world->getPlayerPtr(); - Ogre::Vector3 playerPos (player.getRefData().getPosition().pos); - Ogre::Vector3 redMountainPos (19950, 72032, 27831); + osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); + osg::Vec3f redMountainPos (19950, 72032, 27831); mStormDirection = (playerPos - redMountainPos); - mStormDirection.z = 0; + mStormDirection.z() = 0; //mRendering->getSkyManager()->setStormDirection(mStormDirection); } @@ -844,7 +844,7 @@ bool WeatherManager::isInStorm() const return mIsStorm; } -Ogre::Vector3 WeatherManager::getStormDirection() const +osg::Vec3f WeatherManager::getStormDirection() const { return mStormDirection; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 002f4355c8..77d9610575 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -184,7 +184,7 @@ namespace MWWorld /// Are we in an ash or blight storm? bool isInStorm() const; - Ogre::Vector3 getStormDirection() const; + osg::Vec3f getStormDirection() const; void advanceTime(double hours); @@ -205,7 +205,7 @@ namespace MWWorld float mHour; float mWindSpeed; bool mIsStorm; - Ogre::Vector3 mStormDirection; + osg::Vec3f mStormDirection; MWBase::SoundPtr mAmbientSound; std::string mPlayingSoundID; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 72423f4765..add8d03739 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -7,8 +7,6 @@ #else #include #endif -#include "../mwbase/scriptmanager.hpp" -#include "../mwscript/globalscripts.hpp" #include #include @@ -19,6 +17,7 @@ #include #include #include +#include #include @@ -26,6 +25,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" @@ -39,9 +39,12 @@ #include "../mwrender/renderingmanager.hpp" #include "../mwscript/interpretercontext.hpp" +#include "../mwscript/globalscripts.hpp" #include "../mwclass/door.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "player.hpp" #include "manualref.hpp" #include "cellstore.hpp" @@ -51,7 +54,6 @@ #include "actionteleport.hpp" //#include "projectilemanager.hpp" #include "weather.hpp" -#include "../mwphysics/physicssystem.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -156,7 +158,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new MWPhysics::PhysicsSystem(rootNode); + mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); @@ -1216,7 +1218,7 @@ namespace MWWorld if (haveToMove && ptr.getRefData().getBaseNode()) { mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z)); - //mPhysics->moveObject (ptr); + mPhysics->updatePosition(ptr); } if (isPlayer) { @@ -1343,9 +1345,9 @@ namespace MWWorld if (force || !isFlying(ptr)) { - //Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); - //if (traced.z < pos.pos[2]) - // pos.pos[2] = traced.z; + osg::Vec3f traced = mPhysics->traceDown(ptr, 500); + if (traced.z() < pos.pos[2]) + pos.pos[2] = traced.z(); } moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]); @@ -1358,8 +1360,8 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced;// = mPhysics->traceDown(actor, dist*1.1f); - moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); + osg::Vec3f traced = mPhysics->traceDown(actor, dist*1.1f); + moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z()); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -1397,34 +1399,32 @@ namespace MWWorld cellY = static_cast(std::floor(y / cellSize)); } - void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity) + void World::queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) { - //mPhysics->queueObjectMovement(ptr, velocity); + mPhysics->queueObjectMovement(ptr, velocity); } void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); -#if 0 processDoors(duration); - mProjectileManager->update(duration); + //mProjectileManager->update(duration); - const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); - PtrVelocityList::const_iterator player(results.end()); - for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) + const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); + MWPhysics::PtrVelocityList::const_iterator player(results.end()); + for(MWPhysics::PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) { if(iter->first == getPlayerPtr()) { - /* Handle player last, in case a cell transition occurs */ + // Handle player last, in case a cell transition occurs player = iter; continue; } - moveObjectImp(iter->first, iter->second.x, iter->second.y, iter->second.z); + moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z()); } if(player != results.end()) - moveObjectImp(player->first, player->second.x, player->second.y, player->second.z); -#endif + moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z()); } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) @@ -2312,12 +2312,12 @@ namespace MWWorld return false; } - Ogre::Vector3 World::getStormDirection() const + osg::Vec3f World::getStormDirection() const { if (isCellExterior() || isCellQuasiExterior()) return mWeatherManager->getStormDirection(); else - return Ogre::Vector3(0,1,0); + return osg::Vec3f(0,1,0); } void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index efb9b88c6f..a7830da3a7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -380,7 +380,7 @@ namespace MWWorld virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity); + virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity); ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. @@ -650,7 +650,7 @@ namespace MWWorld virtual bool isInStorm() const; /// @see MWWorld::WeatherManager::getStormDirection - virtual Ogre::Vector3 getStormDirection() const; + virtual osg::Vec3f getStormDirection() const; /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 417164f2db..ef32e10dcd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,9 +52,9 @@ add_component_dir (nifosg nifloader controller particle userdata ) -#add_component_dir (nifbullet -# bulletnifloader -# ) +add_component_dir (nifbullet + bulletnifloader bulletshapemanager + ) add_component_dir (to_utf8 to_utf8 @@ -171,6 +171,7 @@ target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} # For MyGUI platform ${OPENGL_gl_LIBRARY} ) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index b80bbb83f2..62f2d94d8f 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -1,31 +1,11 @@ - /* -OpenMW - The completely unofficial reimplementation of Morrowind -Copyright (C) 2008-2010 Nicolay Korslund -Email: < korslund@gmail.com > -WWW: http://openmw.sourceforge.net/ - -This file (ogre_nif_loader.cpp) is part of the OpenMW package. - -OpenMW is distributed as free software: you can redistribute it -and/or modify it under the terms of the GNU General Public License -version 3, as published by the Free Software Foundation. - -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 -version 3 along with this program. If not, see -http://www.gnu.org/licenses/ . - -*/ - #include "bulletnifloader.hpp" #include +#include +#include +#include +#include -#include #include #include "../nif/niffile.hpp" @@ -34,12 +14,7 @@ http://www.gnu.org/licenses/ . #include "../nif/property.hpp" #include "../nif/controller.hpp" #include "../nif/extra.hpp" -#include -#include -#include -// For warning messages -#include namespace { @@ -51,53 +26,40 @@ osg::Matrixf getWorldTransform(const Nif::Node *node) return node->trafo.toMatrix(); } +btVector3 getbtVector(const osg::Vec3f &v) +{ + return btVector3(v.x(), v.y(), v.z()); +} + } namespace NifBullet { -ManualBulletShapeLoader::~ManualBulletShapeLoader() +BulletNifLoader::BulletNifLoader() + : mCompoundShape(NULL) + , mStaticMesh(NULL) { } - -btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) +BulletNifLoader::~BulletNifLoader() { - return btVector3(v[0], v[1], v[2]); } -void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { - mShape = static_cast(resource); - mResourceName = mShape->getName(); - mBoundingBox = NULL; - mShape->mBoxTranslation = osg::Vec3f(0,0,0); - mShape->mBoxRotation = osg::Quat(); + mShape = new BulletShape; + mCompoundShape = NULL; mStaticMesh = NULL; - Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); - Nif::NIFFile & nif = *pnif.get (); - if (nif.numRoots() < 1) + if (nif->numRoots() < 1) { warn("Found no root nodes in NIF."); - return; + return mShape; } - // Have to load controlled nodes from the .kf - // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused - mControlledNodes.clear(); - std::string kfname = mResourceName.substr(0, mResourceName.length()-7); - Misc::StringUtils::toLower(kfname); - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - { - Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - //extractControlledNodes(kf, mControlledNodes); - } - - Nif::Record *r = nif.getRoot(0); + Nif::Record *r = nif->getRoot(0); assert(r != NULL); Nif::Node *node = dynamic_cast(r); @@ -105,29 +67,40 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) { warn("First root in file was not a node, but a " + r->recName + ". Skipping file."); - return; + return mShape; } - mShape->mAutogenerated = hasAutoGeneratedCollision(node); - - //do a first pass - handleNode(node,0,false,false); - - if(mBoundingBox != NULL) + if (findBoundingBox(node)) { - mShape->mCollisionShape = mBoundingBox; - delete mStaticMesh; - if (mCompoundShape) - { - int n = mCompoundShape->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - delete mCompoundShape; - mShape->mAnimatedShapes.clear(); - } + std::auto_ptr compound (new btCompoundShape); + + btBoxShape* boxShape = new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents)); + btTransform transform = btTransform::getIdentity(); + transform.setOrigin(getbtVector(mShape->mCollisionBoxTranslate)); + compound->addChildShape(transform, boxShape); + + mShape->mCollisionShape = compound.release(); + return mShape; } else { + /* + // Have to load controlled nodes from the .kf + mControlledNodes.clear(); + std::string kfname = mResourceName.substr(0, mResourceName.length()-7); + Misc::StringUtils::toLower(kfname); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) + { + Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); + //extractControlledNodes(kf, mControlledNodes); + } + */ + + bool autogenerated = hasAutoGeneratedCollision(node); + handleNode(node, 0, autogenerated, false, autogenerated); + if (mCompoundShape) { mShape->mCollisionShape = mCompoundShape; @@ -140,10 +113,46 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) } else if (mStaticMesh) mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); + + return mShape; } } -bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) +// Find a boundingBox in the node hierarchy. +// Return: use bounding box for collision? +bool BulletNifLoader::findBoundingBox(const Nif::Node* node, int flags) +{ + flags |= node->flags; + + if (node->hasBounds) + { + mShape->mCollisionBoxHalfExtents = node->boundXYZ; + mShape->mCollisionBoxTranslate = node->boundPos; + + if (flags & Nif::NiNode::Flag_BBoxCollision) + { + return true; + } + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) + { + if(!list[i].empty()) + { + bool found = findBoundingBox (list[i].getPtr()); + if (found) + return true; + } + } + } + return false; +} + +bool BulletNifLoader::hasAutoGeneratedCollision(const Nif::Node* rootNode) { const Nif::NiNode *ninode = dynamic_cast(rootNode); if(ninode) @@ -161,8 +170,8 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo return true; } -void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, - bool isCollisionNode, bool isAnimated) +void BulletNifLoader::handleNode(const Nif::Node *node, int flags, + bool isCollisionNode, bool isAnimated, bool autogenerated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -201,24 +210,21 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } + else if (sd->string == "MRK" && autogenerated) + { + // Marker can still have collision if the model explicitely specifies it via a RootCollisionNode. + return; + } + } } - if (isCollisionNode || (mShape->mAutogenerated)) + if (isCollisionNode) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) - if(node->hasBounds) - { - if (flags & Nif::NiNode::Flag_BBoxCollision) - { - mShape->mBoxTranslation = node->boundPos; - //mShape->mBoxRotation = node->boundRot; - //mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } - } - else if(node->recType == Nif::RC_NiTriShape) + if(!node->hasBounds && node->recType == Nif::RC_NiTriShape) { handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated); } @@ -237,7 +243,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) +void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) { assert(shape != NULL); @@ -261,6 +267,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int if (!shape->skin.empty()) isAnimated = false; + /* if (isAnimated) { if (!mCompoundShape) @@ -281,7 +288,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int osg::Vec3f b1 = vertices[triangles[i+0]]; osg::Vec3f b2 = vertices[triangles[i+1]]; osg::Vec3f b3 = vertices[triangles[i+2]]; - childMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); + childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); @@ -304,9 +311,10 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int mCompoundShape->addChildShape(trans, childShape); } else + */ { if (!mStaticMesh) - mStaticMesh = new btTriangleMesh(); + mStaticMesh = new btTriangleMesh(false); // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -315,61 +323,99 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int for(size_t i = 0;i < data->triangles.size();i+=3) { - osg::Vec3f b1 = transform*vertices[triangles[i+0]]; - osg::Vec3f b2 = transform*vertices[triangles[i+1]]; - osg::Vec3f b3 = transform*vertices[triangles[i+2]]; - mStaticMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z())); + osg::Vec3f b1 = vertices[triangles[i+0]]*transform; + osg::Vec3f b2 = vertices[triangles[i+1]]*transform; + osg::Vec3f b3 = vertices[triangles[i+2]]*transform; + mStaticMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } } } -bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) +BulletShape::BulletShape() + : mCollisionShape(NULL) { - if(node->hasBounds) - { - if (!(node->flags & Nif::NiNode::Flag_Hidden)) - { - //translation = node->boundPos; - //orientation = node->boundRot; - //halfExtents = node->boundXYZ; - return true; - } - } - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &list = ninode->children; - for(size_t i = 0;i < list.length();i++) - { - if(!list[i].empty()) - if (findBoundingBox(list[i].getPtr(), halfExtents, translation, orientation)) - return true; - } - } - return false; } -bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation) +BulletShape::~BulletShape() { - Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile)); - Nif::NIFFile & nif = *pnif.get (); + deleteShape(mCollisionShape); +} - if (nif.numRoots() < 1) +void BulletShape::deleteShape(btCollisionShape* shape) +{ + if(shape!=NULL) { - return false; + if(shape->isCompound()) + { + btCompoundShape* ms = static_cast(shape); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); + } + delete shape; + } +} + +btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +{ + if(shape->isCompound()) + { + btCompoundShape *comp = static_cast(shape); + btCompoundShape *newShape = new btCompoundShape; + + int numShapes = comp->getNumChildShapes(); + for(int i = 0;i < numShapes;++i) + { + btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); + btTransform trans = comp->getChildTransform(i); + newShape->addChildShape(trans, child); + } + + return newShape; } - Nif::Record *r = nif.getRoot(0); - assert(r != NULL); - - Nif::Node *node = dynamic_cast(r); - if (node == NULL) + if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) { - return false; +#if BT_BULLET_VERSION >= 283 + btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); +#else + // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); + btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); + NifBullet::TriangleMeshShape* newShape = new NifBullet::TriangleMeshShape(newMesh, true); +#endif + return newShape; } - return findBoundingBox(node, halfExtents, translation, orientation); + if (btBoxShape* boxshape = dynamic_cast(shape)) + { + return new btBoxShape(*boxshape); + } + + throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); +} + +btCollisionShape *BulletShape::getCollisionShape() +{ + return mCollisionShape; +} + +osg::ref_ptr BulletShape::makeInstance() +{ + osg::ref_ptr instance (new BulletShapeInstance(this)); + return instance; +} + +BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) + : BulletShape() + , mSource(source) +{ + mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; + mCollisionBoxTranslate = source->mCollisionBoxTranslate; + + if (source->mCollisionShape) + mCollisionShape = duplicateCollisionShape(source->mCollisionShape); } } // namespace NifBullet diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 2a2e914e35..d80ab77bd3 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -1,41 +1,22 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (ogre_nif_loader.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - 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 - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include -// For warning messages -#include +#include namespace Nif { @@ -47,6 +28,48 @@ namespace Nif namespace NifBullet { +class BulletShapeInstance; +class BulletShape : public osg::Referenced +{ +public: + BulletShape(); + virtual ~BulletShape(); + + btCollisionShape* mCollisionShape; + + // Used for actors. Note, ideally actors would use a separate loader - as it is + // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. + // For now, use one file <-> one resource for simplicity. + osg::Vec3f mCollisionBoxHalfExtents; + osg::Vec3f mCollisionBoxTranslate; + + // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape + // will be a btCompoundShape (which consists of one or more child shapes). + // In this map, for each animated collision shape, + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; + + osg::ref_ptr makeInstance(); + + btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; + + btCollisionShape* getCollisionShape(); + +private: + void deleteShape(btCollisionShape* shape); +}; + +// An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. +// Vertex data is shallow-copied where possible. A ref_ptr to the original shape needs to be held to keep vertex pointers intact. +class BulletShapeInstance : public BulletShape +{ +public: + BulletShapeInstance(osg::ref_ptr source); + +private: + osg::ref_ptr mSource; +}; + // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface struct TriangleMeshShape : public btBvhTriangleMeshShape { @@ -66,18 +89,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape /** *Load bulletShape from NIF files. */ -class ManualBulletShapeLoader +class BulletNifLoader { public: - ManualBulletShapeLoader(bool showMarkers=false) - : mCompoundShape(NULL) - , mStaticMesh(NULL) - , mBoundingBox(NULL) - , mShowMarkers(showMarkers) - { - } + BulletNifLoader(); - virtual ~ManualBulletShapeLoader(); + virtual ~BulletNifLoader(); void warn(const std::string &msg) { @@ -90,44 +107,26 @@ public: abort(); } + osg::ref_ptr load(const Nif::NIFFilePtr file); + private: - btVector3 getbtVector(Ogre::Vector3 const &v); + bool findBoundingBox(const Nif::Node* node, int flags = 0); - /** - *Parse a node. - */ - void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false); + void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false, bool autogenerated=false); - /** - *Helper function - */ bool hasAutoGeneratedCollision(const Nif::Node *rootNode); - /** - *convert a NiTriShape to a bullet trishape. - */ void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); - std::string mResourceName; - - //OEngine::Physic::BulletShape* mShape;//current shape - btCompoundShape* mCompoundShape; btTriangleMesh* mStaticMesh; - btBoxShape *mBoundingBox; - std::set mControlledNodes; - bool mShowMarkers; + osg::ref_ptr mShape; }; - -bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation); - -bool findBoundingBox(const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation); - } #endif diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp new file mode 100644 index 0000000000..6acfdd4085 --- /dev/null +++ b/components/nifbullet/bulletshapemanager.cpp @@ -0,0 +1,47 @@ +#include "bulletshapemanager.hpp" + +#include + +#include + +namespace NifBullet +{ + +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) + : mVFS(vfs) +{ + +} + +BulletShapeManager::~BulletShapeManager() +{ + +} + +osg::ref_ptr BulletShapeManager::createInstance(const std::string &name) +{ + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr shape; + Index::iterator it = mIndex.find(normalized); + if (it == mIndex.end()) + { + Files::IStreamPtr file = mVFS->get(normalized); + + // TODO: add support for non-NIF formats + + BulletNifLoader loader; + // might be worth sharing NIFFiles with SceneManager in some way + shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + + mIndex[normalized] = shape; + } + else + shape = it->second; + + osg::ref_ptr instance = shape->makeInstance(); + return instance; +} + +} diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp new file mode 100644 index 0000000000..d9ba3ffbb6 --- /dev/null +++ b/components/nifbullet/bulletshapemanager.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H +#define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H + +#include +#include + +#include + +namespace VFS +{ + class Manager; +} + +namespace NifBullet +{ + + class BulletShape; + class BulletShapeInstance; + + class BulletShapeManager + { + public: + BulletShapeManager(const VFS::Manager* vfs); + ~BulletShapeManager(); + + osg::ref_ptr createInstance(const std::string& name); + + private: + const VFS::Manager* mVFS; + + typedef std::map > Index; + Index mIndex; + }; + +} + +#endif From 19988d5e45d4a00b2d773743024f08cfce80585d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 04:04:54 +0200 Subject: [PATCH 0235/1812] Remove RefData::getHandle --- apps/openmw/mwbase/world.hpp | 6 --- apps/openmw/mwphysics/physicssystem.cpp | 8 +++ apps/openmw/mwworld/cellreflist.hpp | 10 ---- apps/openmw/mwworld/cellstore.cpp | 71 ------------------------- apps/openmw/mwworld/cellstore.hpp | 3 -- apps/openmw/mwworld/refdata.cpp | 11 ---- apps/openmw/mwworld/refdata.hpp | 3 -- apps/openmw/mwworld/scene.cpp | 12 +---- apps/openmw/mwworld/scene.hpp | 2 - apps/openmw/mwworld/worldimp.cpp | 57 ++++++++------------ apps/openmw/mwworld/worldimp.hpp | 8 --- 11 files changed, 32 insertions(+), 159 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7cc0a6e5ee..008d64aafc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -189,12 +189,6 @@ namespace MWBase ///< 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. - - virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0; - ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found - virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6d429f3e54..9b56a46b85 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -966,6 +966,7 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { + /* const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -975,11 +976,13 @@ namespace MWPhysics if (it->first == actorHandle && it->second == objectHandle) return true; } + */ return false; } void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { + /* const std::string& objectHandle = object.getRefData().getHandle(); for (std::map::const_iterator it = mStandingCollisions.begin(); @@ -988,10 +991,12 @@ namespace MWPhysics if (it->second == objectHandle) out.push_back(it->first); } + */ } bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { + /* const std::string& actorHandle = actor.getRefData().getHandle(); const std::string& objectHandle = object.getRefData().getHandle(); @@ -1001,11 +1006,13 @@ namespace MWPhysics if (it->first == actorHandle && it->second == objectHandle) return true; } + */ return false; } void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { + /* const std::string& objectHandle = object.getRefData().getHandle(); for (std::map::const_iterator it = mCollisions.begin(); @@ -1014,6 +1021,7 @@ namespace MWPhysics if (it->second == objectHandle) out.push_back(it->first); } + */ } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 2c5e01aaa3..49197d1671 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -40,16 +40,6 @@ namespace MWWorld mList.push_back(item); return mList.back(); } - - LiveCellRef *searchViaHandle (const std::string& handle) - { - for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getBaseNode() && - iter->mData.getHandle()==handle) - return &*iter; - - return 0; - } }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 7da7c187d9..4e6c6f116b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -282,77 +282,6 @@ namespace MWWorld return Ptr(); } - Ptr CellStore::searchViaHandle (const std::string& handle) - { - bool oldState = mHasState; - - mHasState = true; - - if (LiveCellRef *ref = mActivators.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mPotions.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mAppas.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mArmors.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mBooks.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mClothes.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mContainers.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatures.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mDoors.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mIngreds.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatureLists.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mItemLists.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLights.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLockpicks.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mMiscItems.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mNpcs.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mProbes.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mRepairs.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mStatics.searchViaHandle (handle)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mWeapons.searchViaHandle (handle)) - return Ptr (ref, this); - - mHasState = oldState; - - return Ptr(); - } - Ptr CellStore::searchViaActorId (int id) { if (Ptr ptr = ::searchViaActorId (mNpcs, id, this)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index d7036d6b19..d3c6d0735c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -94,9 +94,6 @@ namespace MWWorld ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. - Ptr searchViaHandle (const std::string& handle); - ///< Will return an empty Ptr if cell is not loaded. - Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 82bb06b8d8..a95a66f7e2 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -123,17 +123,6 @@ namespace MWWorld {} } - const std::string &RefData::getHandle() - { - if(!mBaseNode) - { - static const std::string empty; - return empty; - } - - return mBaseNode->getName(); - } - Ogre::SceneNode* RefData::getBaseNodeOld() { return mBaseNode; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 955913d9c4..5951cb1015 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -81,9 +81,6 @@ namespace MWWorld RefData& operator= (const RefData& refData); - /// Return OGRE handle (may be empty). - const std::string &getHandle(); - /// Return OGRE base node (can be a null pointer). /// obsolete Ogre::SceneNode* getBaseNodeOld(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 81e2406986..20f1f7ebc7 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -563,7 +563,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); - //Rendering.removeObject (ptr); + //mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) @@ -578,16 +578,6 @@ namespace MWWorld return false; } - Ptr Scene::searchPtrViaHandle (const std::string& handle) - { - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); - iter!=mActiveCells.end(); ++iter) - if (Ptr ptr = (*iter)->searchViaHandle (handle)) - return ptr; - - return Ptr(); - } - Ptr Scene::searchPtrViaActorId (int actorId) { for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 24ffdf07b9..af0b82fc38 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -117,8 +117,6 @@ namespace MWWorld bool isCellActive(const CellStore &cell); - Ptr searchPtrViaHandle (const std::string& handle); - Ptr searchPtrViaActorId (int actorId); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index add8d03739..094098a916 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -676,22 +676,6 @@ namespace MWWorld throw std::runtime_error ("unknown ID: " + name); } - Ptr World::getPtrViaHandle (const std::string& handle) - { - Ptr res = searchPtrViaHandle (handle); - if (res.isEmpty ()) - throw std::runtime_error ("unknown Ogre handle: " + handle); - return res; - } - - Ptr World::searchPtrViaHandle (const std::string& handle) - { - if (mPlayer->getPlayer().getRefData().getHandle()==handle) - return mPlayer->getPlayer(); - - return mWorldScene->searchPtrViaHandle (handle); - } - Ptr World::searchPtrViaActorId (int actorId) { // The player is not registered in any CellStore so must be checked manually @@ -1060,10 +1044,10 @@ namespace MWWorld getFacedHandle(facedHandle, activationDistance); } - if (facedHandle.empty()) + //if (facedHandle.empty()) return MWWorld::Ptr(); - return getPtrViaHandle(facedHandle); + //return getPtrViaHandle(facedHandle); } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -1083,7 +1067,6 @@ namespace MWWorld if(node != NULL) pos += node->_getDerivedPosition(); } - */ std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), // pos, rot, distance); @@ -1091,6 +1074,8 @@ namespace MWWorld return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); return std::make_pair(searchPtrViaHandle(result.first), result.second); + */ + return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); } void World::deleteObject (const Ptr& ptr) @@ -1875,10 +1860,11 @@ namespace MWWorld if (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() >= 30) return false; + /* MWWorld::Ptr hitObject = searchPtrViaHandle(handle); if (!hitObject.isEmpty() && hitObject.getClass().isActor()) return false; - + */ return true; } else @@ -2239,8 +2225,9 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + /* std::vector actors; - //mPhysics->getActorsStandingOn(object, actors); + mPhysics->getActorsStandingOn(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2263,6 +2250,7 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } + */ } void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) @@ -2270,8 +2258,9 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + /* std::vector actors; - //mPhysics->getActorsCollidingWith(object, actors); + mPhysics->getActorsCollidingWith(object, actors); for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist @@ -2294,6 +2283,7 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } + */ } float World::getWindSpeed() @@ -2338,15 +2328,14 @@ namespace MWWorld } } - struct ListHandlesFunctor + struct ListObjectsFunctor { - std::vector mHandles; + std::vector mObjects; bool operator() (Ptr ptr) { - Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld(); - if (handle) - mHandles.push_back(handle->getName()); + if (ptr.getRefData().getBaseNode()) + mObjects.push_back(ptr); return true; } }; @@ -2356,12 +2345,12 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - ListHandlesFunctor functor; - (*cellIt)->forEach(functor); + ListObjectsFunctor functor; + (*cellIt)->forEach(functor); - for (std::vector::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it) - if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).getCellRef().getOwner(), npc.getCellRef().getRefId())) - out.push_back(searchPtrViaHandle(*it)); + for (std::vector::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it) + if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId())) + out.push_back(*it); } } @@ -2714,8 +2703,8 @@ namespace MWWorld // For the player, use camera to aim std::string facedHandle; getFacedHandle(facedHandle, distance); - if (!facedHandle.empty()) - target = getPtrViaHandle(facedHandle); + //if (!facedHandle.empty()) + // target = getPtrViaHandle(facedHandle); } else { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a7830da3a7..97515b7d08 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -98,8 +98,6 @@ namespace MWWorld World (const World&); World& operator= (const World&); - Ptr getPtrViaHandle (const std::string& handle, CellStore& cellStore); - int mActivationDistanceOverride; std::string mStartupScript; @@ -266,12 +264,6 @@ namespace MWWorld ///< 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 Ptr searchPtrViaHandle (const std::string& handle); - ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found - virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. From 65f0195c71e97c67167128c6a900ad1c83fd2028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:24:53 +0200 Subject: [PATCH 0236/1812] Readded animated collision shape support --- apps/openmw/mwphysics/actor.hpp | 5 + apps/openmw/mwphysics/physicssystem.cpp | 130 +++++++++++--------- apps/openmw/mwphysics/physicssystem.hpp | 9 +- apps/openmw/mwworld/worldimp.cpp | 3 +- components/nifbullet/bulletnifloader.cpp | 27 ++-- components/nifbullet/bulletnifloader.hpp | 4 +- components/nifbullet/bulletshapemanager.cpp | 18 ++- components/nifbullet/bulletshapemanager.hpp | 9 +- components/sceneutil/clone.cpp | 3 +- 9 files changed, 118 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index ec1d81fd9d..1f5838543f 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -25,6 +25,11 @@ namespace MWPhysics public: virtual ~PtrHolder() {} + void updatePtr(const MWWorld::Ptr& updated) + { + mPtr = updated; + } + protected: MWWorld::Ptr mPtr; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9b56a46b85..81fc1e2251 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -9,10 +9,12 @@ #include #include -#include +#include #include +#include // FindRecIndexVisitor + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -24,7 +26,6 @@ #include "../mwrender/bulletdebugdraw.hpp" -//#include "../apps/openmw/mwrender/animation.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -35,57 +36,6 @@ #include "convert.hpp" #include "trace.h" -namespace -{ - -/* -void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) -{ - for (std::map::iterator it = map.begin(); - it != map.end(); ++it) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->first->mName); - if (ptr.isEmpty()) // Shouldn't happen - throw std::runtime_error("can't find Ptr"); - - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if (!animation) - continue; - - OEngine::Physic::AnimatedShapeInstance& instance = it->second; - - std::map& shapes = instance.mAnimatedShapes; - for (std::map::iterator shapeIt = shapes.begin(); - shapeIt != shapes.end(); ++shapeIt) - { - - const std::string& mesh = animation->getObjectRootName(); - int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first); - Ogre::Node* bone = animation->getNode(boneHandle); - - if (bone == NULL) - continue; - - btCompoundShape* compound = static_cast(instance.mCompound); - - btTransform trans; - trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); - trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation())); - - compound->getChildShape(shapeIt->second)->setLocalScaling( - compound->getLocalScaling() * - BtOgre::Convert::toBullet(bone->_getDerivedScale())); - compound->updateChildTransform(shapeIt->second, trans); - } - - // needed because we used btDynamicsWorld::setForceUpdateAllAabbs(false) - dynamicsWorld->updateSingleAabb(it->first); - } -} - */ - -} - namespace MWPhysics { @@ -569,11 +519,6 @@ namespace MWPhysics setOrigin(btVector3(pos[0], pos[1], pos[2])); } - void updatePtr(const MWWorld::Ptr& updated) - { - mPtr = updated; - } - void setScale(float scale) { mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); @@ -594,6 +539,47 @@ namespace MWPhysics return mCollisionObject.get(); } + void animateCollisionShapes(btDynamicsWorld* dynamicsWorld) + { + if (mShapeInstance->mAnimatedShapes.empty()) + return; + + assert (mShapeInstance->getCollisionShape()->isCompound()); + + btCompoundShape* compound = dynamic_cast(mShapeInstance->getCollisionShape()); + + for (std::map::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it) + { + int recIndex = it->first; + int shapeIndex = it->second; + + NifOsg::FindRecIndexVisitor visitor(recIndex); + mPtr.getRefData().getBaseNode()->accept(visitor); + if (!visitor.mFound) + { + std::cerr << "animateCollisionShapes: Can't find node " << recIndex << std::endl; + return; + } + + osg::NodePath path = visitor.mFoundPath; + path.erase(path.begin()); + osg::Matrixf matrix = osg::computeLocalToWorld(path); + osg::Vec3f scale = matrix.getScale(); + matrix.orthoNormalize(matrix); + + btTransform transform; + transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling()); + for (int i=0; i<3; ++i) + for (int j=0; j<3; ++j) + transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference + + compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); + compound->updateChildTransform(shapeIndex, transform); + } + + dynamicsWorld->updateSingleAabb(mCollisionObject.get()); + } + private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; @@ -601,8 +587,8 @@ namespace MWPhysics // --------------------------------------------------------------- - PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(vfs)) + PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) + : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) , mTimeAccum(0.0f) , mWaterEnabled(false) , mWaterHeight(0) @@ -795,6 +781,27 @@ namespace MWPhysics } } + void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + ObjectMap::iterator found = mObjects.find(old); + if (found != mObjects.end()) + { + Object* obj = found->second; + obj->updatePtr(updated); + mObjects.erase(found); + mObjects.insert(std::make_pair(updated, obj)); + } + + ActorMap::iterator foundActor = mActors.find(old); + if (foundActor != mActors.end()) + { + Actor* actor = foundActor->second; + actor->updatePtr(updated); + mActors.erase(foundActor); + mActors.insert(std::make_pair(updated, actor)); + } + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); @@ -955,7 +962,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - //animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); + for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + it->second->animateCollisionShapes(mDynamicsWorld); // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index e6bfd7cd2f..54cf48ad17 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -26,9 +26,9 @@ namespace NifBullet class BulletShapeManager; } -namespace VFS +namespace Resource { - class Manager; + class ResourceSystem; } class btSequentialImpulseConstraintSolver; @@ -45,7 +45,7 @@ namespace MWPhysics class PhysicsSystem { public: - PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr parentNode); + PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); @@ -61,8 +61,7 @@ namespace MWPhysics void updateRotation (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr); - // TODO - //void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 094098a916..c1e31453fd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -158,7 +157,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); + mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 62f2d94d8f..89daf898ae 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -46,6 +46,11 @@ BulletNifLoader::~BulletNifLoader() { } +void BulletNifLoader::setAnimatedNodes(const std::set &animatedNodes) +{ + mAnimatedNodes = animatedNodes; +} + osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { mShape = new BulletShape; @@ -84,20 +89,6 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) } else { - /* - // Have to load controlled nodes from the .kf - mControlledNodes.clear(); - std::string kfname = mResourceName.substr(0, mResourceName.length()-7); - Misc::StringUtils::toLower(kfname); - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) - { - Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname)); - //extractControlledNodes(kf, mControlledNodes); - } - */ - bool autogenerated = hasAutoGeneratedCollision(node); handleNode(node, 0, autogenerated, false, autogenerated); @@ -181,7 +172,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; - if (mControlledNodes.find(node->name) != mControlledNodes.end()) + if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end()) isAnimated = true; isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); @@ -238,7 +229,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated); } } } @@ -267,7 +258,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, if (!shape->skin.empty()) isAnimated = false; - /* if (isAnimated) { if (!mCompoundShape) @@ -311,7 +301,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, mCompoundShape->addChildShape(trans, childShape); } else - */ { if (!mStaticMesh) mStaticMesh = new btTriangleMesh(false); @@ -414,6 +403,8 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; mCollisionBoxTranslate = source->mCollisionBoxTranslate; + mAnimatedShapes = source->mAnimatedShapes; + if (source->mCollisionShape) mCollisionShape = duplicateCollisionShape(source->mCollisionShape); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index d80ab77bd3..ae4279f40c 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,6 +107,8 @@ public: abort(); } + void setAnimatedNodes(const std::set& animatedNodes); + osg::ref_ptr load(const Nif::NIFFilePtr file); private: @@ -122,7 +124,7 @@ private: btTriangleMesh* mStaticMesh; - std::set mControlledNodes; + std::set mAnimatedNodes; osg::ref_ptr mShape; }; diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 6acfdd4085..34c64570e8 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -4,11 +4,14 @@ #include +#include + namespace NifBullet { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager) : mVFS(vfs) + , mSceneManager(sceneManager) { } @@ -31,7 +34,20 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: // TODO: add support for non-NIF formats + std::string kfname = normalized; + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + std::set animatedNodes; + if (mVFS->exists(kfname)) + { + osg::ref_ptr keyframes = mSceneManager->getKeyframes(normalized); + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); + it != keyframes->mKeyframeControllers.end(); ++it) + animatedNodes.insert(it->first); + } + BulletNifLoader loader; + loader.setAnimatedNodes(animatedNodes); // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp index d9ba3ffbb6..9db674d6de 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/nifbullet/bulletshapemanager.hpp @@ -11,6 +11,11 @@ namespace VFS class Manager; } +namespace Resource +{ + class SceneManager; +} + namespace NifBullet { @@ -20,13 +25,15 @@ namespace NifBullet class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs); + BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; + // need to load keyframes to know what nodes are going to be animated + Resource::SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index eb7e635879..862a070d8f 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -18,7 +18,8 @@ namespace SceneUtil { setCopyFlags(osg::CopyOp::DEEP_COPY_NODES // Controller might need different inputs per scene instance - | osg::CopyOp::DEEP_COPY_CALLBACKS); + | osg::CopyOp::DEEP_COPY_CALLBACKS + | osg::CopyOp::DEEP_COPY_USERDATA); } osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const From 2bc95df265b4e75de057a0769b919bb5f15dd678 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:49:21 +0200 Subject: [PATCH 0237/1812] Actor collision object placement fix --- apps/openmw/mwphysics/actor.cpp | 7 +++++-- apps/openmw/mwphysics/actor.hpp | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index edad7e196b..1a712461ef 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -87,7 +87,7 @@ void Actor::updatePosition() osg::Vec3f position = mPtr.getRefData().getPosition().asVec3(); btTransform tr = mCollisionObject->getWorldTransform(); - osg::Vec3f scaledTranslation = osg::componentMultiply(mMeshTranslation, mScale); + osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); osg::Vec3f newPosition = scaledTranslation + position; tr.setOrigin(toBullet(newPosition)); @@ -97,8 +97,11 @@ void Actor::updatePosition() void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); - tr.setRotation(toBullet(mPtr.getRefData().getBaseNode()->getAttitude())); + mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); + tr.setRotation(toBullet(mRotation)); mCollisionObject->setWorldTransform(tr); + + updatePosition(); } void Actor::updateScale() diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 1f5838543f..513985c94c 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include +#include #include class btDynamicsWorld; @@ -109,6 +110,7 @@ namespace MWPhysics osg::Vec3f mMeshTranslation; osg::Vec3f mHalfExtents; + osg::Quat mRotation; osg::Vec3f mScale; osg::Vec3f mPosition; From 82316105de11384d509a54e185b1999d2547899f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:49:53 +0200 Subject: [PATCH 0238/1812] BulletShapeManager kf loading fix --- components/nifbullet/bulletshapemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 34c64570e8..e53a351cf4 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -40,7 +40,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: std::set animatedNodes; if (mVFS->exists(kfname)) { - osg::ref_ptr keyframes = mSceneManager->getKeyframes(normalized); + osg::ref_ptr keyframes = mSceneManager->getKeyframes(kfname); for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); it != keyframes->mKeyframeControllers.end(); ++it) animatedNodes.insert(it->first); From e8ec4387d6081c37fdbc8a4da4ca6eb0944b4b58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:11 +0200 Subject: [PATCH 0239/1812] Creature collision fix --- apps/openmw/mwclass/creature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7d4fcf5d60..89302dcc07 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -173,7 +173,7 @@ namespace MWClass { if(!model.empty()) { - //physics.addActor(ptr, model); + physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } From 4036978718241b62cb532f13a9c987d5e467bac2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:31 +0200 Subject: [PATCH 0240/1812] Empty model exception fix --- apps/openmw/mwclass/light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 4d0c0cba99..1e882b5688 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -48,7 +48,7 @@ namespace MWClass assert (ref->mBase != NULL); // TODO: add option somewhere to enable collision for placeable objects - if ((ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) + if (!model.empty() && (ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) physics.addObject(ptr, model); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) From 56ff280230ddc1fc49ced71c9f0ea2982c49eb2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 16:50:43 +0200 Subject: [PATCH 0241/1812] Mention the RefId in "error during rendering: " errors --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 20f1f7ebc7..d087a40d8c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -119,7 +119,7 @@ namespace } catch (const std::exception& e) { - std::string error ("error during rendering: "); + std::string error ("error during rendering '" + ptr.getCellRef().getRefId() + "': "); std::cerr << error + e.what() << std::endl; } } From ccab8cc9a1a46040d9f82d2d6acbd2553c809c5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 17:40:42 +0200 Subject: [PATCH 0242/1812] Register Player in the PhysicsSystem --- apps/launcher/CMakeLists.txt | 1 - apps/launcher/maindialog.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 10 ++++------ apps/openmw/mwrender/animation.cpp | 14 ++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 12 +++++++----- apps/openmw/mwworld/worldimp.hpp | 2 ++ 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 76b6e46bd9..bc1975ac9d 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -89,7 +89,6 @@ add_executable(openmw-launcher target_link_libraries(openmw-launcher ${Boost_LIBRARIES} - ${OGRE_LIBRARIES} ${SDL2_LIBRARY_ONLY} ${QT_LIBRARIES} components diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 00e6a9aa29..edbe48077a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -199,7 +199,7 @@ bool Launcher::MainDialog::setup() // Now create the pages as they need the settings createPages(); - // Call this so we can exit on Ogre/SDL errors before mainwindow is shown + // Call this so we can exit on SDL errors before mainwindow is shown if (!mGraphicsPage->loadSettings()) return false; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 84cf6f5192..ac5d1691cd 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -16,13 +16,13 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -//#include "character.hpp" // fixme: for getActiveWeapon +#include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" #include "combat.hpp" @@ -188,7 +188,6 @@ namespace MWMechanics */ bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { -#if 0 // get or create temporary storage AiCombatStorage& storage = state.get(); @@ -257,9 +256,11 @@ namespace MWMechanics if(readyToAttack) { + if (!minMaxAttackDurationInitialised) { // TODO: this must be updated when a different weapon is equipped + // FIXME: attack durations would be easier to control if we interact more closely with the CharacterController getMinMaxAttackDuration(actor, minMaxAttackDuration); minMaxAttackDurationInitialised = true; } @@ -674,7 +675,6 @@ namespace MWMechanics // FIXME: can fool actors to stay behind doors, etc. // Related to Bug#1102 and to some degree #1155 as well } -#endif return false; } @@ -812,7 +812,6 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } -#if 0 void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) { if (!actor.getClass().hasInventoryStore(actor)) // creatures @@ -876,7 +875,6 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; } } -#endif Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, float duration, int weapType, float strength) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1f749ab4e1..888846789b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -34,6 +34,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority + #include "vismask.hpp" #include "util.hpp" @@ -1068,6 +1070,18 @@ namespace MWRender } } + bool Animation::upperBodyReady() const + { + for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) + { + if((stateiter->second.mPriority > MWMechanics::Priority_Movement + && stateiter->second.mPriority < MWMechanics::Priority_Torch) + || stateiter->second.mPriority == MWMechanics::Priority_Death) + return false; + } + return true; + } + bool Animation::hasNode(const std::string &name) { std::string lowerName = Misc::StringUtils::lowerCase(name); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c85f874038..81f0447075 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -309,7 +309,7 @@ public: bool isPlaying(const std::string &groupname) const; /// Returns true if no important animations are currently playing on the upper body. - //bool upperBodyReady() const; + bool upperBodyReady() const; /** Gets info about the given animation group. * \param groupname Animation group to check. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c1e31453fd..6ea38a8fbe 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -148,7 +149,7 @@ namespace MWWorld const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) - : mPlayer (0), mLocalScripts (mStore), + : mResourceSystem(resourceSystem), mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mActivationDistanceOverride (activationDistanceOverride), mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), @@ -1170,7 +1171,7 @@ namespace MWWorld MWWorld::Ptr newPtr = ptr.getClass() .copyToCell(ptr, *newCell); - newPtr.getRefData().setBaseNodeOld(0); + newPtr.getRefData().setBaseNode(0); } else if (!currCellActive && !newCellActive) ptr.getClass().copyToCell(ptr, *newCell); @@ -1180,8 +1181,9 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); //mRendering->updateObjectCell(ptr, copy); - ptr.getRefData().setBaseNodeOld(NULL); + ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); + mPhysics->updatePtr(ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->updateCell(ptr, copy); @@ -2123,8 +2125,8 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); - //model = Misc::ResourceHelpers::correctActorModelPath(model); - //mPhysics->addActor(mPlayer->getPlayer(), model); + model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); + mPhysics->addActor(getPlayerPtr(), model); } int World::canRest () diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 97515b7d08..279d35329b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -70,6 +70,8 @@ namespace MWWorld class World : public MWBase::World { + Resource::ResourceSystem* mResourceSystem; + MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; From 7a3bc69df7d33a0b0629d7637b182efe0d6fb4f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 May 2015 19:02:56 +0200 Subject: [PATCH 0243/1812] Readded sound listener --- apps/openmw/mwbase/soundmanager.hpp | 9 +-- apps/openmw/mwphysics/physicssystem.cpp | 8 +++ apps/openmw/mwphysics/physicssystem.hpp | 8 ++- .../mwscript/transformationextensions.cpp | 37 +++++----- apps/openmw/mwsound/loudness.cpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 22 +++--- apps/openmw/mwsound/openal_output.hpp | 4 +- apps/openmw/mwsound/sound.hpp | 6 +- apps/openmw/mwsound/sound_output.hpp | 8 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 16 ++--- apps/openmw/mwsound/soundmanagerimp.hpp | 10 +-- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 72 +++++++++---------- 14 files changed, 108 insertions(+), 106 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index e71558de0b..4fccec40bb 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -7,11 +7,6 @@ #include "../mwworld/ptr.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class CellStore; @@ -125,7 +120,7 @@ namespace MWBase ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. @@ -162,7 +157,7 @@ namespace MWBase virtual void update(float duration) = 0; - virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 81fc1e2251..04b53a8e38 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -802,6 +802,14 @@ namespace MWPhysics } } + Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) + { + ActorMap::iterator found = mActors.find(ptr); + if (found != mActors.end()) + return found->second; + return NULL; + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 54cf48ad17..91e166bef4 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -53,6 +53,11 @@ namespace MWPhysics void disableWater(); void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); + + void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + + Actor* getActor(const MWWorld::Ptr& ptr); // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -61,9 +66,6 @@ namespace MWPhysics void updateRotation (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr); - void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); - - void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e71a4a34b6..d43eae021e 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -519,17 +519,17 @@ namespace MWScript for (int i=0; igetOrientation() * posChange; - Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange; + osg::Vec3f worldPos(ptr.getRefData().getPosition().asVec3()); worldPos += diff; - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z()); } }; diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 0077919840..9446a1daea 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -1,5 +1,7 @@ #include "loudness.hpp" +#include + #include "soundmanagerimp.hpp" namespace MWSound @@ -28,7 +30,7 @@ namespace MWSound value = ((char)(data[sample*advance]^0x80))/128.f; else if (type == SampleType_Int16) { - value = *reinterpret_cast(&data[sample*advance]); + value = *reinterpret_cast(&data[sample*advance]); value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 266b97f875..6862bb889d 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -271,7 +271,7 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) - : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) + : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) { throwALerror(); @@ -505,7 +505,7 @@ private: OpenAL_Sound& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); + OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_Sound(); virtual void stop(); @@ -524,14 +524,14 @@ class OpenAL_Sound3D : public OpenAL_Sound OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags) { } virtual void update(); }; -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) , mOutput(output), mSource(src), mBuffer(buf) { @@ -628,7 +628,7 @@ void OpenAL_Sound3D::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) + if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) gain = 0.0f; else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { @@ -867,7 +867,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f try { buf = getBuffer(fname).mALBuffer; - sound.reset(new OpenAL_Sound(*this, src, buf, Ogre::Vector3(0.0f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new OpenAL_Sound(*this, src, buf, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { @@ -892,7 +892,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f return sound; } -MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch, +MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness) { boost::shared_ptr sound; @@ -967,7 +967,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl } -void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) +void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; mLastEnvironment = env; @@ -975,10 +975,10 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 if(mContext) { ALfloat orient[6] = { - atdir.x, atdir.y, atdir.z, - updir.x, updir.y, updir.z + atdir.x(), atdir.y(), atdir.z(), + updir.x(), updir.y(), updir.z() }; - alListener3f(AL_POSITION, mPos.x, mPos.y, mPos.z); + alListener3f(AL_POSITION, mPos.x(), mPos.y(), mPos.z()); alListenerfv(AL_ORIENTATION, orient); throwALerror(); } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 1a95d61505..755a0e5b62 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -54,11 +54,11 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); - virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); virtual void pauseSounds(int types); virtual void resumeSounds(int types); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 1b5c001966..bdc8cf459e 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -15,7 +15,7 @@ namespace MWSound Sound(const Sound &rhs); protected: - Ogre::Vector3 mPos; + osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mBaseVolume; float mPitch; @@ -31,7 +31,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; - void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } + void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setFadeout(float duration) { mFadeOutTime=duration; } void setLoudnessVector(const std::vector& loudnessVector, float loudnessFPS); @@ -44,7 +44,7 @@ namespace MWSound { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) , mVolume(vol) , mBaseVolume(basevol) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 4f5c210bbe..a0c6fb17b9 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -4,8 +4,6 @@ #include #include -#include - #include "soundmanagerimp.hpp" #include "../mwworld/ptr.hpp" @@ -27,11 +25,11 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, 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; + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; virtual void pauseSounds(int types) = 0; virtual void resumeSounds(int types) = 0; @@ -41,7 +39,7 @@ namespace MWSound protected: bool mInitialized; - Ogre::Vector3 mPos; + osg::Vec3f mPos; Sound_Output(SoundManager &mgr) : mManager(mgr) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 775e3da199..a5ae9f0e27 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -268,7 +268,7 @@ namespace MWSound float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -396,9 +396,9 @@ namespace MWSound float min, max; std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); - if ((mode & Play_RemoveAtDistance) && mListenerPos.squaredDistance(objpos) > 2000*2000) + if ((mode & Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) { return MWBase::SoundPtr(); } @@ -416,7 +416,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + MWBase::SoundPtr SoundManager::playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -666,11 +666,11 @@ namespace MWSound if(!ptr.isEmpty()) { const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos); + const osg::Vec3f objpos(pos.asVec3()); snditer->first->setPosition(objpos); if ((snditer->first->mFlags & Play_RemoveAtDistance) - && mListenerPos.squaredDistance(Ogre::Vector3(ptr.getRefData().getPosition().pos)) > 2000*2000) + && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { mActiveSounds.erase(snditer++); continue; @@ -728,7 +728,7 @@ namespace MWSound } } - void SoundManager::setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) + void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) { mListenerPos = pos; mListenerDir = dir; @@ -738,7 +738,7 @@ namespace MWSound MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::CellStore *cell = player.getCell(); - mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z < cell->getWaterLevel()); + mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8089a7e6f5..27af1e65b9 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -55,9 +55,9 @@ namespace MWSound MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; - Ogre::Vector3 mListenerPos; - Ogre::Vector3 mListenerDir; - Ogre::Vector3 mListenerUp; + osg::Vec3f mListenerPos; + osg::Vec3f mListenerDir; + osg::Vec3f mListenerUp; int mPausedSoundTypes; @@ -132,7 +132,7 @@ namespace MWSound ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId, + virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. @@ -171,7 +171,7 @@ namespace MWSound virtual void update(float duration); - virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up); virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 371543f2e1..d4aadc6c7a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -242,7 +242,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNodeOld(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell + item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell ESM::Position pos; pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 93f54c0086..f46f544d28 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -6,18 +6,14 @@ #include #include -#include #include "../mwbase/soundmanager.hpp" #include "ptr.hpp" -namespace OEngine +namespace MWPhysics { -namespace Physic -{ - class PhysicEngine; -} + class PhysicsSystem; } namespace Loading diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6ea38a8fbe..6c7fd6ff38 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include "../mwclass/door.hpp" #include "../mwphysics/physicssystem.hpp" +#include "../mwphysics/actor.hpp" #include "player.hpp" #include "manualref.hpp" @@ -1314,7 +1315,7 @@ namespace MWWorld { ESM::Position pos (ptr.getRefData().getPosition()); - if(!ptr.getRefData().getBaseNodeOld()) + if(!ptr.getRefData().getBaseNode()) { // will be adjusted when Ptr's cell becomes active return; @@ -1596,9 +1597,9 @@ namespace MWWorld performUpdateSceneQueries (); updateWindowManager (); - + */ updateSoundListener(); - + /* if (!paused && mPlayer->getPlayer().getCell()->isExterior()) { ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); @@ -1611,17 +1612,21 @@ namespace MWWorld void World::updateSoundListener() { - /* - Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition(); + const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); + osg::Vec3f playerPos = refpos.asVec3(); - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); - if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; - Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X) * - Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); - MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(), - playerOrient.zAxis()); - */ + const MWPhysics::Actor* actor = mPhysics->getActor(getPlayerPtr()); + if (actor) + playerPos.z() += 1.85f * actor->getHalfExtents().z(); + + osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * + osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f forward = playerOrient * osg::Vec3f(0,1,0); + osg::Vec3f up = playerOrient * osg::Vec3f(0,0,1); + + MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, forward, up); } void World::updateWindowManager () @@ -1987,9 +1992,9 @@ namespace MWWorld && isLevitationEnabled()) return true; - //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle()); - //if(!actor || !actor->getCollisionMode()) - // return true; + const MWPhysics::Actor* actor = mPhysics->getActor(ptr); + if(!actor || !actor->getCollisionMode()) + return true; return false; } @@ -2027,10 +2032,10 @@ namespace MWWorld const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - //const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle()); - //if (actor) + const MWPhysics::Actor* actor = mPhysics->getActor(object); + if (actor) { - // pos.z += heightRatio*2*actor->getHalfExtents().z; + pos.z += heightRatio*2*actor->getHalfExtents().z(); } return isUnderwater(object.getCell(), pos); @@ -2134,17 +2139,16 @@ namespace MWWorld CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr player = mPlayer->getPlayer(); - //RefData &refdata = player.getRefData(); - //Ogre::Vector3 playerPos(refdata.getPosition().pos); + RefData &refdata = player.getRefData(); + Ogre::Vector3 playerPos(refdata.getPosition().pos); - /* - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if (!physactor) + const MWPhysics::Actor* actor = mPhysics->getActor(player); + if (!actor) throw std::runtime_error("can't find player"); - if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) + if((!actor->getOnGround()&&actor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; - */ + if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; @@ -2359,9 +2363,10 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld()) + if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell + // TODO: move to PhysicsSystem /* OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); @@ -2402,11 +2407,9 @@ namespace MWWorld void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { - /* - OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle()); + MWPhysics::Actor *physicActor = mPhysics->getActor(actor); if (physicActor) physicActor->enableCollisionBody(enable); - */ } bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) @@ -3261,9 +3264,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); else - sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); } // Get the actors in range of the effect std::vector objects; @@ -3348,12 +3351,9 @@ namespace MWWorld bool World::isWalkingOnWater(const Ptr &actor) { - return false; - /* - OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + MWPhysics::Actor* physicActor = mPhysics->getActor(actor); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; - */ } } From 375b736e74d83696720a85dfb78ad41f873e9cbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 02:52:04 +0200 Subject: [PATCH 0244/1812] Use SDL to create the window No input nor event loop handling yet, so the window will "stop responding" after a few seconds. Thanks to KittyCat for the GraphicsWindowSDL2 code. --- apps/openmw/engine.cpp | 103 +++++++-- apps/openmw/engine.hpp | 5 + apps/openmw/mwclass/creature.cpp | 10 - apps/openmw/mwclass/creature.hpp | 4 - apps/openmw/mwclass/npc.cpp | 10 - apps/openmw/mwclass/npc.hpp | 4 - apps/openmw/mwworld/class.cpp | 5 - apps/openmw/mwworld/class.hpp | 4 - components/CMakeLists.txt | 5 + components/sdlutil/sdlgraphicswindow.cpp | 272 +++++++++++++++++++++++ components/sdlutil/sdlgraphicswindow.hpp | 108 +++++++++ 11 files changed, 477 insertions(+), 53 deletions(-) create mode 100644 components/sdlutil/sdlgraphicswindow.cpp create mode 100644 components/sdlutil/sdlgraphicswindow.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4c6d1585bf..a77b3e293f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,16 +6,15 @@ #include #include -#include - #include -// TODO: move to component #include #include #include +#include + #include #include @@ -182,7 +181,8 @@ void OMW::Engine::frame(float frametime) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mEncoding(ToUTF8::WINDOWS_1252) + : mWindow(NULL) + , mEncoding(ToUTF8::WINDOWS_1252) , mEncoder(NULL) , mVerboseScripts (false) , mSkipMenu (false) @@ -219,6 +219,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mResourceSystem.reset(); + + mViewer = NULL; + + SDL_DestroyWindow(mWindow); + mWindow = NULL; + mEnvironment.cleanup(); delete mScriptContext; SDL_Quit(); @@ -293,24 +300,88 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) return settingspath; } +void OMW::Engine::createWindow(Settings::Manager& settings) +{ + int screen = settings.getInt("screen", "Video"); + int width = settings.getInt("resolution x", "Video"); + int height = settings.getInt("resolution y", "Video"); + bool fullscreen = settings.getBool("fullscreen", "Video"); + bool windowBorder = settings.getBool("window border", "Video"); + bool vsync = settings.getBool("vsync", "Video"); + int antialiasing = settings.getInt("antialiasing", "Video"); + + int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(screen), + pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(screen); + + if(fullscreen) + { + pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + } + + Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE; + if(fullscreen) + flags |= SDL_WINDOW_FULLSCREEN; + + if (!windowBorder) + flags |= SDL_WINDOW_BORDERLESS; + + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, + settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); + + if (antialiasing > 0) + { + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } + + mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + if (mWindow == NULL) + { + std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; + return; + } + + // TODO: set window icon + + SDLUtil::setupWindowingSystemInterface(); + + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); + SDL_GetWindowSize(mWindow, &traits->width, &traits->height); + traits->windowName = SDL_GetWindowTitle(mWindow); + traits->windowDecoration = !(SDL_GetWindowFlags(mWindow)&SDL_WINDOW_BORDERLESS); + traits->screenNum = SDL_GetWindowDisplayIndex(mWindow); + // FIXME: Some way to get these settings back from the SDL window? + traits->red = 8; + traits->green = 8; + traits->blue = 8; + traits->alpha = 8; + traits->depth = 24; + traits->stencil = 8; + traits->vsync = vsync; + traits->doubleBuffer = true; + traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow); + + osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if(!gc.valid()) throw std::runtime_error("Failed to create GraphicsContext"); + + osg::ref_ptr camera = mViewer->getCamera(); + camera->setGraphicsContext(gc.get()); + camera->setViewport(0, 0, width, height); + + mViewer->realize(); +} + void OMW::Engine::prepareEngine (Settings::Manager & settings) { mEnvironment.setStateManager ( new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); - //OEngine::Render::WindowSettings windowSettings; - //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); - //windowSettings.window_border = settings.getBool("window border", "Video"); - //windowSettings.vsync = settings.getBool("vsync", "Video"); - //windowSettings.icon = "openmw.png"; - //std::string aa = settings.getString("antialiasing", "Video"); - //windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + createWindow(settings); - SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, - settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - - // not handling fullscreen yet, we should figure this out when adding SDL to the mix - mViewer->setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); osg::ref_ptr rootNode (new osg::Group); mViewer->setSceneData(rootNode); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e94b5e3ff5..420121a8e3 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -53,11 +53,14 @@ namespace Files struct ConfigurationManager; } +struct SDL_Window; + namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW class Engine { + SDL_Window* mWindow; std::auto_ptr mVFS; std::auto_ptr mResourceSystem; MWBase::Environment mEnvironment; @@ -112,6 +115,8 @@ namespace OMW /// Prepare engine for game play void prepareEngine (Settings::Manager & settings); + void createWindow(Settings::Manager& settings); + public: Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 89302dcc07..1e41aea247 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -580,16 +580,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 7a50968bf8..f5a2402f38 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -113,10 +113,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6f969146b4..463209df8d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -961,16 +961,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index e0ebbec2b2..f72a9bb2c0 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -105,10 +105,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 0ab18699dd..5999979dec 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -186,11 +186,6 @@ namespace MWWorld throw std::runtime_error ("movement settings not supported by class"); } - Ogre::Vector3 Class::getMovementVector (const Ptr& ptr) const - { - return Ogre::Vector3 (0, 0, 0); - } - Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const { return Ogre::Vector3 (0, 0, 0); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 15058294f3..02afd8960b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -192,10 +192,6 @@ namespace MWWorld virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ef32e10dcd..d62ff3f009 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -126,6 +126,10 @@ add_component_dir (fontloader fontloader ) +add_component_dir (sdlutil + sdlgraphicswindow + ) + add_component_dir (version version ) @@ -172,6 +176,7 @@ target_link_libraries(components ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} ) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp new file mode 100644 index 0000000000..5a9db5923e --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -0,0 +1,272 @@ +#include "sdlgraphicswindow.hpp" + +#include + +#include + +namespace SDLUtil +{ + +GraphicsWindowSDL2::~GraphicsWindowSDL2() +{ + close(true); +} + + +bool GraphicsWindowSDL2::setWindowDecorationImplementation(bool flag) +{ + if(!mWindow) return false; + + SDL_SetWindowBordered(mWindow, flag ? SDL_TRUE : SDL_FALSE); + return true; +} + +bool GraphicsWindowSDL2::setWindowRectangleImplementation(int x, int y, int width, int height) +{ + if(!mWindow) return false; + + SDL_SetWindowPosition(mWindow, x, y); + SDL_SetWindowSize(mWindow, width, height); + return true; +} + +void GraphicsWindowSDL2::setWindowName(const std::string &name) +{ + if(!mWindow) return; + + SDL_SetWindowTitle(mWindow, name.c_str()); + _traits->windowName = name; +} + +void GraphicsWindowSDL2::setCursor(MouseCursor mouseCursor) +{ + _traits->useCursor = false; +} + + +void GraphicsWindowSDL2::init() +{ + if(mValid) return; + + if(!_traits.valid()) + return; + + // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); + + WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); + mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; + + mOwnsWindow = (mWindow == 0); + if(mOwnsWindow) + { + OSG_NOTICE<<"Error: No SDL window provided."<vsync); + + SDL_GL_MakeCurrent(oldWin, oldCtx); + + mValid = true; + + getEventQueue()->syncWindowRectangleWithGraphcisContext(); +} + + +bool GraphicsWindowSDL2::realizeImplementation() +{ + if(mRealized) + { + OSG_NOTICE<< "GraphicsWindowSDL2::realizeImplementation() Already realized" <syncWindowRectangleWithGraphcisContext(); + + mRealized = true; + + return true; +} + +bool GraphicsWindowSDL2::makeCurrentImplementation() +{ + if(!mRealized) + { + OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<setNumFramesToRetainObjects(0); + osg::Referenced::getDeleteHandler()->flushAll(); + } + + //OSG_NOTICE<< "~SDL2WindowingSystemInterface()" <pbuffer) + return NULL; + + osg::ref_ptr window = new GraphicsWindowSDL2(traits); + if(window->valid()) return window.release(); + return NULL; + } +}; + +void setupWindowingSystemInterface() +{ + osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); +} + +} // namespace TK diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp new file mode 100644 index 0000000000..27b9e8e288 --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -0,0 +1,108 @@ +#ifndef OSGGRAPHICSWINDOW_H +#define OSGGRAPHICSWINDOW_H + +#include + +#include + +namespace SDLUtil +{ + +class GraphicsWindowSDL2 : public osgViewer::GraphicsWindow +{ + SDL_Window* mWindow; + SDL_GLContext mContext; + + bool mValid; + bool mRealized; + bool mOwnsWindow; + + void init(); + + virtual ~GraphicsWindowSDL2(); + +public: + GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) + : mWindow(0) + , mContext(0) + , mValid(false) + , mRealized(false) + , mOwnsWindow(false) + { + _traits = traits; + + init(); + if(valid()) + { + setState(new osg::State); + getState()->setGraphicsContext(this); + + if(_traits.valid() && _traits->sharedContext.valid()) + { + getState()->setContextID(_traits->sharedContext->getState()->getContextID()); + incrementContextIDUsageCount(getState()->getContextID()); + } + else + { + getState()->setContextID(osg::GraphicsContext::createNewContextID()); + } + } + } + + virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } + virtual const char* libraryName() const { return "osgViewer"; } + virtual const char* className() const { return "GraphicsWindowSDL2"; } + + virtual bool valid() const { return mValid; } + + /** Realise the GraphicsContext.*/ + virtual bool realizeImplementation(); + + /** Return true if the graphics context has been realised and is ready to use.*/ + virtual bool isRealizedImplementation() const { return mRealized; } + + /** Close the graphics context.*/ + virtual void closeImplementation(); + + /** Make this graphics context current.*/ + virtual bool makeCurrentImplementation(); + + /** Release the graphics context.*/ + virtual bool releaseContextImplementation(); + + /** Swap the front and back buffers.*/ + virtual void swapBuffersImplementation(); + + /** Set sync-to-vblank. */ + virtual void setSyncToVBlank(bool on); + + /** Set Window decoration.*/ + virtual bool setWindowDecorationImplementation(bool flag); + + /** Raise specified window */ + virtual void raiseWindow(); + + /** Set the window's position and size.*/ + virtual bool setWindowRectangleImplementation(int x, int y, int width, int height); + + /** Set the name of the window */ + virtual void setWindowName(const std::string &name); + + /** Set mouse cursor to a specific shape.*/ + virtual void setCursor(MouseCursor cursor); + + /** WindowData is used to pass in the SDL2 window handle attached the GraphicsContext::Traits structure. */ + struct WindowData : public osg::Referenced + { + WindowData(SDL_Window *window) : mWindow(window) + { } + + SDL_Window *mWindow; + }; +}; + +void setupWindowingSystemInterface(); + +} // namespace TK + +#endif /* OSGGRAPHICSWINDOW_H */ From 36e0cfbc9dd20ca40b53ccd1eeeadce0fa2c45ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 03:36:20 +0200 Subject: [PATCH 0245/1812] Cleanup --- apps/openmw/engine.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a77b3e293f..9270b07e81 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -201,7 +201,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mCfgMgr(configurationManager) { Misc::Rng::init(); - std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; @@ -219,6 +218,11 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mEnvironment.cleanup(); + + delete mScriptContext; + mScriptContext = NULL; + mResourceSystem.reset(); mViewer = NULL; @@ -226,8 +230,6 @@ OMW::Engine::~Engine() SDL_DestroyWindow(mWindow); mWindow = NULL; - mEnvironment.cleanup(); - delete mScriptContext; SDL_Quit(); } From 0498e6e5f0fe36cc4a211733c15f97e4e4995660 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 15:03:21 +0200 Subject: [PATCH 0246/1812] Readded window icon --- apps/openmw/engine.cpp | 26 +++++++++++++++++++++- apps/openmw/engine.hpp | 1 + components/CMakeLists.txt | 2 +- components/sdlutil/imagetosurface.cpp | 28 ++++++++++++++++++++++++ components/sdlutil/imagetosurface.hpp | 20 +++++++++++++++++ components/sdlutil/sdlgraphicswindow.cpp | 2 +- components/sdlutil/sdlgraphicswindow.hpp | 4 ++-- 7 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 components/sdlutil/imagetosurface.cpp create mode 100644 components/sdlutil/imagetosurface.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9270b07e81..7f98f6ad7f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -3,8 +3,11 @@ #include #include +#include + #include #include +#include #include @@ -14,6 +17,7 @@ #include #include +#include #include #include @@ -346,7 +350,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) return; } - // TODO: set window icon + setWindowIcon(); SDLUtil::setupWindowingSystemInterface(); @@ -377,6 +381,26 @@ void OMW::Engine::createWindow(Settings::Manager& settings) mViewer->realize(); } +void OMW::Engine::setWindowIcon() +{ + boost::filesystem::ifstream windowIconStream; + std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); + windowIconStream.open(windowIcon); + if (windowIconStream.fail()) + std::cerr << "Failed to open " << windowIcon << std::endl; + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); + if (!result.success()) + std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; + else + { + osg::ref_ptr image = result.getImage(); + SDL_Surface* surface = SDLUtil::imageToSurface(image); + SDL_SetWindowIcon(mWindow, surface); + SDL_FreeSurface(surface); + } +} + void OMW::Engine::prepareEngine (Settings::Manager & settings) { mEnvironment.setStateManager ( diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 420121a8e3..bb70c288d8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -116,6 +116,7 @@ namespace OMW void prepareEngine (Settings::Manager & settings); void createWindow(Settings::Manager& settings); + void setWindowIcon(); public: Engine(Files::ConfigurationManager& configurationManager); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d62ff3f009..e18871a64e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow + sdlgraphicswindow imagetosurface ) add_component_dir (version diff --git a/components/sdlutil/imagetosurface.cpp b/components/sdlutil/imagetosurface.cpp new file mode 100644 index 0000000000..36e503c749 --- /dev/null +++ b/components/sdlutil/imagetosurface.cpp @@ -0,0 +1,28 @@ +#include "imagetosurface.hpp" + +#include +#include + +namespace SDLUtil +{ + +SDL_Surface* imageToSurface(osg::Image *image) +{ + int width = image->s(); + int height = image->t(); + SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); + + for(int x = 0; x < width; ++x) + for(int y = 0; y < height; ++y) + { + osg::Vec4f clr = image->getColor(x, (height-1)-y); + int bpp = surface->format->BytesPerPixel; + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + *(Uint32*)(p) = SDL_MapRGBA(surface->format, static_cast(clr.r() * 255), + static_cast(clr.g() * 255), static_cast(clr.b() * 255), static_cast(clr.a() * 255)); + } + + return surface; +} + +} diff --git a/components/sdlutil/imagetosurface.hpp b/components/sdlutil/imagetosurface.hpp new file mode 100644 index 0000000000..2c5df5cbd5 --- /dev/null +++ b/components/sdlutil/imagetosurface.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H +#define OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H + +struct SDL_Surface; + +namespace osg +{ + class Image; +} + +namespace SDLUtil +{ + + /// Convert an osg::Image to an SDL_Surface. + /// @note The returned surface must be freed using SDL_FreeSurface. + SDL_Surface* imageToSurface(osg::Image* image); + +} + +#endif diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 5a9db5923e..1424337ab6 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -269,4 +269,4 @@ void setupWindowingSystemInterface() osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); } -} // namespace TK +} diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index 27b9e8e288..cfe40d98e9 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -91,7 +91,7 @@ public: /** Set mouse cursor to a specific shape.*/ virtual void setCursor(MouseCursor cursor); - /** WindowData is used to pass in the SDL2 window handle attached the GraphicsContext::Traits structure. */ + /** WindowData is used to pass in the SDL2 window handle attached to the GraphicsContext::Traits structure. */ struct WindowData : public osg::Referenced { WindowData(SDL_Window *window) : mWindow(window) @@ -103,6 +103,6 @@ public: void setupWindowingSystemInterface(); -} // namespace TK +} #endif /* OSGGRAPHICSWINDOW_H */ From 298b3ed2efbf52ba2887aa8acacf4677b3cf0532 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 15:08:47 +0200 Subject: [PATCH 0247/1812] Create the GraphicsWindowSDL2 directly --- apps/openmw/engine.cpp | 8 +- components/sdlutil/sdlgraphicswindow.cpp | 106 ----------------------- components/sdlutil/sdlgraphicswindow.hpp | 2 - 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7f98f6ad7f..98e1c5a282 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -352,8 +352,6 @@ void OMW::Engine::createWindow(Settings::Manager& settings) setWindowIcon(); - SDLUtil::setupWindowingSystemInterface(); - osg::ref_ptr traits = new osg::GraphicsContext::Traits; SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); SDL_GetWindowSize(mWindow, &traits->width, &traits->height); @@ -371,11 +369,11 @@ void OMW::Engine::createWindow(Settings::Manager& settings) traits->doubleBuffer = true; traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow); - osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); - if(!gc.valid()) throw std::runtime_error("Failed to create GraphicsContext"); + osg::ref_ptr graphicsWindow = new SDLUtil::GraphicsWindowSDL2(traits); + if(!graphicsWindow->valid()) throw std::runtime_error("Failed to create GraphicsContext"); osg::ref_ptr camera = mViewer->getCamera(); - camera->setGraphicsContext(gc.get()); + camera->setGraphicsContext(graphicsWindow); camera->setViewport(0, 0, width, height); mViewer->realize(); diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 1424337ab6..6c7bac12eb 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -163,110 +163,4 @@ void GraphicsWindowSDL2::raiseWindow() SDL_RaiseWindow(mWindow); } - -class SDL2WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface -{ -public: - SDL2WindowingSystemInterface() - { - OSG_INFO<< "SDL2WindowingSystemInterface()" <setNumFramesToRetainObjects(0); - osg::Referenced::getDeleteHandler()->flushAll(); - } - - //OSG_NOTICE<< "~SDL2WindowingSystemInterface()" <pbuffer) - return NULL; - - osg::ref_ptr window = new GraphicsWindowSDL2(traits); - if(window->valid()) return window.release(); - return NULL; - } -}; - -void setupWindowingSystemInterface() -{ - osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); -} - } diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index cfe40d98e9..45cf470028 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -101,8 +101,6 @@ public: }; }; -void setupWindowingSystemInterface(); - } #endif /* OSGGRAPHICSWINDOW_H */ From 39fb46601a71342366b2dee79fe01849c432160e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 16:50:47 +0200 Subject: [PATCH 0248/1812] Readded input & event handling --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 72 +++++----- apps/openmw/mwinput/inputmanagerimp.hpp | 37 +++-- components/CMakeLists.txt | 2 +- .../sdlutil/OISCompat.hpp | 0 .../events.h => components/sdlutil/events.hpp | 3 +- components/sdlutil/sdlgraphicswindow.cpp | 27 ++++ components/sdlutil/sdlgraphicswindow.hpp | 33 +---- .../sdlutil}/sdlinputwrapper.cpp | 43 +++--- .../sdlutil}/sdlinputwrapper.hpp | 44 +++--- extern/oics/ICSInputControlSystem.h | 27 ++-- extern/oics/ICSInputControlSystem_mouse.cpp | 6 +- extern/sdl4ogre/imagerotate.cpp | 99 ------------- extern/sdl4ogre/imagerotate.hpp | 25 ---- extern/sdl4ogre/osx_utils.h | 12 -- extern/sdl4ogre/osx_utils.mm | 15 -- extern/sdl4ogre/sdlwindowhelper.cpp | 130 ------------------ extern/sdl4ogre/sdlwindowhelper.hpp | 31 ----- 18 files changed, 151 insertions(+), 457 deletions(-) rename extern/sdl4ogre/OISCompat.h => components/sdlutil/OISCompat.hpp (100%) rename extern/sdl4ogre/events.h => components/sdlutil/events.hpp (99%) rename {extern/sdl4ogre => components/sdlutil}/sdlinputwrapper.cpp (94%) rename {extern/sdl4ogre => components/sdlutil}/sdlinputwrapper.hpp (70%) delete mode 100644 extern/sdl4ogre/imagerotate.cpp delete mode 100644 extern/sdl4ogre/imagerotate.hpp delete mode 100644 extern/sdl4ogre/osx_utils.h delete mode 100644 extern/sdl4ogre/osx_utils.mm delete mode 100644 extern/sdl4ogre/sdlwindowhelper.cpp delete mode 100644 extern/sdl4ogre/sdlwindowhelper.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 98e1c5a282..08d77e7af1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -442,7 +442,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) gameControllerdb = ""; //if it doesn't exist, pass in an empty string // FIXME: shouldn't depend on Engine - MWInput::InputManager* input = new MWInput::InputManager (*this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 62d3bdd03f..0fc25db4cf 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,8 +1,7 @@ #include "inputmanagerimp.hpp" -#include -#include #include +#include #include @@ -14,6 +13,8 @@ #include +#include + #include "../engine.hpp" #include "../mwbase/world.hpp" @@ -31,8 +32,6 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include - using namespace ICS; namespace @@ -97,6 +96,8 @@ namespace namespace MWInput { InputManager::InputManager( + SDL_Window* window, + osg::ref_ptr viewer, OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) @@ -118,8 +119,8 @@ namespace MWInput , mGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) - , mMouseX(0)//ogre.getWindow()->getWidth ()/2.f) - , mMouseY(0)//ogre.getWindow()->getHeight ()/2.f) + , mMouseX(0) + , mMouseY(0) , mMouseWheel(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) @@ -128,19 +129,20 @@ namespace MWInput , mAttemptJump(false) , mFakeDeviceID(1) { + int w,h; + SDL_GetWindowSize(window, &w, &h); - /* - Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow(), grab); + mMouseX = w / 2.f; + mMouseY = h / 2.f; + + mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); - */ std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - //adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); loadControllerDefaults(); @@ -198,7 +200,7 @@ namespace MWInput delete mInputBinder; - //delete mInputManager; + delete mInputManager; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -365,24 +367,24 @@ namespace MWInput void InputManager::updateCursorMode() { - //bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) - // && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; + bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; - bool was_relative = 0;//mInputManager->getMouseRelative(); + bool was_relative = mInputManager->getMouseRelative(); bool is_relative = !MWBase::Environment::get().getWindowManager()->isGuiMode(); // don't keep the pointer away from the window edge in gui mode // stop using raw mouse motions and switch to system cursor movements - //mInputManager->setMouseRelative(is_relative); + mInputManager->setMouseRelative(is_relative); //we let the mouse escape in the main menu - //mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); + mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative)); //we switched to non-relative mode, move our cursor to where the in-game //cursor is if( !is_relative && was_relative != is_relative ) { - //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -390,9 +392,9 @@ namespace MWInput { mControlsDisabled = disableControls; - //mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); + mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - //mInputManager->capture(disableEvents); + mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); @@ -426,7 +428,7 @@ namespace MWInput mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - //mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -657,17 +659,11 @@ namespace MWInput mControlSwitch[sw] = value; } - void InputManager::adjustMouseRegion(int width, int height) - { - mInputBinder->adjustMouseRegion(width, height); - } - void InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing // This assumes that SDL_TextInput events always come *after* the key event // (which is somewhat reasonable, and hopefully true for all SDL platforms) - /* OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) == arg.keysym.scancode @@ -685,7 +681,6 @@ namespace MWInput if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; - */ } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -698,13 +693,11 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - /* mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); - */ } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) @@ -751,7 +744,7 @@ namespace MWInput } } - void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) + void InputManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg ) { mInputBinder->mouseMoved (arg); @@ -830,9 +823,9 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); //esc, to leave initial movie screen - //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - //bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - //setPlayerControlsEnabled(!guiFocus); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -857,8 +850,8 @@ namespace MWInput mInputBinder->buttonReleased(deviceID, arg); ///to escape initial movie - //OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - //setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) @@ -883,12 +876,15 @@ namespace MWInput void InputManager::windowVisibilityChange(bool visible) { - //TODO: Pause game? + //TODO: Pause game? } void InputManager::windowResized(int x, int y) { - //mOgre.windowResized(x,y); + Settings::Manager::setInt("resolution x", "Video", x); + Settings::Manager::setInt("resolution y", "Video", y); + + MWBase::Environment::get().getWindowManager()->windowResized(x, y); } void InputManager::windowClosed() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index cd80ed460b..27c08ed325 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -3,11 +3,17 @@ #include "../mwgui/mode.hpp" +#include + +#include +#include + #include #include +#include #include "../mwbase/inputmanager.hpp" -#include + namespace MWWorld { @@ -39,8 +45,17 @@ namespace Files struct ConfigurationManager; } -#include -#include +namespace SDLUtil +{ + class InputWrapper; +} + +namespace osgViewer +{ + class Viewer; +} + +struct SDL_Window; namespace MWInput { @@ -50,15 +65,17 @@ namespace MWInput */ class InputManager : public MWBase::InputManager, - public SFO::KeyListener, - public SFO::MouseListener, - public SFO::WindowListener, - public SFO::ControllerListener, + public SDLUtil::KeyListener, + public SDLUtil::MouseListener, + public SDLUtil::WindowListener, + public SDLUtil::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { public: InputManager( + SDL_Window* window, + osg::ref_ptr viewer, OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -100,7 +117,7 @@ namespace MWInput virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); - virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void mouseMoved( const SDLUtil::MouseMotionEvent &arg ); virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); @@ -140,8 +157,7 @@ namespace MWInput ICS::InputControlSystem* mInputBinder; - - SFO::InputWrapper* mInputManager; + SDLUtil::InputWrapper* mInputManager; std::string mUserFile; @@ -178,7 +194,6 @@ namespace MWInput std::map mControlSwitch; private: - void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); virtual std::string sdlControllerAxisToString(int axis); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e18871a64e..6590c7e995 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface + sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events ) add_component_dir (version diff --git a/extern/sdl4ogre/OISCompat.h b/components/sdlutil/OISCompat.hpp similarity index 100% rename from extern/sdl4ogre/OISCompat.h rename to components/sdlutil/OISCompat.hpp diff --git a/extern/sdl4ogre/events.h b/components/sdlutil/events.hpp similarity index 99% rename from extern/sdl4ogre/events.h rename to components/sdlutil/events.hpp index 986dd7d8b5..7c79470fff 100644 --- a/extern/sdl4ogre/events.h +++ b/components/sdlutil/events.hpp @@ -8,7 +8,8 @@ // Events // //////////// -namespace SFO { +namespace SDLUtil +{ /** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ struct MouseMotionEvent : SDL_MouseMotionEvent { diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 6c7bac12eb..c69fcca642 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -12,6 +12,33 @@ GraphicsWindowSDL2::~GraphicsWindowSDL2() close(true); } +GraphicsWindowSDL2::GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) + : mWindow(0) + , mContext(0) + , mValid(false) + , mRealized(false) + , mOwnsWindow(false) +{ + _traits = traits; + + init(); + if(valid()) + { + setState(new osg::State); + getState()->setGraphicsContext(this); + + if(_traits.valid() && _traits->sharedContext.valid()) + { + getState()->setContextID(_traits->sharedContext->getState()->getContextID()); + incrementContextIDUsageCount(getState()->getContextID()); + } + else + { + getState()->setContextID(osg::GraphicsContext::createNewContextID()); + } + } +} + bool GraphicsWindowSDL2::setWindowDecorationImplementation(bool flag) { diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index 45cf470028..b2b7cfaf0d 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -1,7 +1,7 @@ -#ifndef OSGGRAPHICSWINDOW_H -#define OSGGRAPHICSWINDOW_H +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLGRAPHICSWINDOW_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLGRAPHICSWINDOW_H -#include +#include #include @@ -22,32 +22,7 @@ class GraphicsWindowSDL2 : public osgViewer::GraphicsWindow virtual ~GraphicsWindowSDL2(); public: - GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) - : mWindow(0) - , mContext(0) - , mValid(false) - , mRealized(false) - , mOwnsWindow(false) - { - _traits = traits; - - init(); - if(valid()) - { - setState(new osg::State); - getState()->setGraphicsContext(this); - - if(_traits.valid() && _traits->sharedContext.valid()) - { - getState()->setContextID(_traits->sharedContext->getState()->getContextID()); - incrementContextIDUsageCount(getState()->getContextID()); - } - else - { - getState()->setContextID(osg::GraphicsContext::createNewContextID()); - } - } - } + GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits); virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } virtual const char* libraryName() const { return "osgViewer"; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp similarity index 94% rename from extern/sdl4ogre/sdlinputwrapper.cpp rename to components/sdlutil/sdlinputwrapper.cpp index aaf669ff43..44492cf6c9 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -1,17 +1,16 @@ #include "sdlinputwrapper.hpp" -#include -#include -#include +#include +#include +#include -namespace SFO +namespace SDLUtil { - /// \brief General purpose wrapper for OGRE applications around SDL's event - /// queue, mostly used for handling input-related events. - InputWrapper::InputWrapper(SDL_Window* window, Ogre::RenderWindow* ogreWindow, bool grab) : + +InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr viewer, bool grab) : mSDLWindow(window), - mOgreWindow(ogreWindow), + mViewer(viewer), mWarpCompensate(false), mMouseRelative(false), mGrabPointer(false), @@ -147,28 +146,26 @@ namespace SFO mMouseInWindow = false; updateMouseSettings(); break; + case SDL_WINDOWEVENT_MOVED: + // I'm not sure what OSG is using the window position for, but I don't think it's needed, + // so we ignore window moved events (improves window movement performance) + break; case SDL_WINDOWEVENT_SIZE_CHANGED: int w,h; SDL_GetWindowSize(mSDLWindow, &w, &h); - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mOgreWindow->resize(w, h); -#else - mOgreWindow->windowMovedOrResized(); -#endif + int x,y; + SDL_GetWindowPosition(mSDLWindow, &x,&y); + mViewer->getCamera()->getGraphicsContext()->resized(x,y,w,h); + + mViewer->getEventQueue()->windowResize(x,y,w,h); + if (mWindowListener) mWindowListener->windowResized(w, h); + break; case SDL_WINDOWEVENT_RESIZED: - // TODO: Fix Ogre to handle this more consistently (fixed in 1.9) -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - mOgreWindow->resize(evt.window.data1, evt.window.data2); -#else - mOgreWindow->windowMovedOrResized(); -#endif - if (mWindowListener) - mWindowListener->windowResized(evt.window.data1, evt.window.data2); + // This should also fire SIZE_CHANGED, so no need to handle break; case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -187,12 +184,10 @@ namespace SFO case SDL_WINDOWEVENT_CLOSE: break; case SDL_WINDOWEVENT_SHOWN: - mOgreWindow->setVisible(true); if (mWindowListener) mWindowListener->windowVisibilityChange(true); break; case SDL_WINDOWEVENT_HIDDEN: - mOgreWindow->setVisible(false); if (mWindowListener) mWindowListener->windowVisibilityChange(false); break; diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp similarity index 70% rename from extern/sdl4ogre/sdlinputwrapper.hpp rename to components/sdlutil/sdlinputwrapper.hpp index a7023207c6..bdb5842ae8 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -1,24 +1,27 @@ -#ifndef SDL4OGRE_SDLINPUTWRAPPER_H -#define SDL4OGRE_SDLINPUTWRAPPER_H +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLINPUTWRAPPER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLINPUTWRAPPER_H -#define NOMINMAX +#include + +#include #include -#include -#include +#include "OISCompat.hpp" +#include "events.hpp" -#include "OISCompat.h" -#include "events.h" - - - -namespace SFO +namespace osgViewer { + class Viewer; +} + +namespace SDLUtil +{ + /// \brief A wrapper around SDL's event queue, mostly used for handling input-related events. class InputWrapper { public: - InputWrapper(SDL_Window *window, Ogre::RenderWindow* ogreWindow, bool grab); + InputWrapper(SDL_Window *window, osg::ref_ptr viewer, bool grab); ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } @@ -42,7 +45,6 @@ namespace SFO void updateMouseSettings(); private: - void handleWindowEvent(const SDL_Event& evt); bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); @@ -51,12 +53,15 @@ namespace SFO void _setupOISKeys(); - SFO::MouseListener* mMouseListener; - SFO::KeyListener* mKeyboardListener; - SFO::WindowListener* mWindowListener; - SFO::ControllerListener* mConListener; + SDL_Window* mSDLWindow; + osg::ref_ptr mViewer; - typedef boost::unordered_map KeyMap; + MouseListener* mMouseListener; + KeyListener* mKeyboardListener; + WindowListener* mWindowListener; + ControllerListener* mConListener; + + typedef std::map KeyMap; KeyMap mKeyMap; Uint16 mWarpX; @@ -79,9 +84,6 @@ namespace SFO bool mWindowHasFocus; bool mMouseInWindow; - - SDL_Window* mSDLWindow; - Ogre::RenderWindow* mOgreWindow; }; } diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 51b701b48c..a82a11d751 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,8 +32,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" - #include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); @@ -51,11 +49,8 @@ namespace ICS virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : - public SFO::MouseListener, - public SFO::KeyListener, - public SFO::ControllerListener - { + class DllExport InputControlSystem + { public: @@ -64,7 +59,7 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::map JoystickInstanceMap; + typedef std::map JoystickInstanceMap; typedef std::list JoystickIDList; typedef struct @@ -101,13 +96,13 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); void controllerRemoved(const SDL_ControllerDeviceEvent &args); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; // MouseListener - void mouseMoved(const SFO::MouseMotionEvent &evt); + void mouseMoved(const SDL_MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); @@ -185,9 +180,9 @@ namespace ICS typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - - typedef std::map JoystickAxisBinderMapType; // > + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // @@ -210,7 +205,7 @@ namespace ICS bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -237,7 +232,7 @@ namespace ICS , int axis, Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control - , unsigned int button, Control::ControlChangingDirection direction); + , unsigned int button, Control::ControlChangingDirection direction); }; diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index 9742d389c1..5decaf1eb8 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -224,11 +224,11 @@ namespace ICS } // mouse Listeners - void InputControlSystem::mouseMoved(const SFO::MouseMotionEvent& evt) + void InputControlSystem::mouseMoved(const SDL_MouseMotionEvent& evt) { if(mActive) { - if(!mDetectingBindingControl) + if(!mDetectingBindingControl) { if(mXmouseAxisBinded && evt.xrel) { @@ -289,7 +289,7 @@ namespace ICS mMouseAxisBindingInitialValues[0] += evt.xrel; mMouseAxisBindingInitialValues[1] += evt.yrel; - mMouseAxisBindingInitialValues[2] += evt.zrel; + // mMouseAxisBindingInitialValues[2] += evt.zrel; if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN ) { diff --git a/extern/sdl4ogre/imagerotate.cpp b/extern/sdl4ogre/imagerotate.cpp deleted file mode 100644 index b825943fc1..0000000000 --- a/extern/sdl4ogre/imagerotate.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "imagerotate.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; - -namespace SFO -{ - -void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) -{ - Root* root = Ogre::Root::getSingletonPtr(); - - std::string destImageRot = std::string(destImage) + std::string("_rot"); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); - - MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); - Degree deg(angle); - tus->setTextureRotate(Radian(deg.valueRadians())); - tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setCorners(-1.0, 1.0, 1.0, -1.0); - rect->setMaterial("ImageRotateMaterial"); - // Render the background before everything else - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - // retrieve image width and height - TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); - unsigned int width = sourceTexture->getWidth(); - unsigned int height = sourceTexture->getHeight(); - - TexturePtr destTextureRot = TextureManager::getSingleton().createManual( - destImageRot, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_A8B8G8R8, - TU_RENDERTARGET); - - RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - //copy the rotated image to a static texture - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_A8B8G8R8, - Ogre::TU_STATIC); - - destTexture->getBuffer()->blit(destTextureRot->getBuffer()); - - // remove all the junk we've created - TextureManager::getSingleton().remove(destImageRot); - MaterialManager::getSingleton().remove("ImageRotateMaterial"); - root->destroySceneManager(sceneMgr); - delete rect; -} - -} diff --git a/extern/sdl4ogre/imagerotate.hpp b/extern/sdl4ogre/imagerotate.hpp deleted file mode 100644 index 7135a571ab..0000000000 --- a/extern/sdl4ogre/imagerotate.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef OENGINE_OGRE_IMAGEROTATE_HPP -#define OENGINE_OGRE_IMAGEROTATE_HPP - -#include - - -namespace SFO -{ - - /// Rotate an image by certain degrees and save as file, uses the GPU - /// Make sure Ogre Root is initialised before calling - class ImageRotate - { - public: - /** - * @param source image (file name - has to exist in an resource group) - * @param name of the destination texture to save to (in memory) - * @param angle in degrees to turn - */ - static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); - }; - -} - -#endif diff --git a/extern/sdl4ogre/osx_utils.h b/extern/sdl4ogre/osx_utils.h deleted file mode 100644 index 48149827ab..0000000000 --- a/extern/sdl4ogre/osx_utils.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SDL4OGRE_OSX_UTILS_H -#define SDL4OGRE_OSX_UTILS_H - -#include - -namespace SFO { - -extern unsigned long WindowContentViewHandle(SDL_SysWMinfo &info); - -} - -#endif // SDL4OGRE_OSX_UTILS_H diff --git a/extern/sdl4ogre/osx_utils.mm b/extern/sdl4ogre/osx_utils.mm deleted file mode 100644 index 4069959cbd..0000000000 --- a/extern/sdl4ogre/osx_utils.mm +++ /dev/null @@ -1,15 +0,0 @@ -#include "osx_utils.h" -#import - - -namespace SFO { - -unsigned long WindowContentViewHandle(SDL_SysWMinfo &info) -{ - NSWindow *window = info.info.cocoa.window; - NSView *view = [window contentView]; - - return (unsigned long)view; -} - -} diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp deleted file mode 100644 index 637fae0efe..0000000000 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "sdlwindowhelper.hpp" - -#include -#include -#include - -#include -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include "osx_utils.h" -#endif - -namespace SFO -{ - -SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h, - const std::string& title, bool fullscreen, Ogre::NameValuePairList params) - : mSDLWindow(window) -{ - //get the native whnd - struct SDL_SysWMinfo wmInfo; - SDL_VERSION(&wmInfo.version); - - if (SDL_GetWindowWMInfo(mSDLWindow, &wmInfo) == SDL_FALSE) - throw std::runtime_error("Couldn't get WM Info!"); - - Ogre::String winHandle; - - switch (wmInfo.subsystem) - { -#ifdef WIN32 - case SDL_SYSWM_WINDOWS: - // Windows code - winHandle = Ogre::StringConverter::toString((uintptr_t)wmInfo.info.win.window); - break; -#elif __MACOSX__ - case SDL_SYSWM_COCOA: - //required to make OGRE play nice with our window - params.insert(std::make_pair("macAPI", "cocoa")); - params.insert(std::make_pair("macAPICocoaUseNSView", "true")); - winHandle = Ogre::StringConverter::toString(WindowContentViewHandle(wmInfo)); - break; -#elif ANDROID - case SDL_SYSWM_ANDROID: - winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.android.window); - break; - #else - case SDL_SYSWM_X11: - winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window); - break; -#endif - default: - throw std::runtime_error("Unexpected WM!"); - break; - } - - /// \todo externalWindowHandle is deprecated according to the source code. Figure out a way to get parentWindowHandle - /// to work properly. On Linux/X11 it causes an occasional GLXBadDrawable error. - -#ifdef ANDROID - SDL_GLContext context= SDL_GL_CreateContext(window); - params.insert(std::make_pair("currentGLContext","True")); -#endif - params.insert(std::make_pair("externalWindowHandle", winHandle)); - - mWindow = Ogre::Root::getSingleton().createRenderWindow(title, w, h, fullscreen, ¶ms); -} - -void SDLWindowHelper::setWindowIcon(const std::string &name) -{ - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().load(name, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); - if (texture.isNull()) - { - std::stringstream error; - error << "Window icon not found: " << name; - throw std::runtime_error(error.str()); - } - Ogre::Image image; - texture->convertToImage(image); - - SDL_Surface* surface = SDL_CreateRGBSurface(0,texture->getWidth(),texture->getHeight(),32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < texture->getWidth(); ++x) - { - for(size_t y = 0; y < texture->getHeight(); ++y) - { - Ogre::ColourValue clr = image.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - Uint32 pixel = SDL_MapRGBA(surface->format, static_cast(clr.r * 255), - static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255)); - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } - } - - SDL_SetWindowIcon(mSDLWindow, surface); - SDL_FreeSurface(surface); -} - -} diff --git a/extern/sdl4ogre/sdlwindowhelper.hpp b/extern/sdl4ogre/sdlwindowhelper.hpp deleted file mode 100644 index 834716b223..0000000000 --- a/extern/sdl4ogre/sdlwindowhelper.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SDL4OGRE_SDLWINDOWHELPER_H -#define SDL4OGRE_SDLWINDOWHELPER_H - -#include - -namespace Ogre -{ - class RenderWindow; -} -struct SDL_Window; - -namespace SFO -{ - - /// @brief Creates an Ogre window from an SDL window and allows setting an Ogre texture as window icon - class SDLWindowHelper - { - public: - SDLWindowHelper (SDL_Window* window, int w, int h, const std::string& title, bool fullscreen, Ogre::NameValuePairList params); - void setWindowIcon(const std::string& name); - Ogre::RenderWindow* getWindow() { return mWindow; } - - private: - Ogre::RenderWindow* mWindow; - SDL_Window* mSDLWindow; - }; - -} - - -#endif From 4825744a0386a1104736e0d4a6ab70b99677bd98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 17:25:54 +0200 Subject: [PATCH 0249/1812] Fix inconsistent health bar skin --- files/mygui/openmw_progress.skin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index 761574c15d..71bbfe9f0c 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -2,7 +2,7 @@ - + From 9ea416b852447669317aa547b3584cef32a58ec2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 18:56:14 +0200 Subject: [PATCH 0250/1812] Readded HW cursor manager (no image rotation yet) --- CMakeLists.txt | 1 - apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 20 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +- components/CMakeLists.txt | 2 +- components/sdlutil/imagetosurface.cpp | 4 +- components/sdlutil/imagetosurface.hpp | 2 +- components/sdlutil/sdlcursormanager.cpp | 182 +++++++++++++++++++++++ components/sdlutil/sdlcursormanager.hpp | 51 +++++++ components/sdlutil/sdlgraphicswindow.cpp | 9 +- components/sdlutil/sdlinputwrapper.cpp | 10 ++ extern/sdl4ogre/CMakeLists.txt | 27 ---- extern/sdl4ogre/cursormanager.hpp | 30 ---- extern/sdl4ogre/sdlcursormanager.cpp | 161 -------------------- extern/sdl4ogre/sdlcursormanager.hpp | 39 ----- 15 files changed, 270 insertions(+), 276 deletions(-) create mode 100644 components/sdlutil/sdlcursormanager.cpp create mode 100644 components/sdlutil/sdlcursormanager.hpp delete mode 100644 extern/sdl4ogre/CMakeLists.txt delete mode 100644 extern/sdl4ogre/cursormanager.hpp delete mode 100644 extern/sdl4ogre/sdlcursormanager.cpp delete mode 100644 extern/sdl4ogre/sdlcursormanager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fae7ff6836..d0515a1fb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,7 +458,6 @@ endif(WIN32) # Extern add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) -#add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08d77e7af1..403cb79f28 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -393,7 +393,7 @@ void OMW::Engine::setWindowIcon() else { osg::ref_ptr image = result.getImage(); - SDL_Surface* surface = SDLUtil::imageToSurface(image); + SDL_Surface* surface = SDLUtil::imageToSurface(image, true); SDL_SetWindowIcon(mWindow, surface); SDL_FreeSurface(surface); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9c7a9de20a..5e573c1e4b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -20,11 +20,12 @@ #include #include -#include +#include #include #include +#include #include @@ -35,6 +36,8 @@ #include #include +#include + #include #include "../mwbase/inputmanager.hpp" @@ -219,7 +222,7 @@ namespace MWGui mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); //set up the hardware cursor manager - //mCursorManager = new SFO::SDLCursorManager(); + mCursorManager = new SDLUtil::SDLCursorManager(); MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); @@ -227,7 +230,7 @@ namespace MWGui onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - //mCursorManager->setEnabled(true); + mCursorManager->setEnabled(true); // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); @@ -417,7 +420,7 @@ namespace MWGui delete mDebugWindow; delete mJailScreen; - //delete mCursorManager; + delete mCursorManager; cleanupGarbage(); @@ -1152,7 +1155,6 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { - /* if(!mCursorManager->cursorChanged(name)) return; //the cursor manager doesn't want any more info about this cursor //See if we can get the information we need out of the cursor resource @@ -1163,10 +1165,11 @@ namespace MWGui std::string tex_name = imgSet->getIndexInfo(0,0).texture; - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + tex->setUnRefImageDataAfterApply(false); // FIXME? //everything looks good, send it to the cursor manager - if(!tex.isNull()) + if(tex.valid()) { Uint8 size_x = imgSetPtr->getSize().width; Uint8 size_y = imgSetPtr->getSize().height; @@ -1174,10 +1177,9 @@ namespace MWGui Uint8 hotspot_y = imgSetPtr->getHotSpot().top; int rotation = imgSetPtr->getRotation(); - mCursorManager->receiveCursorInfo(name, rotation, tex, size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); } } - */ } void WindowManager::popGuiMode() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3258818896..d07f2fb98d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -52,9 +52,9 @@ namespace Resource class ResourceSystem; } -namespace SFO +namespace SDLUtil { - class CursorManager; + class SDLCursorManager; } namespace osgMyGUI @@ -454,7 +454,7 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; - SFO::CursorManager* mCursorManager; + SDLUtil::SDLCursorManager* mCursorManager; std::vector mGarbageDialogs; void cleanupGarbage(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6590c7e995..0c76f666b2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events + sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events sdlcursormanager ) add_component_dir (version diff --git a/components/sdlutil/imagetosurface.cpp b/components/sdlutil/imagetosurface.cpp index 36e503c749..6313c0a8fd 100644 --- a/components/sdlutil/imagetosurface.cpp +++ b/components/sdlutil/imagetosurface.cpp @@ -6,7 +6,7 @@ namespace SDLUtil { -SDL_Surface* imageToSurface(osg::Image *image) +SDL_Surface* imageToSurface(osg::Image *image, bool flip) { int width = image->s(); int height = image->t(); @@ -15,7 +15,7 @@ SDL_Surface* imageToSurface(osg::Image *image) for(int x = 0; x < width; ++x) for(int y = 0; y < height; ++y) { - osg::Vec4f clr = image->getColor(x, (height-1)-y); + osg::Vec4f clr = image->getColor(x, flip ? ((height-1)-y) : y); int bpp = surface->format->BytesPerPixel; Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; *(Uint32*)(p) = SDL_MapRGBA(surface->format, static_cast(clr.r() * 255), diff --git a/components/sdlutil/imagetosurface.hpp b/components/sdlutil/imagetosurface.hpp index 2c5df5cbd5..ad0457433c 100644 --- a/components/sdlutil/imagetosurface.hpp +++ b/components/sdlutil/imagetosurface.hpp @@ -13,7 +13,7 @@ namespace SDLUtil /// Convert an osg::Image to an SDL_Surface. /// @note The returned surface must be freed using SDL_FreeSurface. - SDL_Surface* imageToSurface(osg::Image* image); + SDL_Surface* imageToSurface(osg::Image* image, bool flip=false); } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp new file mode 100644 index 0000000000..b8ae92c578 --- /dev/null +++ b/components/sdlutil/sdlcursormanager.cpp @@ -0,0 +1,182 @@ +#include "sdlcursormanager.hpp" + +#include + +#include +#include + +#include +#include +#include + +#include "imagetosurface.hpp" + +namespace +{ + + class MyGraphicsContext { + public: + MyGraphicsContext(int w, int h) + { + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->x = 0; + traits->y = 0; + traits->width = 1;//w; + traits->height = 1;//h; + traits->windowDecoration = false; + traits->doubleBuffer = false; + traits->sharedContext = 0; + traits->pbuffer = true; + + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + + if (!_gc) + { + osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<pbuffer = false; + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + } + + if (_gc.valid()) + { + _gc->realize(); + _gc->makeCurrent(); + } + } + + osg::ref_ptr getContext() + { + return _gc; + } + + bool valid() const { return _gc.valid() && _gc->isRealized(); } + + private: + osg::ref_ptr _gc; + }; + + osg::ref_ptr decompress (osg::ref_ptr source) + { + int width = source->s(); + int height = source->t(); + + MyGraphicsContext context(width, height); + + osg::ref_ptr state = context.getContext()->getState(); + + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(source); + + state->applyTextureAttribute(0, texture); + + osg::ref_ptr resultImage = new osg::Image; + resultImage->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + + assert(resultImage->isDataContiguous()); + + // FIXME: implement for GL ES (PBO & glMapBufferRange?) + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + + source->releaseGLObjects(); + texture->releaseGLObjects(); + + return resultImage; + } + +} + +namespace SDLUtil +{ + + SDLCursorManager::SDLCursorManager() : + mEnabled(false), + mInitialized(false) + { + } + + SDLCursorManager::~SDLCursorManager() + { + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + } + + void SDLCursorManager::setEnabled(bool enabled) + { + if(mInitialized && enabled == mEnabled) + return; + + mInitialized = true; + mEnabled = enabled; + + //turn on hardware cursors + if(enabled) + { + _setGUICursor(mCurrentCursor); + } + //turn off hardware cursors + else + { + SDL_ShowCursor(SDL_FALSE); + } + } + + bool SDLCursorManager::cursorChanged(const std::string& name) + { + mCurrentCursor = name; + + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + _setGUICursor(name); + + return false; + } + else + { + //they should get back to us with more info + return true; + } + } + + void SDLCursorManager::_setGUICursor(const std::string &name) + { + SDL_SetCursor(mCursorMap.find(name)->second); + } + + void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); + } + + void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + if (mCursorMap.find(name) != mCursorMap.end()) + return; + + osg::ref_ptr decompressed = decompress(image); + + // TODO: rotate + + SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, false); + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + //clean up + SDL_FreeSurface(surf); + + _setGUICursor(name); + } + +} diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp new file mode 100644 index 0000000000..646f548e3c --- /dev/null +++ b/components/sdlutil/sdlcursormanager.hpp @@ -0,0 +1,51 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLCURSORMANAGER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLCURSORMANAGER_H + +#include +#include + +#include + +struct SDL_Cursor; +struct SDL_Surface; + +namespace osg +{ + class Image; +} + +namespace SDLUtil +{ + class SDLCursorManager + { + public: + SDLCursorManager(); + virtual ~SDLCursorManager(); + + /// \brief sets whether to actively manage cursors or not + virtual void setEnabled(bool enabled); + + /// \brief Tell the manager that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the manager is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name); + + /// \brief Follow up a cursorChanged() call with enough info to create an cursor. + virtual void receiveCursorInfo(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + + private: + void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + + void _setGUICursor(const std::string& name); + + typedef std::map CursorMap; + CursorMap mCursorMap; + + std::string mCurrentCursor; + bool mEnabled; + bool mInitialized; + }; +} + +#endif diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index c69fcca642..f16c0bca4d 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -102,7 +102,7 @@ void GraphicsWindowSDL2::init() return; } - setSyncToVBlank(_traits->vsync); + SDL_GL_SetSwapInterval(_traits->vsync ? 1 : 0); SDL_GL_MakeCurrent(oldWin, oldCtx); @@ -182,7 +182,14 @@ void GraphicsWindowSDL2::swapBuffersImplementation() void GraphicsWindowSDL2::setSyncToVBlank(bool on) { + SDL_Window *oldWin = SDL_GL_GetCurrentWindow(); + SDL_GLContext oldCtx = SDL_GL_GetCurrentContext(); + + SDL_GL_MakeCurrent(mWindow, mContext); + SDL_GL_SetSwapInterval(on ? 1 : 0); + + SDL_GL_MakeCurrent(oldWin, oldCtx); } void GraphicsWindowSDL2::raiseWindow() diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 44492cf6c9..eb3370cf7f 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -82,10 +82,20 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v case SDL_KEYDOWN: if (!evt.key.repeat) mKeyboardListener->keyPressed(evt.key); + + // temporary for the stats viewer + if (evt.key.keysym.sym == SDLK_s) + mViewer->getEventQueue()->keyPress('s'); + break; case SDL_KEYUP: if (!evt.key.repeat) mKeyboardListener->keyReleased(evt.key); + + // temporary for the stats viewer + if (evt.key.keysym.sym == SDLK_s) + mViewer->getEventQueue()->keyRelease('s'); + break; case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt deleted file mode 100644 index b8c56bd000..0000000000 --- a/extern/sdl4ogre/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -set(SDL4OGRE_LIBRARY "sdl4ogre") - -# Sources - -set(SDL4OGRE_SOURCE_FILES - sdlinputwrapper.cpp - sdlcursormanager.cpp - sdlwindowhelper.cpp - imagerotate.cpp -) - -if (APPLE) - set(SDL4OGRE_SOURCE_FILES ${SDL4OGRE_SOURCE_FILES} osx_utils.mm) -endif () - -set(SDL4OGRE_HEADER_FILES - OISCompat.h - cursormanager.hpp - events.h -) - -add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES} ${SDL4OGRE_HEADER_FILES}) - -link_directories(${CMAKE_CURRENT_BINARY_DIR}) - - -target_link_libraries(${SDL4OGRE_LIBRARY} ${SDL2_LIBRARY}) diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp deleted file mode 100644 index 3036b236be..0000000000 --- a/extern/sdl4ogre/cursormanager.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SDL4OGRE_CURSOR_MANAGER_H -#define SDL4OGRE_CURSOR_MANAGER_H - -#include -#include - -#include -#include - -namespace SFO -{ -class CursorManager -{ -public: - virtual ~CursorManager(){} - - /// \brief Tell the manager that the cursor has changed, giving the - /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the manager is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name) = 0; - - /// \brief Follow up a cursorChanged() call with enough info to create an cursor. - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; - - /// \brief sets whether to actively manage cursors or not - virtual void setEnabled(bool enabled) = 0; -}; -} - -#endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp deleted file mode 100644 index 61d9c32dd6..0000000000 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "sdlcursormanager.hpp" - -#include -#include -#include - -#include -#include - -#include "imagerotate.hpp" - -namespace SFO -{ - - SDLCursorManager::SDLCursorManager() : - mEnabled(false), - mInitialized(false) - { - } - - SDLCursorManager::~SDLCursorManager() - { - CursorMap::const_iterator curs_iter = mCursorMap.begin(); - - while(curs_iter != mCursorMap.end()) - { - SDL_FreeCursor(curs_iter->second); - ++curs_iter; - } - - mCursorMap.clear(); - } - - void SDLCursorManager::setEnabled(bool enabled) - { - if(mInitialized && enabled == mEnabled) - return; - - mInitialized = true; - mEnabled = enabled; - - //turn on hardware cursors - if(enabled) - { - _setGUICursor(mCurrentCursor); - } - //turn off hardware cursors - else - { - SDL_ShowCursor(SDL_FALSE); - } - } - - bool SDLCursorManager::cursorChanged(const std::string &name) - { - mCurrentCursor = name; - - CursorMap::const_iterator curs_iter = mCursorMap.find(name); - - //we have this cursor - if(curs_iter != mCursorMap.end()) - { - _setGUICursor(name); - - return false; - } - else - { - //they should get back to us with more info - return true; - } - } - - void SDLCursorManager::_setGUICursor(const std::string &name) - { - SDL_SetCursor(mCursorMap.find(name)->second); - } - - void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - _createCursorFromResource(name, rotDegrees, tex, size_x, size_y, hotspot_x, hotspot_y); - } - - /// \brief creates an SDL cursor from an Ogre texture - void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - if (mCursorMap.find(name) != mCursorMap.end()) - return; - - std::string tempName = tex->getName() + "_rotated"; - - // we use a render target to uncompress the DDS texture - // just blitting doesn't seem to work on D3D9 - ImageRotate::rotate(tex->getName(), tempName, static_cast(-rotDegrees)); - - Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); - - // now blit to memory - Ogre::Image destImage; - resultTexture->convertToImage(destImage); - - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < size_x; ++x) - { - for(size_t y = 0; y < size_y; ++y) - { - Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, static_cast(clr.r * 255), - static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255))); - } - } - - //set the cursor and store it for later - SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); - mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - - //clean up - SDL_FreeSurface(surf); - Ogre::TextureManager::getSingleton().remove(tempName); - - _setGUICursor(name); - } - - void SDLCursorManager::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) - { - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } -} diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp deleted file mode 100644 index 58324fc01c..0000000000 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SDL4OGRE_CURSORMANAGER_H -#define SDL4OGRE_CURSORMANAGER_H - -#include "cursormanager.hpp" -#include - -struct SDL_Cursor; -struct SDL_Surface; - -namespace SFO -{ - class SDLCursorManager : - public CursorManager - { - public: - SDLCursorManager(); - virtual ~SDLCursorManager(); - - virtual void setEnabled(bool enabled); - - virtual bool cursorChanged(const std::string &name); - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - - private: - void _createCursorFromResource(const std::string &name, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); - - void _setGUICursor(const std::string& name); - - typedef std::map CursorMap; - CursorMap mCursorMap; - - std::string mCurrentCursor; - bool mEnabled; - bool mInitialized; - }; -} - -#endif From c775cbbbaa4cd8dc650f11b3e2b1e324324612fd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 00:40:51 +0200 Subject: [PATCH 0251/1812] Silence an annoying message --- components/sdlutil/sdlgraphicswindow.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp index b2b7cfaf0d..4b48b40732 100644 --- a/components/sdlutil/sdlgraphicswindow.hpp +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -66,6 +66,12 @@ public: /** Set mouse cursor to a specific shape.*/ virtual void setCursor(MouseCursor cursor); + /** Get focus.*/ + virtual void grabFocus() {} + + /** Get focus on if the pointer is in this window.*/ + virtual void grabFocusIfPointerInWindow() {} + /** WindowData is used to pass in the SDL2 window handle attached to the GraphicsContext::Traits structure. */ struct WindowData : public osg::Referenced { From 5dd1b2ae860c9ba6eb83b72c232945b03dddd3df Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:04:34 +0200 Subject: [PATCH 0252/1812] Readded HW cursor rotation --- components/sdlutil/sdlcursormanager.cpp | 54 ++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b8ae92c578..9a7c2aa761 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "imagetosurface.hpp" @@ -21,8 +22,12 @@ namespace osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->x = 0; traits->y = 0; - traits->width = 1;//w; - traits->height = 1;//h; + traits->width = w; + traits->height = h; + traits->red = 8; + traits->green = 8; + traits->blue = 8; + traits->alpha = 8; traits->windowDecoration = false; traits->doubleBuffer = false; traits->sharedContext = 0; @@ -56,7 +61,7 @@ namespace osg::ref_ptr _gc; }; - osg::ref_ptr decompress (osg::ref_ptr source) + osg::ref_ptr decompress (osg::ref_ptr source, float rotDegrees) { int width = source->s(); int height = source->t(); @@ -67,17 +72,50 @@ namespace osg::ref_ptr texture = new osg::Texture2D; texture->setImage(source); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER); + texture->setBorderColor(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + osg::ref_ptr texmat = new osg::TexMat; + osg::Matrix texRot (osg::Matrix::identity()); + float theta ( osg::DegreesToRadians(-rotDegrees) ); + float cosTheta = std::cos(theta); + float sinTheta = std::sin(theta); + + texRot(0,0) = cosTheta; + texRot(1,0) = -sinTheta; + texRot(0,1) = sinTheta; + texRot(1,1) = cosTheta; + // Offset center of rotation to center of texture + texRot(3,0) = 0.5f + ( (-0.5f * cosTheta) - (-0.5f * sinTheta) ); + texRot(3,1) = 0.5f + ( (-0.5f * sinTheta) + (-0.5f * cosTheta) ); + + texmat->setMatrix(texRot); + + state->applyTextureAttribute(0, texmat); + + osg::ref_ptr identity (new osg::RefMatrix(osg::Matrix::identity())); + state->applyModelViewMatrix(identity); + state->applyProjectionMatrix(identity); + + state->applyMode(GL_TEXTURE_2D, true); state->applyTextureAttribute(0, texture); osg::ref_ptr resultImage = new osg::Image; resultImage->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); - assert(resultImage->isDataContiguous()); + osg::RenderInfo renderInfo; + renderInfo.setState(state); - // FIXME: implement for GL ES (PBO & glMapBufferRange?) - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + glViewport(0, 0, width, height); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + geom->drawImplementation(renderInfo); + + // TODO: implement for GL ES + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); + + geom->releaseGLObjects(); source->releaseGLObjects(); texture->releaseGLObjects(); @@ -163,9 +201,7 @@ namespace SDLUtil if (mCursorMap.find(name) != mCursorMap.end()) return; - osg::ref_ptr decompressed = decompress(image); - - // TODO: rotate + osg::ref_ptr decompressed = decompress(image, static_cast(rotDegrees)); SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, false); From fd3d49c1717b105070071e46bb80bab6898ac74e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:18:24 +0200 Subject: [PATCH 0253/1812] Fix typo in settings layout --- files/mygui/openmw_settings_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index cc9c3d1dc7..768652e1a0 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -175,7 +175,7 @@ - + From a18663c8b3b9d3a59721e745d85a30413982a755 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:26:10 +0200 Subject: [PATCH 0254/1812] Improve MyGUI texture updates --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ---- components/myguiplatform/myguitexture.cpp | 16 +++++++++++++--- components/myguiplatform/myguitexture.hpp | 2 -- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5e573c1e4b..3bedb5d5e0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1098,11 +1098,7 @@ namespace MWGui else if (it->first == "GUI" && it->second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); else if (it->first == "GUI" && it->second == "menu transparency") - { - mViewer->stopThreading(); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); - mViewer->startThreading(); - } } } diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 7de7ebfb0c..68408dd3a9 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -141,11 +141,21 @@ namespace osgMyGUI if (!mLockedImage.valid()) throw std::runtime_error("Texture not locked"); + // mTexture might be in use by the draw thread, so create a new texture instead and use that. + osg::ref_ptr newTexture = new osg::Texture2D; + newTexture->setTextureSize(getWidth(), getHeight()); + newTexture->setSourceFormat(mTexture->getSourceFormat()); + newTexture->setSourceType(mTexture->getSourceType()); + newTexture->setFilter(osg::Texture::MIN_FILTER, mTexture->getFilter(osg::Texture::MIN_FILTER)); + newTexture->setFilter(osg::Texture::MAG_FILTER, mTexture->getFilter(osg::Texture::MAG_FILTER)); + newTexture->setWrap(osg::Texture::WRAP_S, mTexture->getWrap(osg::Texture::WRAP_S)); + newTexture->setWrap(osg::Texture::WRAP_T, mTexture->getWrap(osg::Texture::WRAP_T)); + newTexture->setImage(mLockedImage.get()); // Tell the texture it can get rid of the image for static textures (since // they aren't expected to update much at all). - mTexture->setImage(mLockedImage.get()); - mTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); - mTexture->dirtyTextureObject(); + newTexture->setUnRefImageDataAfterApply(mUsage.isValue(MyGUI::TextureUsage::Static) ? true : false); + + mTexture = newTexture; mLockedImage = nullptr; } diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index 109858bc8b..de385e94d6 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -42,8 +42,6 @@ namespace osgMyGUI virtual void destroy(); - /// @warning If you intend to change a texture during the frame update, you must either declare the texture with DataVariance::DYNAMIC - /// or temporarily stop the viewer threading, to prevent race conditions with the draw thread. virtual void* lock(MyGUI::TextureUsage access); virtual void unlock(); virtual bool isLocked(); From 4dd96f33188fac381d9f8a28a834680b92c789f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 01:32:46 +0200 Subject: [PATCH 0255/1812] Fix missing tiling in skin --- files/mygui/openmw_windows.skin.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 2854401c89..ca95a552bb 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -151,14 +151,22 @@ - - + + + + + + - - + + + + + + From e3b1707bbd26f2ad33fbc263c11a6fc4b2810ba8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 02:24:15 +0200 Subject: [PATCH 0256/1812] Pause simulationTime when the GUI is up --- apps/openmw/engine.cpp | 10 +++++++--- apps/openmw/engine.hpp | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 403cb79f28..f9bb297a9d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -73,7 +73,7 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::frame(float frametime) +double OMW::Engine::frame(float frametime) { try { @@ -94,6 +94,8 @@ void OMW::Engine::frame(float frametime) // GUI active? Most game processing will be paused, but scripts still run. bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if (!guiActive) + mSimulationTime += frametime; // Main menu opened? Then scripts are also paused. bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); @@ -182,6 +184,7 @@ void OMW::Engine::frame(float frametime) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } + return mSimulationTime; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -203,6 +206,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mScriptBlacklistUse (true) , mNewGame (false) , mCfgMgr(configurationManager) + , mSimulationTime(0.0) { Misc::Rng::init(); MWClass::registerClasses(); @@ -587,8 +591,8 @@ void OMW::Engine::go() frameTimer.setStartTick(); //dt = std::min(dt, 0.2); - frame(dt); - mViewer->frame(/*simulationTime*/); + double simulationTime = frame(dt); + mViewer->frame(simulationTime); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index bb70c288d8..8b792c5a89 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -100,6 +100,7 @@ namespace OMW bool mNewGame; osg::Timer_t mStartTick; + double mSimulationTime; // not implemented Engine (const Engine&); @@ -107,7 +108,8 @@ namespace OMW void executeLocalScripts(); - void frame (float dt); + /// @return The new simulationTime + double frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From b6cb73e6e8d5c513a72bd36a43c4f163e8269e2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 15:07:58 +0200 Subject: [PATCH 0257/1812] Fix deep copying of controllers This fixes the cell loading crash. --- components/sceneutil/clone.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 862a070d8f..237417974e 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -27,7 +27,7 @@ namespace SceneUtil if (!stateset) return NULL; if (stateset->getDataVariance() == osg::StateSet::DYNAMIC) - return osg::clone(stateset, osg::CopyOp::DEEP_COPY_STATESETS); + return osg::clone(stateset, *this); return const_cast(stateset); } @@ -37,7 +37,7 @@ namespace SceneUtil return operator()(processor); if (const osgParticle::ParticleSystemUpdater* updater = dynamic_cast(node)) { - osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, osg::CopyOp::DEEP_COPY_NODES); + osgParticle::ParticleSystemUpdater* cloned = osg::clone(updater, *this); mMap2[cloned] = updater->getParticleSystem(0); return cloned; } @@ -50,21 +50,26 @@ namespace SceneUtil return operator()(partsys); if (dynamic_cast(drawable) || dynamic_cast(drawable)) - return osg::clone(drawable, osg::CopyOp::DEEP_COPY_DRAWABLES); + { + osg::Drawable* cloned = osg::clone(drawable, *this); + if (cloned->getUpdateCallback()) + cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); + return cloned; + } return osg::CopyOp::operator()(drawable); } osgParticle::ParticleProcessor* CopyOp::operator() (const osgParticle::ParticleProcessor* processor) const { - osgParticle::ParticleProcessor* cloned = osg::clone(processor, osg::CopyOp::DEEP_COPY_NODES); + osgParticle::ParticleProcessor* cloned = osg::clone(processor, *this); mMap[cloned] = processor->getParticleSystem(); return cloned; } osgParticle::ParticleSystem* CopyOp::operator ()(const osgParticle::ParticleSystem* partsys) const { - osgParticle::ParticleSystem* cloned = osg::clone(partsys, osg::CopyOp::DEEP_COPY_DRAWABLES); + osgParticle::ParticleSystem* cloned = osg::clone(partsys, *this); for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) { From 4ad0b83aa5ecfaf904da8a480b54fa898159cca8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 16:33:41 +0200 Subject: [PATCH 0258/1812] Eliminate string lookups in AnimationTime --- apps/openmw/mwrender/animation.cpp | 73 ++++++++++++++---------------- apps/openmw/mwrender/animation.hpp | 26 +++++++---- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 888846789b..c0cddb4d09 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -326,7 +326,7 @@ namespace MWRender mStates.clear(); for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i]->setAnimName(std::string()); + mAnimationTimePtr[i]->setTimePtr(boost::shared_ptr()); mAccumCtrl = NULL; @@ -433,32 +433,32 @@ namespace MWRender state.mSource = *iter; state.mSpeedMult = speedmult; state.mLoopCount = loops; - state.mPlaying = (state.mTime < state.mStopTime); + state.mPlaying = (state.getTime() < state.mStopTime); state.mPriority = priority; state.mGroups = groups; state.mAutoDisable = autodisable; mStates[groupname] = state; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); if (state.mPlaying) { - while(textkey != textkeys.end() && textkey->first <= state.mTime) + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); ++textkey; } } - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) { state.mLoopCount--; - state.mTime = state.mLoopStartTime; + state.setTime(state.mLoopStartTime); state.mPlaying = true; - if(state.mTime >= state.mLoopStopTime) + if(state.getTime() >= state.mLoopStopTime) break; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); ++textkey; @@ -527,11 +527,11 @@ namespace MWRender } state.mStopTime = stopkey->first; - state.mTime = state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint); + state.setTime(state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint)); // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.mTime > state.mStartTime) + if(state.getTime() > state.mStartTime) { const std::string loopstarttag = groupname+": loop start"; const std::string loopstoptag = groupname+": loop stop"; @@ -539,7 +539,7 @@ namespace MWRender NifOsg::TextKeyMap::const_reverse_iterator key(groupend); for (; key != startkey && key != keys.rend(); ++key) { - if (key->first > state.mTime) + if (key->first > state.getTime()) continue; if (key->second == loopstarttag) @@ -587,8 +587,7 @@ namespace MWRender active = state; } - mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ? - std::string() : active->first); + mAnimationTimePtr[grp]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); // add external controllers for the AnimSource active in this group if (active != mStates.end()) @@ -671,7 +670,7 @@ namespace MWRender if(complete) { if(iter->second.mStopTime > iter->second.mStartTime) - *complete = (iter->second.mTime - iter->second.mStartTime) / + *complete = (iter->second.getTime() - iter->second.mStartTime) / (iter->second.mStopTime - iter->second.mStartTime); else *complete = (iter->second.mPlaying ? 0.0f : 1.0f); @@ -686,7 +685,7 @@ namespace MWRender if(iter == mStates.end()) return -1.f; - return iter->second.mTime; + return iter->second.getTime(); } void Animation::disable(const std::string &groupname) @@ -767,54 +766,54 @@ namespace MWRender { AnimState &state = stateiter->second; const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); - NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.mTime)); + NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.getTime())); float timepassed = duration * state.mSpeedMult; while(state.mPlaying) { float targetTime; - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) goto handle_loop; - targetTime = state.mTime + timepassed; + targetTime = state.getTime() + timepassed; if(textkey == textkeys.end() || textkey->first > targetTime) { - if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, targetTime, movement); - state.mTime = std::min(targetTime, state.mStopTime); + if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr()) + updatePosition(state.getTime(), targetTime, movement); + state.setTime(std::min(targetTime, state.mStopTime)); } else { - if(mAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - updatePosition(state.mTime, textkey->first, movement); - state.mTime = textkey->first; + if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr()) + updatePosition(state.getTime(), textkey->first, movement); + state.setTime(textkey->first); } - state.mPlaying = (state.mTime < state.mStopTime); - timepassed = targetTime - state.mTime; + state.mPlaying = (state.getTime() < state.mStopTime); + timepassed = targetTime - state.getTime(); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); ++textkey; } - if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) + if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) { handle_loop: state.mLoopCount--; - state.mTime = state.mLoopStartTime; + state.setTime(state.mLoopStartTime); state.mPlaying = true; - textkey = textkeys.lower_bound(state.mTime); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + textkey = textkeys.lower_bound(state.getTime()); + while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); ++textkey; } - if(state.mTime >= state.mLoopStopTime) + if(state.getTime() >= state.mLoopStopTime) break; } @@ -1090,11 +1089,9 @@ namespace MWRender float Animation::AnimationTime::getValue(osg::NodeVisitor*) { - // FIXME: hold a pointer instead of searching every frame - AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName); - if(iter != mAnimation->mStates.end()) - return iter->second.mTime; - return 0.0f; + if (mTimePtr) + return *mTimePtr; + return 0.f; } float EffectAnimationTime::getValue(osg::NodeVisitor*) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 81f0447075..3426094c83 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -62,17 +62,17 @@ protected: { private: Animation *mAnimation; - std::string mAnimationName; + boost::shared_ptr mTimePtr; public: AnimationTime(Animation *anim) : mAnimation(anim) { } - void setAnimName(const std::string &name) - { mAnimationName = name; } - const std::string &getAnimName() const - { return mAnimationName; } + void setTimePtr(boost::shared_ptr time) + { mTimePtr = time; } + boost::shared_ptr getTimePtr() const + { return mTimePtr; } virtual float getValue(osg::NodeVisitor* nv); }; @@ -104,7 +104,8 @@ protected: float mLoopStopTime; float mStopTime; - float mTime; + typedef boost::shared_ptr TimePtr; + TimePtr mTime; float mSpeedMult; bool mPlaying; @@ -115,9 +116,18 @@ protected: bool mAutoDisable; AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), - mTime(0.0f), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), + mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), mPriority(0), mGroups(0), mAutoDisable(true) - { } + { + } + float getTime() const + { + return *mTime; + } + void setTime(float time) + { + *mTime = time; + } }; typedef std::map AnimStateMap; AnimStateMap mStates; From bc237ee1fe95a841d84d317f4bd078f55ad6714c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 17:14:49 +0200 Subject: [PATCH 0259/1812] Actor placement fix --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6c7fd6ff38..1ee9586aec 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1321,7 +1321,7 @@ namespace MWWorld return; } - float terrainHeight = 0;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = -FLT_MAX;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; From b7258c8d234751e3aac2f048e3c90e1a681a575c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 17:34:55 +0200 Subject: [PATCH 0260/1812] Readded Objects::updatePtr --- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 11 +++++++++++ apps/openmw/mwrender/npcanimation.hpp | 4 ++++ apps/openmw/mwrender/objects.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 2 +- 8 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3426094c83..a12375a9b9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -274,7 +274,7 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out); - void updatePtr(const MWWorld::Ptr &ptr); + virtual void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 26f05e35f5..2bb1b66fdd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -76,6 +76,11 @@ HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) resetBlinkTimer(); } +void HeadAnimationTime::updatePtr(const MWWorld::Ptr &updated) +{ + mReference = updated; +} + void HeadAnimationTime::setEnabled(bool enabled) { mEnabled = enabled; @@ -901,6 +906,12 @@ void NpcAnimation::setVampire(bool vampire) } } +void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) +{ + Animation::updatePtr(updated); + mHeadAnimationTime->updatePtr(updated); +} + /* void NpcAnimation::setHeadPitch(Ogre::Radian pitch) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 0c91dfe6eb..a58f0fdf33 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -34,6 +34,8 @@ private: public: HeadAnimationTime(MWWorld::Ptr reference); + void updatePtr(const MWWorld::Ptr& updated); + void update(float dt); void setEnabled(bool enabled); @@ -176,6 +178,8 @@ public: virtual void setAlpha(float alpha); virtual void setVampire(bool vampire); + + virtual void updatePtr(const MWWorld::Ptr& updated); }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 17fbbe5494..5face96a6e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -198,30 +198,33 @@ void Objects::removeCell(const MWWorld::CellStore* store) } } -void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) +void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { - /* - Ogre::SceneNode *node; MWWorld::CellStore *newCell = cur.getCell(); + osg::Group* cellnode; if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { - node = mRootNode->createChildSceneNode(); - mCellSceneNodes[newCell] = node; + cellnode = new osg::Group; + mRootNode->addChild(cellnode); + mCellSceneNodes[newCell] = cellnode; } else { - node = mCellSceneNodes[newCell]; + cellnode = mCellSceneNodes[newCell]; } - node->addChild(cur.getRefData().getBaseNode()); + osg::Node* objectNode = cur.getRefData().getBaseNode(); + + if (objectNode->getNumParents()) + objectNode->getParent(0)->removeChild(objectNode); + cellnode->addChild(objectNode); PtrAnimationMap::iterator iter = mObjects.find(old); if(iter != mObjects.end()) { - ObjectAnimation *anim = iter->second; + Animation *anim = iter->second; mObjects.erase(iter); anim->updatePtr(cur); mObjects[cur] = anim; } - */ } Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e920869b90..3e1af60873 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -72,7 +72,7 @@ public: void removeCell(const MWWorld::CellStore* store); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); + void updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); private: void operator = (const Objects&); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c9bf220099..49e6ba06fa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -271,6 +271,11 @@ namespace MWRender ptr.getRefData().getBaseNode()->setScale(scale); } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + mObjects->updatePtr(old, updated); + } + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) { mEffectManager->addEffect(model, texture, worldPosition, scale); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0dc0fe571e..7d902b8545 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -62,6 +62,8 @@ namespace MWRender void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); + void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + // TODO rename to setRotation/setPosition/setScale, along with the World equivalents void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1ee9586aec..32eb92d2af 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1181,7 +1181,7 @@ namespace MWWorld MWWorld::Ptr copy = ptr.getClass().copyToCell(ptr, *newCell, pos); - //mRendering->updateObjectCell(ptr, copy); + mRendering->updatePtr(ptr, copy); ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); mPhysics->updatePtr(ptr, copy); From 3e86dd7df0f757a8f59a91ef4a3bb3af6a49b51d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 18:46:04 +0200 Subject: [PATCH 0261/1812] Apply runtime changes to field of view & view distance --- apps/openmw/mwrender/renderingmanager.cpp | 42 ++++++++++++++++++----- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++ apps/openmw/mwworld/worldimp.cpp | 2 +- files/settings-default.cfg | 3 ++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 49e6ba06fa..7822ccb30d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -128,8 +128,10 @@ namespace MWRender osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; - // for consistent benchmarks against the ogre branch. remove later - cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + if (!Settings::Manager::getBool("small feature culling", "Viewing distance")) + cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); + else + cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; viewer.getCamera()->setCullingMode( cullingMode ); @@ -137,13 +139,8 @@ namespace MWRender mViewer.getCamera()->setCullingMode(cullingMode); mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); - - double fovy, aspect, zNear, zFar; - mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - fovy = 55.f; - zNear = 5.f; - zFar = mViewDistance; - mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + updateProjectionMatrix(); } RenderingManager::~RenderingManager() @@ -325,4 +322,31 @@ namespace MWRender //mWater->addEmitter(ptr); } + void RenderingManager::updateProjectionMatrix() + { + double fovy, aspect, zNear, zFar; + mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + fovy = mFieldOfView; + zNear = 5.f; + zFar = mViewDistance; + mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) + { + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) + { + if (it->first == "General" && it->second == "field of view") + { + mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + updateProjectionMatrix(); + } + else if (it->first == "Viewing distance" && it->second == "viewing distance") + { + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + updateProjectionMatrix(); + } + } + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7d902b8545..b13dffb8ca 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "objects.hpp" #include "renderinginterface.hpp" @@ -93,7 +95,11 @@ namespace MWRender void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); + void processChangedSettings(const Settings::CategorySettingVector& settings); + private: + void updateProjectionMatrix(); + osgViewer::Viewer& mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mLightRoot; @@ -111,6 +117,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; float mViewDistance; + float mFieldOfView; void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 32eb92d2af..bbd98be561 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1971,7 +1971,7 @@ namespace MWWorld void World::processChangedSettings(const Settings::CategorySettingVector& settings) { - //mRendering->processChangedSettings(settings); + mRendering->processChangedSettings(settings); } bool World::isFlying(const MWWorld::Ptr &ptr) const diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7f2185b62d..eeea0e6e18 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -132,6 +132,9 @@ fog start factor = 0.5 # Distance at which fog ends (proportional to viewing distance) fog end factor = 1.0 +# Culling of objects smaller than a pixel +small feature culling = true + [Terrain] distant land = false From 5442bf23a6e8fe16f2feefbf18877d13561590ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 20:31:16 +0200 Subject: [PATCH 0262/1812] Apply video mode & gamma setting changes --- apps/openmw/mwinput/inputmanagerimp.cpp | 35 ++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 5 ++ components/CMakeLists.txt | 2 +- components/sdlutil/sdlvideowrapper.cpp | 94 +++++++++++++++++++++++ components/sdlutil/sdlvideowrapper.hpp | 44 +++++++++++ files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 5 +- 7 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 components/sdlutil/sdlvideowrapper.cpp create mode 100644 components/sdlutil/sdlvideowrapper.hpp diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0fc25db4cf..6abd3c0c9d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../engine.hpp" @@ -101,10 +102,13 @@ namespace MWInput OMW::Engine& engine, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) - : mJoystickLastUsed(false) + : mWindow(window) + , mViewer(viewer) + , mJoystickLastUsed(false) , mPlayer(NULL) , mEngine(engine) , mInputManager(NULL) + , mVideoWrapper(NULL) , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) @@ -141,6 +145,10 @@ namespace MWInput mInputManager->setWindowEventCallback(this); mInputManager->setControllerEventCallback(this); + mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer); + mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), + Settings::Manager::getFloat("contrast", "Video")); + std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -201,6 +209,8 @@ namespace MWInput delete mInputBinder; delete mInputManager; + + delete mVideoWrapper; } void InputManager::setPlayerControlsEnabled(bool enabled) @@ -614,6 +624,8 @@ namespace MWInput void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) { + bool changeRes = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { @@ -629,6 +641,27 @@ namespace MWInput if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); + if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y" + || it->second == "fullscreen" + || it->second == "window border")) + changeRes = true; + + if (it->first == "Video" && it->second == "vsync") + mVideoWrapper->setSyncToVBlank(Settings::Manager::getBool("vsync", "Video")); + + if (it->first == "Video" && (it->second == "gamma" || it->second == "contrast")) + mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), + Settings::Manager::getFloat("contrast", "Video")); + } + + if (changeRes) + { + mVideoWrapper->setVideoMode(Settings::Manager::getInt("resolution x", "Video"), + Settings::Manager::getInt("resolution y", "Video"), + Settings::Manager::getBool("fullscreen", "Video"), + Settings::Manager::getBool("window border", "Video")); } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 27c08ed325..6b636058fe 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -48,6 +48,7 @@ namespace Files namespace SDLUtil { class InputWrapper; + class VideoWrapper; } namespace osgViewer @@ -151,6 +152,9 @@ namespace MWInput void clearAllControllerBindings (ICS::Control* control); private: + SDL_Window* mWindow; + osg::ref_ptr mViewer; + bool mJoystickLastUsed; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -158,6 +162,7 @@ namespace MWInput ICS::InputControlSystem* mInputBinder; SDLUtil::InputWrapper* mInputManager; + SDLUtil::VideoWrapper* mVideoWrapper; std::string mUserFile; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0c76f666b2..b800da701d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -127,7 +127,7 @@ add_component_dir (fontloader ) add_component_dir (sdlutil - sdlgraphicswindow imagetosurface sdlinputwrapper OISCompat events sdlcursormanager + sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper OISCompat events sdlcursormanager ) add_component_dir (version diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp new file mode 100644 index 0000000000..dd89d10724 --- /dev/null +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -0,0 +1,94 @@ +#include "sdlvideowrapper.hpp" + +#include + +#include + +#include + +namespace SDLUtil +{ + + VideoWrapper::VideoWrapper(SDL_Window *window, osg::ref_ptr viewer) + : mWindow(window) + , mViewer(viewer) + , mGamma(1.f) + , mContrast(1.f) + , mHasSetGammaContrast(false) + { + SDL_GetWindowGammaRamp(mWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + } + + VideoWrapper::~VideoWrapper() + { + SDL_SetWindowFullscreen(mWindow, 0); + + // If user hasn't touched the defaults no need to restore + if (mHasSetGammaContrast) + SDL_SetWindowGammaRamp(mWindow, mOldSystemGammaRamp, &mOldSystemGammaRamp[256], &mOldSystemGammaRamp[512]); + } + + void VideoWrapper::setSyncToVBlank(bool sync) + { + osgViewer::Viewer::Windows windows; + mViewer->getWindows(windows); + mViewer->stopThreading(); + for (osgViewer::Viewer::Windows::iterator it = windows.begin(); it != windows.end(); ++it) + { + osgViewer::GraphicsWindow* win = *it; + win->setSyncToVBlank(sync); + } + mViewer->startThreading(); + } + + void VideoWrapper::setGammaContrast(float gamma, float contrast) + { + if (gamma == mGamma && contrast == mContrast) + return; + + mGamma = gamma; + mContrast = contrast; + + mHasSetGammaContrast = true; + + Uint16 red[256], green[256], blue[256]; + for (int i = 0; i < 256; i++) + { + float k = i/256.0f; + k = (k - 0.5f) * contrast + 0.5f; + k = pow(k, 1.f/gamma); + k *= 256; + float value = k*256; + if (value > 65535) value = 65535; + else if (value < 0) value = 0; + + red[i] = green[i] = blue[i] = static_cast(value); + } + if (SDL_SetWindowGammaRamp(mWindow, red, green, blue) < 0) + std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; + } + + void VideoWrapper::setVideoMode(int width, int height, bool fullscreen, bool windowBorder) + { + SDL_SetWindowFullscreen(mWindow, 0); + + if (SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MAXIMIZED) + SDL_RestoreWindow(mWindow); + + if (fullscreen) + { + SDL_DisplayMode mode; + SDL_GetWindowDisplayMode(mWindow, &mode); + mode.w = width; + mode.h = height; + SDL_SetWindowDisplayMode(mWindow, &mode); + SDL_SetWindowFullscreen(mWindow, fullscreen); + } + else + { + SDL_SetWindowSize(mWindow, width, height); + SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); + } + } + +} diff --git a/components/sdlutil/sdlvideowrapper.hpp b/components/sdlutil/sdlvideowrapper.hpp new file mode 100644 index 0000000000..77f0b80393 --- /dev/null +++ b/components/sdlutil/sdlvideowrapper.hpp @@ -0,0 +1,44 @@ +#ifndef OPENMW_COMPONENTS_SDLUTIL_SDLVIDEOWRAPPER_H +#define OPENMW_COMPONENTS_SDLUTIL_SDLVIDEOWRAPPER_H + +#include + +#include + +struct SDL_Window; + +namespace osgViewer +{ + class Viewer; +} + +namespace SDLUtil +{ + + class VideoWrapper + { + public: + VideoWrapper(SDL_Window* window, osg::ref_ptr viewer); + ~VideoWrapper(); + + void setSyncToVBlank(bool sync); + + void setGammaContrast(float gamma, float contrast); + + void setVideoMode(int width, int height, bool fullscreen, bool windowBorder); + + private: + SDL_Window* mWindow; + osg::ref_ptr mViewer; + + float mGamma; + float mContrast; + bool mHasSetGammaContrast; + + // Store system gamma ramp on window creation. Restore system gamma ramp on exit + Uint16 mOldSystemGammaRamp[256*3]; + }; + +} + +#endif diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 768652e1a0..397a9df04c 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -299,7 +299,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index eeea0e6e18..d28240f2c6 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -26,6 +26,9 @@ vsync = false # PBuffer, FBO, Copy opengl rtt mode = FBO +gamma = 1.00 +contrast = 1.00 + [GUI] # 1 is fully opaque menu transparency = 0.84 @@ -43,8 +46,6 @@ stretch menu background = false [General] # Camera field of view field of view = 55 -gamma = 1.00 -contrast = 1.00 # Texture filtering mode. valid values: # none From 24bb2e152cdd54b08b06b4c0b5b8b80f8f5f0ebc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 21:42:04 +0200 Subject: [PATCH 0263/1812] Apply texture filter setting changes --- apps/openmw/engine.cpp | 8 ++++- apps/openmw/mwgui/settingswindow.cpp | 8 ++--- apps/openmw/mwrender/renderingmanager.cpp | 40 ++++++++++++++++------- apps/openmw/mwrender/renderingmanager.hpp | 5 +-- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/resource/texturemanager.cpp | 21 ++++++++++++ components/resource/texturemanager.hpp | 7 +++- files/mygui/openmw_settings_window.layout | 1 - files/settings-default.cfg | 5 +-- 10 files changed, 72 insertions(+), 27 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f9bb297a9d..9fb233140a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -419,6 +419,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); + osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + if (Settings::Manager::getString("texture filtering", "General") == "trilinear") + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so @@ -469,7 +475,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } // Create the world - mEnvironment.setWorld( new MWWorld::World (*mViewer, rootNode, mResourceSystem.get(), + mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); MWBase::Environment::get().getWorld()->setupPlayer(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c23e2bb948..8ba46339ac 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -38,12 +38,10 @@ namespace std::string textureFilteringToStr(const std::string& val) { - if (val == "anisotropic") - return "Anisotropic"; - else if (val == "bilinear") - return "Bilinear"; - else + if (val == "trilinear") return "Trilinear"; + else + return "Bilinear"; } void parseResolution (int &x, int &y, const std::string& str) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7822ccb30d..7e742e7293 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -82,7 +83,7 @@ namespace MWRender float mFogEnd; }; - RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -97,13 +98,13 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); - mViewer.setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); + mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); - mObjects->setIncrementalCompileOperation(mViewer.getIncrementalCompileOperation()); + mObjects->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); - mViewer.setLightingMode(osgViewer::View::NO_LIGHT); + mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; mSunLight = new osg::Light; @@ -133,10 +134,10 @@ namespace MWRender else cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; - viewer.getCamera()->setCullingMode( cullingMode ); + mViewer->getCamera()->setCullingMode( cullingMode ); - mViewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); - mViewer.getCamera()->setCullingMode(cullingMode); + mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + mViewer->getCamera()->setCullingMode(cullingMode); mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); @@ -184,7 +185,7 @@ namespace MWRender osg::Vec3f RenderingManager::getEyePos() { - osg::Vec3d eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + osg::Vec3d eye = mViewer->getCameraManipulator()->getMatrix().getTrans(); return eye; } @@ -232,7 +233,7 @@ namespace MWRender void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) { - mViewer.getCamera()->setClearColor(colour); + mViewer->getCamera()->setClearColor(colour); mStateUpdater->setFogColor(colour); mStateUpdater->setFogEnd(mViewDistance); @@ -325,11 +326,26 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { double fovy, aspect, zNear, zFar; - mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = mFieldOfView; zNear = 5.f; zFar = mViewDistance; - mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + void RenderingManager::updateTextureFiltering() + { + osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + if (Settings::Manager::getString("texture filtering", "General") == "trilinear") + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + + mViewer->stopThreading(); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + mViewer->startThreading(); } void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) @@ -346,6 +362,8 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); updateProjectionMatrix(); } + else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) + updateTextureFiltering(); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b13dffb8ca..32e081995e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -45,7 +45,7 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); ~RenderingManager(); MWRender::Objects& getObjects(); @@ -99,8 +99,9 @@ namespace MWRender private: void updateProjectionMatrix(); + void updateTextureFiltering(); - osgViewer::Viewer& mViewer; + osg::ref_ptr mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mLightRoot; Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bbd98be561..91484a6ba7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -143,7 +143,7 @@ namespace MWWorld } World::World ( - osgViewer::Viewer& viewer, + osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 279d35329b..21ad2d7ef2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -162,7 +162,7 @@ namespace MWWorld public: World ( - osgViewer::Viewer& viewer, + osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const Files::Collections& fileCollections, diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index b9b9fad5fa..5f2ca19efd 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -36,6 +36,9 @@ namespace Resource TextureManager::TextureManager(const VFS::Manager *vfs) : mVFS(vfs) + , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) + , mMagFilter(osg::Texture::LINEAR) + , mMaxAnisotropy(1) , mWarningTexture(createWarningTexture()) , mUnRefImageDataAfterApply(false) { @@ -52,6 +55,21 @@ namespace Resource mUnRefImageDataAfterApply = unref; } + void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) + { + mMinFilter = minFilter; + mMagFilter = magFilter; + mMaxAnisotropy = std::max(1, maxAnisotropy); + + for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) + { + osg::ref_ptr tex = it->second; + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); + } + } + /* osg::ref_ptr TextureManager::getImage(const std::string &filename) { @@ -110,6 +128,9 @@ namespace Resource texture->setImage(image); texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); + texture->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + texture->setFilter(osg::Texture::MAG_FILTER, mMagFilter); + texture->setMaxAnisotropy(mMaxAnisotropy); texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 851a55166e..5ff233348d 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -23,7 +23,8 @@ namespace Resource TextureManager(const VFS::Manager* vfs); ~TextureManager(); - // TODO: texture filtering settings + /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! + void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, /// otherwise should be disabled to reduce memory usage. @@ -40,6 +41,10 @@ namespace Resource private: const VFS::Manager* mVFS; + osg::Texture::FilterMode mMinFilter; + osg::Texture::FilterMode mMagFilter; + int mMaxAnisotropy; + typedef std::pair, std::string> MapKey; std::map > mImages; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 397a9df04c..66514c886e 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -322,7 +322,6 @@ - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d28240f2c6..4ad2a323f8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,13 +48,10 @@ stretch menu background = false field of view = 55 # Texture filtering mode. valid values: -# none -# anisotropic # bilinear # trilinear -texture filtering = anisotropic +texture filtering = -# Has no effect when texture filtering is not anisotropic anisotropy = 4 # Number of texture mipmaps to generate From a73362f036ce4ae541acdcf54c3d296a366937ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 May 2015 21:45:18 +0200 Subject: [PATCH 0264/1812] Settings file cleanup --- files/settings-default.cfg | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4ad2a323f8..cbb3ff6b0d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -12,20 +12,11 @@ screen = 0 # Minimize the window if it loses key focus? minimize on focus loss = true -# Valid values: -# none -# MSAA 2 -# MSAA 4 -# MSAA 8 -# MSAA 16 -antialiasing = none +# Valid values: 0 for no antialiasing, or any power of two +antialiasing = 0 vsync = false -# opengl render to texture mode, valid options: -# PBuffer, FBO, Copy -opengl rtt mode = FBO - gamma = 1.00 contrast = 1.00 @@ -54,9 +45,6 @@ texture filtering = anisotropy = 4 -# Number of texture mipmaps to generate -num mipmaps = 8 - screenshot format = png [Shadows] From 842ff4d874da28bfa77a51093552c6fb761ffb06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 00:23:31 +0200 Subject: [PATCH 0265/1812] Catch exception for not found videos --- apps/openmw/mwgui/videowidget.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 2c9b1c97ef..d28ea0b660 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -30,7 +30,18 @@ void VideoWidget::playVideo(const std::string &video) { mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer->playVideo(mVFS->get(video), video); + Files::IStreamPtr videoStream; + try + { + videoStream = mVFS->get(video); + } + catch (std::exception& e) + { + std::cerr << "Failed to open video: " << e.what() << std::endl; + return; + } + + mPlayer->playVideo(videoStream, video); osg::ref_ptr texture = mPlayer->getVideoTexture(); if (!texture) From 49df07ea7f34c0aa952f53311bcc5e0c71198f1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 00:41:21 +0200 Subject: [PATCH 0266/1812] Implement UI scaling factor --- apps/openmw/mwgui/windowbase.cpp | 7 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++- apps/openmw/mwinput/inputmanagerimp.cpp | 56 +++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 8 ++- components/myguiplatform/myguiplatform.hpp | 4 +- .../myguiplatform/myguirendermanager.cpp | 40 ++----------- .../myguiplatform/myguirendermanager.hpp | 6 +- components/myguiplatform/myguitexture.cpp | 2 +- files/settings-default.cfg | 2 + 9 files changed, 61 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 8fdcf6b207..c3be3539e7 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,6 +1,7 @@ #include "windowbase.hpp" #include +#include #include @@ -48,11 +49,7 @@ void WindowBase::center() { // Centre dialog - // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - // Note by scrawl: The following works more reliably in the case when the window was _just_ - // resized and MyGUI RenderManager doesn't know about the new size yet - MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), - Settings::Manager::getInt("resolution y", "Video")); + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntCoord coord = mMainWidget->getCoord(); coord.left = (gameWindowSize.width - coord.width)/2; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3bedb5d5e0..aef37809b7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -182,7 +182,8 @@ namespace MWGui , mFPS(0.0f) , mFallbackMap(fallbackMap) { - mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager()); + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); mGuiPlatform->initialise(resourcePath, logpath); mGui = new MyGUI::Gui; @@ -1104,6 +1105,13 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { + mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y); + + // scaled size + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + x = viewSize.width; + y = viewSize.height; + sizeVideo(x, y); if (!mHud) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6abd3c0c9d..7a3dd5e18f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -123,8 +123,8 @@ namespace MWInput , mGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) - , mMouseX(0) - , mMouseY(0) + , mGuiCursorX(0) + , mGuiCursorY(0) , mMouseWheel(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) @@ -132,13 +132,8 @@ namespace MWInput , mSneaking(false) , mAttemptJump(false) , mFakeDeviceID(1) + , mInvUiScalingFactor(1.f) { - int w,h; - SDL_GetWindowSize(window, &w, &h); - - mMouseX = w / 2.f; - mMouseY = h / 2.f; - mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); @@ -193,6 +188,16 @@ namespace MWInput //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); } } + + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + if (uiScale != 0.f) + mInvUiScalingFactor = 1.f / uiScale; + + int w,h; + SDL_GetWindowSize(window, &w, &h); + + mGuiCursorX = mInvUiScalingFactor * w / 2.f; + mGuiCursorY = mInvUiScalingFactor * h / 2.f; } void InputManager::clear() @@ -394,7 +399,7 @@ namespace MWInput //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); } } @@ -406,7 +411,7 @@ namespace MWInput mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); if (mControlsDisabled) { @@ -430,15 +435,15 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX += xAxis * dt * 1500.0f; - mMouseY += yAxis * dt * 1500.0f; + mGuiCursorX += xAxis * dt * 1500.0f * mInvUiScalingFactor; + mGuiCursorY += yAxis * dt * 1500.0f * mInvUiScalingFactor; mMouseWheel -= static_cast(zAxis * dt * 1500.0f); - mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); - mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width))); + mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height))); - MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); - mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); + mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); } if (mMouseLookEnabled) { @@ -741,7 +746,7 @@ namespace MWInput if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -768,7 +773,7 @@ namespace MWInput mInputBinder->mouseReleased (arg, id); } else { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -786,19 +791,14 @@ namespace MWInput if (mGuiCursorEnabled) { - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX = static_cast(arg.x); - mMouseY = static_cast(arg.y); - - mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); - mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + mGuiCursorX = static_cast(arg.x) * mInvUiScalingFactor; + mGuiCursorY = static_cast(arg.y) * mInvUiScalingFactor; mMouseWheel = int(arg.z); - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); } if (mMouseLookEnabled && !mControlsDisabled) @@ -840,7 +840,7 @@ namespace MWInput guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); if(!mInputBinder->detectingBindingState()) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { @@ -872,7 +872,7 @@ namespace MWInput else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 6b636058fe..aec6407360 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -187,8 +187,8 @@ namespace MWInput float mOverencumberedMessageDelay; - float mMouseX; - float mMouseY; + float mGuiCursorX; + float mGuiCursorY; int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; @@ -198,7 +198,11 @@ namespace MWInput std::map mControlSwitch; + float mInvUiScalingFactor; + private: + void convertMousePosForMyGUI(int& x, int& y); + MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); virtual std::string sdlControllerAxisToString(int axis); diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index c0c9e0ce4f..513267c991 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -14,14 +14,14 @@ namespace osgMyGUI class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager) + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor) : mRenderManager(nullptr) , mDataManager(nullptr) , mLogManager(nullptr) , mLogFacility(nullptr) { mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); mDataManager = new DataManager(); } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 3caa61548e..e2f2f98206 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -40,37 +40,6 @@ } \ } while(0) -namespace -{ - -// Proxy to forward an OSG resize event to RenderManager::setViewSize -class ResizeHandler : public osgGA::GUIEventHandler { - osgMyGUI::RenderManager *mParent; - - virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) - { - if(ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) - { - int width = ea.getWindowWidth(); - int height = ea.getWindowHeight(); - mParent->setViewSize(width, height); - } - return false; - } - -public: - ResizeHandler(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } - ResizeHandler(const ResizeHandler ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osgGA::GUIEventHandler(copy, copyop) - , mParent(copy.mParent) - { } - - META_Object(osgMyGUI, ResizeHandler) -}; - -} - - namespace osgMyGUI { @@ -322,13 +291,16 @@ void OSGVertexBuffer::create() // --------------------------------------------------------------------------- -RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager) +RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor) : mViewer(viewer) , mSceneRoot(sceneroot) , mTextureManager(textureManager) , mUpdate(false) , mIsInitialise(false) + , mInvScalingFactor(1.f) { + if (scalingFactor != 0.f) + mInvScalingFactor = 1.f / scalingFactor; } RenderManager::~RenderManager() @@ -380,7 +352,6 @@ void RenderManager::initialise() mGuiRoot = camera; mSceneRoot->addChild(mGuiRoot.get()); - mViewer->addEventHandler(new ResizeHandler(this)); osg::ref_ptr vp = mViewer->getCamera()->getViewport(); setViewSize(vp->width(), vp->height()); @@ -458,7 +429,8 @@ void RenderManager::setViewSize(int width, int height) if(height < 1) height = 1; mGuiRoot->setViewport(0, 0, width, height); - mViewSize.set(width, height); + + mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor); mInfo.maximumDepth = 1; mInfo.hOffset = 0; diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index afb07eaa61..d9fdc1834a 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -46,15 +46,19 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget osg::ref_ptr mGuiRoot; + float mInvScalingFactor; + void destroyAllResources(); public: - RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager); + RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::TextureManager* textureManager, float scalingFactor); virtual ~RenderManager(); void initialise(); void shutdown(); + void setScalingFactor(float factor); + static RenderManager& getInstance() { return *getInstancePtr(); } static RenderManager* getInstancePtr() { return static_cast(MyGUI::RenderManager::getInstancePtr()); } diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 68408dd3a9..2a32dd9f31 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,7 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP, osg::Texture2D::CLAMP); + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index cbb3ff6b0d..fc8571bf86 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -21,6 +21,8 @@ gamma = 1.00 contrast = 1.00 [GUI] +scaling factor = 1.0 + # 1 is fully opaque menu transparency = 0.84 From b7fa64553009effbc4b6c0cab3838560396ed6bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 19:34:18 +0200 Subject: [PATCH 0267/1812] Don't destroy a NULL window --- apps/openmw/engine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9fb233140a..be873d09b8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -235,8 +235,11 @@ OMW::Engine::~Engine() mViewer = NULL; - SDL_DestroyWindow(mWindow); - mWindow = NULL; + if (mWindow) + { + SDL_DestroyWindow(mWindow); + mWindow = NULL; + } SDL_Quit(); } From 737c2114dcfb86110d8cddd6cef3a9f91a37ddd0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 19:43:48 +0200 Subject: [PATCH 0268/1812] Change viewer stats keybinding to F9 --- apps/openmw/engine.cpp | 1 + components/sdlutil/sdlinputwrapper.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index be873d09b8..ca21e36125 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -542,6 +542,7 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; osg::ref_ptr statshandler = new osgViewer::StatsHandler; + statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F9); statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index eb3370cf7f..1f47d53046 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -84,8 +84,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyPressed(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_s) - mViewer->getEventQueue()->keyPress('s'); + if (evt.key.keysym.sym == SDLK_F9) + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F9); break; case SDL_KEYUP: @@ -93,8 +93,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyReleased(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_s) - mViewer->getEventQueue()->keyRelease('s'); + if (evt.key.keysym.sym == SDLK_F9) + mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F9); break; case SDL_TEXTINPUT: From bec9abd319c866796f2c6ad9c1a4f4715466757e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 May 2015 23:21:29 +0200 Subject: [PATCH 0269/1812] Remove name extension for internal MyGUI textures Since they're no longer loaded from disk, the extension makes no sense. --- apps/openmw/mwgui/backgroundimage.cpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 14 +++++++------- files/mygui/openmw_screen_fader.layout | 2 +- files/mygui/openmw_windows.skin.xml | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index ee966c189c..98828a0411 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -14,7 +14,7 @@ void BackgroundImage::setBackgroundImage (const std::string& image, bool fixedRa } if (!stretch) { - setImageTexture("black.png"); + setImageTexture("black"); if (fixedRatio) mAspect = 4.0/3.0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f594cd43c2..dbc5130491 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -170,7 +170,7 @@ namespace MWGui // Use black background to correct aspect ratio mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default, "Menu"); - mVideoBackground->setImageTexture("black.png"); + mVideoBackground->setImageTexture("black"); mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d65e242def..4b37110715 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -222,7 +222,7 @@ namespace MWGui MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) + : "black" ) : ""); } } @@ -354,7 +354,7 @@ namespace MWGui if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) box->setImageTexture(image); else - box->setImageTexture("black.png"); + box->setImageTexture("black"); } } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index aef37809b7..0a9e867502 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -238,7 +238,7 @@ namespace MWGui mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default, "Overlay"); - mVideoBackground->setImageTexture("black.png"); + mVideoBackground->setImageTexture("black"); mVideoBackground->setVisible(false); mVideoBackground->setNeedMouseFocus(true); mVideoBackground->setNeedKeyFocus(true); @@ -309,14 +309,14 @@ namespace MWGui mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); - mBlindnessFader = new ScreenFader("black.png"); + mBlindnessFader = new ScreenFader("black"); std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available // TODO: check if non-BM versions actually use player_hit_01.dds if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) hitFaderTexture = "textures\\player_hit_01.dds"; mHitFader = new ScreenFader(hitFaderTexture); - mScreenFader = new ScreenFader("black.png"); + mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); @@ -1941,7 +1941,7 @@ namespace MWGui void WindowManager::createTextures() { { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) @@ -1955,7 +1955,7 @@ namespace MWGui } { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) @@ -1969,7 +1969,7 @@ namespace MWGui } { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent"); tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -1977,7 +1977,7 @@ namespace MWGui void WindowManager::setMenuTransparency(float value) { - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent.png"); + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent"); unsigned char* data = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); for (int x=0; x<8; ++x) for (int y=0; y<8; ++y) diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout index fffd2e66e3..13234792f7 100644 --- a/files/mygui/openmw_screen_fader.layout +++ b/files/mygui/openmw_screen_fader.layout @@ -2,6 +2,6 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ca95a552bb..e740383914 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -2,7 +2,7 @@ - + @@ -122,7 +122,7 @@ - + From 75ace9f8b51bb619c825f3fb8de2a1953dbe0b58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 May 2015 14:48:20 +0200 Subject: [PATCH 0270/1812] Global map base layer --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwgui/mapwindow.cpp | 40 +++++++++----------- apps/openmw/mwgui/mapwindow.hpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 60 +++++++++++++----------------- apps/openmw/mwrender/globalmap.hpp | 22 ++++++----- 5 files changed, 60 insertions(+), 69 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 95875de10b..7d66b2aba8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,10 +22,10 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw + bulletdebugdraw globalmap # camera # localmap occlusionquery water shadows -# characterpreview globalmap ripplesimulation refraction +# characterpreview ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4b37110715..a44c0214c4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,8 +1,9 @@ #include "mapwindow.hpp" -#include #include +#include + #include #include #include @@ -14,6 +15,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" @@ -559,6 +561,7 @@ namespace MWGui : WindowPinnableBase("openmw_map_window.layout") , NoDrop(drag, mMainWidget) , LocalMapBase(customMarkers) + , mGlobalMapTexture(NULL) , mGlobal(false) , mGlobalMap(0) //, mGlobalMapRender(0) @@ -708,19 +711,23 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { -#if 0 - mGlobalMapRender = new MWRender::GlobalMap(""); + mGlobalMapRender = new MWRender::GlobalMap(); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); -#endif + + mGlobalMapTexture = new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture()); + mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture); + mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + //mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); } MapWindow::~MapWindow() { - //delete mGlobalMapRender; + delete mGlobalMapTexture; + + delete mGlobalMapRender; } void MapWindow::setCellName(const std::string& cellName) @@ -730,7 +737,6 @@ namespace MWGui void MapWindow::addVisitedLocation(const std::string& name, int x, int y) { -#if 0 CellId cell; cell.first = x; cell.second = y; @@ -757,7 +763,6 @@ namespace MWGui markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); } -#endif } void MapWindow::cellExplored(int x, int y) @@ -769,12 +774,11 @@ namespace MWGui { LocalMapBase::onFrame(dt); -#if 0 for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { mGlobalMapRender->exploreCell(it->first, it->second); } -#endif + mQueuedToExplore.clear(); NoDrop::onFrame(dt); @@ -831,14 +835,12 @@ namespace MWGui void MapWindow::globalMapUpdatePlayer () { -#if 0 // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); - setGlobalMapPlayerPosition(pos.x, pos.y); + osg::Vec3f pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData().getPosition().asVec3(); + setGlobalMapPlayerPosition(pos.x(), pos.y()); } -#endif } void MapWindow::notifyPlayerUpdate () @@ -848,7 +850,6 @@ namespace MWGui void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) { -#if 0 float x, y; mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y); x *= mGlobalMapRender->getWidth(); @@ -860,7 +861,6 @@ namespace MWGui MyGUI::IntSize viewsize = mGlobalMap->getSize(); MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); -#endif } void MapWindow::setGlobalMapPlayerDir(const float x, const float y) @@ -876,7 +876,7 @@ namespace MWGui { mMarkers.clear(); - //mGlobalMapRender->clear(); + mGlobalMapRender->clear(); mChanged = true; while (mEventBoxGlobal->getChildCount()) @@ -885,7 +885,6 @@ namespace MWGui void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) { -#if 0 ESM::GlobalMap map; mGlobalMapRender->write(map); @@ -894,12 +893,10 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); -#endif } void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { -#if 0 if (type == ESM::REC_GMAP) { ESM::GlobalMap map; @@ -914,7 +911,6 @@ namespace MWGui addVisitedLocation(cell->mName, it->first, it->second); } } -#endif } void MapWindow::setAlpha(float alpha) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 68d2e28de5..1e1e2c97e3 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -195,6 +195,7 @@ namespace MWGui void globalMapUpdatePlayer(); MyGUI::ScrollView* mGlobalMap; + MyGUI::ITexture* mGlobalMapTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; @@ -216,7 +217,7 @@ namespace MWGui MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; - //MWRender::GlobalMap* mGlobalMapRender; + MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 95d4429d6f..897225a72f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -1,14 +1,9 @@ #include "globalmap.hpp" -#include -#include +#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -23,9 +18,8 @@ namespace MWRender { - GlobalMap::GlobalMap(const std::string &cacheDir) - : mCacheDir(cacheDir) - , mMinX(0), mMaxX(0) + GlobalMap::GlobalMap() + : mMinX(0), mMaxX(0) , mMinY(0), mMaxY(0) , mWidth(0) , mHeight(0) @@ -35,13 +29,10 @@ namespace MWRender GlobalMap::~GlobalMap() { - Ogre::TextureManager::getSingleton().remove(mOverlayTexture->getName()); } void GlobalMap::render (Loading::Listener* loadingListener) { - Ogre::TexturePtr tex; - const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -67,7 +58,9 @@ namespace MWRender loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1)); loadingListener->setProgress(0); - std::vector data (mWidth * mHeight * 3); + osg::ref_ptr image = new osg::Image; + image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE); + unsigned char* data = image->data(); for (int x = mMinX; x <= mMaxX; ++x) { @@ -139,16 +132,8 @@ namespace MWRender } } - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - - tex = Ogre::TextureManager::getSingleton ().createManual ("GlobalMap.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_B8G8R8, Ogre::TU_STATIC); - tex->loadRawData(stream, mWidth, mHeight, Ogre::PF_B8G8R8); - - tex->load(); - - mOverlayTexture = Ogre::TextureManager::getSingleton().createManual("GlobalMapOverlay", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_A8B8G8R8, Ogre::TU_DYNAMIC, this); + mBaseTexture = new osg::Texture2D; + mBaseTexture->setImage(image); clear(); @@ -172,13 +157,14 @@ namespace MWRender void GlobalMap::exploreCell(int cellX, int cellY) { - float originX = static_cast((cellX - mMinX) * mCellSize); + //float originX = static_cast((cellX - mMinX) * mCellSize); // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); + //float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; + /* Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); @@ -208,24 +194,19 @@ namespace MWRender mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), static_cast(originX + x), static_cast(originY + y), 0); } } + */ } void GlobalMap::clear() { + /* Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); memset(buffer, 0, mWidth * mHeight * 4); mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image mOverlayTexture->load(); - } - - void GlobalMap::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = static_cast(resource); - Ogre::ConstImagePtrList list; - list.push_back(&mOverlayImage); - tex->_loadImages(list); + */ } void GlobalMap::write(ESM::GlobalMap& map) @@ -235,9 +216,11 @@ namespace MWRender map.mBounds.mMinY = mMinY; map.mBounds.mMaxY = mMaxY; + /* Ogre::DataStreamPtr encoded = mOverlayImage.encode("png"); map.mImageData.resize(encoded->size()); encoded->read(&map.mImageData[0], encoded->size()); + */ } void GlobalMap::read(ESM::GlobalMap& map) @@ -253,6 +236,7 @@ namespace MWRender || bounds.mMinY > bounds.mMaxY) throw std::runtime_error("invalid map bounds"); + /* Ogre::Image image; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); image.load(stream, "png"); @@ -309,5 +293,11 @@ namespace MWRender mOverlayTexture->convertToImage(mOverlayImage); Ogre::TextureManager::getSingleton().remove("@temp"); + */ + } + + osg::ref_ptr GlobalMap::getBaseTexture() + { + return mBaseTexture; } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index a162ab68fb..d7e20a3a77 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -2,8 +2,14 @@ #define GAME_RENDER_GLOBALMAP_H #include +#include -#include +#include + +namespace osg +{ + class Texture2D; +} namespace Loading { @@ -18,10 +24,10 @@ namespace ESM namespace MWRender { - class GlobalMap : public Ogre::ManualResourceLoader + class GlobalMap { public: - GlobalMap(const std::string& cacheDir); + GlobalMap(); ~GlobalMap(); void render(Loading::Listener* loadingListener); @@ -37,23 +43,21 @@ namespace MWRender void exploreCell (int cellX, int cellY); - virtual void loadResource(Ogre::Resource* resource); - /// Clears the overlay void clear(); void write (ESM::GlobalMap& map); void read (ESM::GlobalMap& map); - private: - std::string mCacheDir; + osg::ref_ptr getBaseTexture(); + //osg::ref_ptr getOverlayTexture(); + private: int mCellSize; std::vector< std::pair > mExploredCells; - Ogre::TexturePtr mOverlayTexture; - Ogre::Image mOverlayImage; // Backup in system memory + osg::ref_ptr mBaseTexture; int mWidth; int mHeight; From 99eb78fc19d86508e641f08ae74845fec4dee9a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 May 2015 22:16:14 +0200 Subject: [PATCH 0271/1812] Fix $DISPLAY not being accounted for in cursor decompression context --- components/sdlutil/sdlcursormanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 9a7c2aa761..70f3891360 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -33,6 +33,12 @@ namespace traits->sharedContext = 0; traits->pbuffer = true; + osg::GraphicsContext::ScreenIdentifier si; + si.readDISPLAY(); + traits->displayNum = si.displayNum; + traits->screenNum = si.screenNum; + traits->hostName = si.hostName; + _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!_gc) From 314c1161ae1bc018316adb0512867b77c6331e81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 May 2015 21:05:17 +0200 Subject: [PATCH 0272/1812] Minor addition to reading display --- components/sdlutil/sdlcursormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 70f3891360..2befc7bd05 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -35,6 +35,7 @@ namespace osg::GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); + if (si.displayNum<0) si.displayNum = 0; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->hostName = si.hostName; From 8b768f4377b4bb37c3cca3f8e0735607de0d1165 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 May 2015 21:06:42 +0200 Subject: [PATCH 0273/1812] Minor fix for behaviour with non-existing LightManager --- components/sceneutil/lightmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1aaf7ab408..ce7a343da5 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -244,7 +244,10 @@ namespace SceneUtil } } if (!mLightManager) + { + traverse(node, nv); return; + } } mLightManager->prepareForCamera(cv->getCurrentCamera()); From 820f4a2688b0910aaa53859d05159e25f69e0212 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 02:07:18 +0200 Subject: [PATCH 0274/1812] Fix light direction --- apps/opencs/view/render/lightingbright.cpp | 2 +- apps/opencs/view/render/lightingday.cpp | 2 +- apps/opencs/view/render/lightingnight.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 035e57c562..00c4fb8151 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -13,7 +13,7 @@ void CSVRender::LightingBright::activate (osg::Group* rootNode) osg::ref_ptr light (new osg::Light); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); light->setConstantAttenuation(1.f); diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index 376f3e4321..a841edc639 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -11,7 +11,7 @@ void CSVRender::LightingDay::activate (osg::Group* rootNode) mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 18a12d63d5..6f87d020b9 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -11,7 +11,7 @@ void CSVRender::LightingNight::activate (osg::Group* rootNode) mLightSource = new osg::LightSource; osg::ref_ptr light (new osg::Light); - light->setDirection(osg::Vec3f(0.f, 0.f, -1.f)); + light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f)); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); light->setDiffuse(osg::Vec4f(0.2f, 0.2f, 0.2f, 1.f)); light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7e742e7293..c0eb00ea47 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -178,9 +178,10 @@ namespace MWRender void RenderingManager::setSunDirection(const osg::Vec3f &direction) { - mSunLight->setDirection(direction*-1); + osg::Vec3 position = direction * -1; + mSunLight->setPosition(osg::Vec4(position.x(), position.y(), position.z(), 0)); - mSky->setSunDirection(direction*-1); + mSky->setSunDirection(position); } osg::Vec3f RenderingManager::getEyePos() From 72c1f37527cab2e5924f4c1759f4219b7d10385e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 02:18:20 +0200 Subject: [PATCH 0275/1812] Port CharacterPreview --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwgui/charactercreation.cpp | 14 +- apps/openmw/mwgui/charactercreation.hpp | 16 +- apps/openmw/mwgui/inventorywindow.cpp | 103 +++--- apps/openmw/mwgui/inventorywindow.hpp | 23 +- apps/openmw/mwgui/race.cpp | 64 ++-- apps/openmw/mwgui/race.hpp | 24 +- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 11 +- apps/openmw/mwrender/animation.hpp | 6 +- apps/openmw/mwrender/characterpreview.cpp | 391 +++++++++++----------- apps/openmw/mwrender/characterpreview.hpp | 93 +++-- 12 files changed, 389 insertions(+), 366 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7d66b2aba8..9fa5e38a28 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,10 +22,10 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap + bulletdebugdraw globalmap characterpreview # camera # localmap occlusionquery water shadows -# characterpreview ripplesimulation refraction +# ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index fb00d6a985..73b950a6aa 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -60,8 +60,10 @@ namespace namespace MWGui { - CharacterCreation::CharacterCreation() - : mNameDialog(0) + CharacterCreation::CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mResourceSystem(resourceSystem) + , mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) , mGenerateClassQuestionDialog(0) @@ -146,7 +148,7 @@ namespace MWGui case GM_Race: MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(); + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -261,12 +263,6 @@ namespace MWGui } } - void CharacterCreation::doRenderUpdate() - { - if (mRaceDialog) - mRaceDialog->doRenderUpdate(); - } - void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index a4515569db..f6e7c6c923 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -8,6 +8,16 @@ #include "../mwmechanics/stat.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class WindowBase; @@ -29,7 +39,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(); + CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); ~CharacterCreation(); //Show a dialog @@ -39,9 +49,11 @@ namespace MWGui void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); - void doRenderUpdate(); private: + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + //Dialogs TextInputDialog* mNameDialog; RaceDialog* mRaceDialog; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index cbce86650e..a225b4e111 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,10 @@ #include #include +#include + +#include + #include #include "../mwbase/world.hpp" @@ -48,22 +52,23 @@ namespace namespace MWGui { - InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) - #if 0 - , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) - #endif - , mPreviewDirty(true) - , mPreviewResize(true) + , mViewer(viewer) + , mResourceSystem(resourceSystem) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mDragAndDrop(dragAndDrop) , mSortModel(NULL) , mTradeModel(NULL) , mSelectedItem(-1) , mGuiMode(GM_Inventory) { + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreview->rebuild(); + mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); getWidget(mAvatar, "Avatar"); @@ -79,6 +84,8 @@ namespace MWGui getWidget(mArmorRating, "ArmorRating"); mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); + mAvatarImage->setRenderItemTexture(mPreviewTexture.get()); + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); getWidget(mItemView, "ItemView"); mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected); @@ -115,17 +122,13 @@ namespace MWGui mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel(mSortModel); - mPreview.reset(NULL); - mAvatarImage->setImageTexture(""); -#if 0 - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); - if (tex) - MyGUI::RenderManager::getInstance().destroyTexture(tex); - mPreview.reset(new MWRender::InventoryPreview(mPtr)); - mPreview->setup(); -#endif - mPreviewDirty = true; - mPreviewResize = true; + mPreview->updatePtr(mPtr); + mPreview->rebuild(); + mPreview->update(); + + dirtyPreview(); + + updatePreviewSize(); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -158,7 +161,7 @@ namespace MWGui static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) - mPreviewResize = true; + updatePreviewSize(); mMainWidget->setPosition(pos); mMainWidget->setSize(size); @@ -319,7 +322,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); - mPreviewDirty = true; + + dirtyPreview(); } void InventoryWindow::open() @@ -366,10 +370,31 @@ namespace MWGui { mLastXSize = mMainWidget->getSize().width; mLastYSize = mMainWidget->getSize().height; - mPreviewResize = true; + + updatePreviewSize(); + updateArmorRating(); } } + void InventoryWindow::updateArmorRating() + { + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) + mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + } + + void InventoryWindow::updatePreviewSize() + { + MyGUI::IntSize size = mAvatarImage->getSize(); + int width = std::min(mPreview->getTextureWidth(), size.width); + int height = std::min(mPreview->getTextureHeight(), size.height); + mPreview->setViewport(width, height); + + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, height/float(mPreview->getTextureHeight()), + width/float(mPreview->getTextureWidth()), 0.f)); + } + void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) @@ -483,8 +508,6 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { - return MWWorld::Ptr(); -#if 0 int slot = mPreview->getSlotSelected (x, y); if (slot == -1) @@ -503,7 +526,6 @@ namespace MWGui } return MWWorld::Ptr(); -#endif } void InventoryWindow::updateEncumbranceBar() @@ -529,36 +551,11 @@ namespace MWGui mTrading = trading; } - void InventoryWindow::doRenderUpdate () + void InventoryWindow::dirtyPreview() { -#if 0 - mPreview->onFrame(); + mPreview->update(); - if (mPreviewResize || mPreviewDirty) - { - mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) - mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - } - if (mPreviewResize) - { - mPreviewResize = false; - MyGUI::IntSize size = mAvatarImage->getSize(); - mPreview->resize(size.width, size.height); - - mAvatarImage->setImageTexture("CharacterPreview"); - mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height))); - mAvatarImage->setImageTile(MyGUI::IntSize(std::min(512, size.width), std::min(1024, size.height))); - } - if (mPreviewDirty) - { - mPreviewDirty = false; - mPreview->update (); - - mAvatarImage->setImageTexture("CharacterPreview"); - } -#endif + updateArmorRating(); } void InventoryWindow::notifyContentChanged() @@ -569,7 +566,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); - mPreviewDirty = true; + dirtyPreview(); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) @@ -675,8 +672,6 @@ namespace MWGui void InventoryWindow::rebuildAvatar() { -#if 0 mPreview->rebuild(); -#endif } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ee71d9b04c..fc579ae628 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -6,6 +6,16 @@ #include "../mwworld/ptr.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWRender { class InventoryPreview; @@ -27,12 +37,10 @@ namespace MWGui class InventoryWindow : public WindowPinnableBase { public: - InventoryWindow(DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); virtual void open(); - void doRenderUpdate(); - /// start trading, disables item drag&drop void setTrading(bool trading); @@ -62,8 +70,6 @@ namespace MWGui private: DragAndDrop* mDragAndDrop; - bool mPreviewDirty; - bool mPreviewResize; int mSelectedItem; MWWorld::Ptr mPtr; @@ -93,6 +99,10 @@ namespace MWGui int mLastXSize; int mLastYSize; + Resource::ResourceSystem* mResourceSystem; + osgViewer::Viewer* mViewer; + + std::auto_ptr mPreviewTexture; std::auto_ptr mPreview; bool mTrading; @@ -113,6 +123,9 @@ namespace MWGui void updateEncumbranceBar(); void notifyContentChanged(); + void dirtyPreview(); + void updatePreviewSize(); + void updateArmorRating(); void adjustPanes(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index af4332c7ca..a65379fca4 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,8 +5,12 @@ #include #include +#include + #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,8 +41,10 @@ namespace namespace MWGui { - RaceDialog::RaceDialog() + RaceDialog::RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowModal("openmw_chargen_race.layout") + , mViewer(viewer) + , mResourceSystem(resourceSystem) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -125,19 +131,20 @@ namespace MWGui updateSkills(); updateSpellPowers(); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); - mPreviewImage->setImageTexture(""); + mPreview.reset(NULL); + mPreviewTexture.reset(NULL); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); + mPreview.reset(new MWRender::RaceSelectionPreview(mViewer, mResourceSystem)); + mPreview->rebuild(); + mPreview->setAngle (mCurrentAngle); - //mPreview.reset(new MWRender::RaceSelectionPreview()); - //mPreview->setup(); - //mPreview->update (mCurrentAngle); + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreviewImage->setRenderItemTexture(mPreviewTexture.get()); + mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); - //const ESM::NPC& proto = mPreview->getPrototype(); - ESM::NPC proto; + const ESM::NPC& proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); @@ -153,8 +160,6 @@ namespace MWGui mHairIndex = i; } - mPreviewImage->setImageTexture (textureName); - mPreviewDirty = true; size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; @@ -182,10 +187,10 @@ namespace MWGui void RaceDialog::close() { - mPreviewImage->setImageTexture(""); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); + + mPreviewTexture.reset(NULL); + mPreview.reset(NULL); } // widget controls @@ -205,8 +210,8 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; - //mPreview->update (angle); - mPreviewDirty = true; + mPreview->setAngle (angle); + mCurrentAngle = angle; } @@ -317,7 +322,7 @@ namespace MWGui void RaceDialog::updatePreview() { - ESM::NPC record;// = mPreview->getPrototype(); + ESM::NPC record = mPreview->getPrototype(); record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); @@ -326,27 +331,12 @@ namespace MWGui try { - //mPreview->setPrototype(record); + mPreview->setPrototype(record); } catch (std::exception& e) { std::cerr << "Error creating preview: " << e.what() << std::endl; } - - mPreviewDirty = true; - } - - void RaceDialog::doRenderUpdate() - { - //if (!mPreview.get()) - return; - - //mPreview->onFrame(); - if (mPreviewDirty) - { - //mPreview->render(); - mPreviewDirty = false; - } } void RaceDialog::updateRaces() @@ -451,8 +441,6 @@ namespace MWGui const ESM::NPC& RaceDialog::getResult() const { - static ESM::NPC result; - return result; - //return mPreview->getPrototype(); + return mPreview->getPrototype(); } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f188af2b30..b3de9bef06 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -19,12 +19,22 @@ namespace ESM struct NPC; } +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class RaceDialog : public WindowModal { public: - RaceDialog(); + RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); enum Gender { @@ -35,13 +45,9 @@ namespace MWGui const ESM::NPC &getResult() const; 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) { mGenderIndex = gender == GM_Male ? 0 : 1; } - // setFace() - // setHair() void setNextButtonShow(bool shown); virtual void open(); @@ -60,8 +66,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - void doRenderUpdate(); - protected: void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); @@ -89,6 +93,9 @@ namespace MWGui void getBodyParts (int part, std::vector& out); + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + std::vector mAvailableHeads; std::vector mAvailableHairs; @@ -108,7 +115,8 @@ namespace MWGui float mCurrentAngle; - //std::auto_ptr mPreview; + std::auto_ptr mPreview; + std::auto_ptr mPreviewTexture; bool mPreviewDirty; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0a9e867502..5649908fcd 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -275,7 +275,7 @@ namespace MWGui mJournal = JournalWindow::create(JournalViewModel::create ()); mMessageBoxManager = new MessageBoxManager( MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); mTradeWindow = new TradeWindow(); trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -324,7 +324,7 @@ namespace MWGui mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) @@ -358,7 +358,7 @@ namespace MWGui { disallowAll(); delete mCharGen; - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); mGuiModes.clear(); MWBase::Environment::get().getInputManager()->changeInputMode(false); mHud->unsetSelectedWeapon(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0cddb4d09..3a0f543d9d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1081,12 +1081,21 @@ namespace MWRender return true; } - bool Animation::hasNode(const std::string &name) + bool Animation::hasNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); return (mNodeMap.find(lowerName) != mNodeMap.end()); } + const osg::Node* Animation::getNode(const std::string &name) const + { + std::string lowerName = Misc::StringUtils::lowerCase(name); + NodeMap::const_iterator found = mNodeMap.find(lowerName); + if (found == mNodeMap.end()) + throw std::runtime_error("Can't find node " + name); + return found->second; + } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { if (mTimePtr) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a12375a9b9..0c490b525d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -354,7 +354,11 @@ public: /// Is there a node with the specified name? /// @note The matching is case-insensitive. - bool hasNode(const std::string& name); + bool hasNode(const std::string& name) const; + + /// Return a node with the specified name, throws an exception if the node is not found. + /// @note The matching is case-insensitive. + const osg::Node* getNode(const std::string& name) const; virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 7d61e3b6c1..1a7b4ea390 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,189 +1,186 @@ #include "characterpreview.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "renderconst.hpp" #include "npcanimation.hpp" namespace MWRender { - CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mRecover(false) - , mRenderTarget(NULL) - , mViewport(NULL) - , mCamera(NULL) - , mSceneMgr (0) - , mNode(NULL) + class DrawOnceCallback : public osg::NodeCallback + { + public: + DrawOnceCallback () + : mRendered(false) + { + } + + virtual void operator () (osg::Node* node, osg::NodeVisitor* nv) + { + if (!mRendered) + { + mRendered = true; + } + else + { + node->setNodeMask(0); + } + + traverse(node, nv); + } + + void redrawNextFrame() + { + mRendered = false; + } + + private: + bool mRendered; + }; + + CharacterPreview::CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, + MWWorld::Ptr character, int sizeX, int sizeY, const osg::Vec3f& position, const osg::Vec3f& lookAt) + : mViewer(viewer) + , mResourceSystem(resourceSystem) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) - , mName(name) , mSizeX(sizeX) , mSizeY(sizeY) { + mTexture = new osg::Texture2D; + mTexture->setTextureSize(sizeX, sizeY); + mTexture->setInternalFormat(GL_RGBA); + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + mCamera = new osg::Camera; + // hints that the camera is not relative to the master camera + mCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + mCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + mCamera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 0.f)); + mCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + const float fovYDegrees = 12.3f; + mCamera->setProjectionMatrixAsPerspective(fovYDegrees, sizeX/static_cast(sizeY), 0.1f, 10000.f); // zNear and zFar are autocomputed + mCamera->setViewport(0, 0, sizeX, sizeY); + mCamera->setRenderOrder(osg::Camera::PRE_RENDER); + mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); + mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + + osg::ref_ptr lightManager = new SceneUtil::LightManager; + lightManager->setStartLight(1); + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + + /// \todo Read the fallback values from INIImporter (Inventory:Directional*) ? + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); + light->setDiffuse(osg::Vec4(1,1,1,1)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON); + + lightManager->setStateSet(stateset); + lightManager->addChild(lightSource); + + mCamera->addChild(lightManager); + + mNode = new osg::PositionAttitudeTransform; + lightManager->addChild(mNode); + + mDrawOnceCallback = new DrawOnceCallback; + mCamera->addUpdateCallback(mDrawOnceCallback); + + mViewer->getSceneData()->asGroup()->addChild(mCamera); + mCharacter.mCell = NULL; } - void CharacterPreview::onSetup() - { - - } - - void CharacterPreview::onFrame() - { - if (mRecover) - { - setupRenderTarget(); - mRenderTarget->update(); - mRecover = false; - } - } - - void CharacterPreview::setup () - { - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - // This is a dummy light to turn off shadows without having to use a separate set of shaders - Ogre::Light* l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDiffuseColour (Ogre::ColourValue(0,0,0)); - - /// \todo Read the fallback values from INIImporter (Inventory:Directional*) - l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - l->setDiffuseColour (Ogre::ColourValue(1,1,1)); - - mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); - - mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3f)); - mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); - - Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); - - // leftover of old coordinate system. TODO: remove this and adjust positions/orientations to match - renderRoot->pitch(Ogre::Degree(-90)); - - mNode = renderRoot->createChildSceneNode(); - - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); - - mCamera->setNearClipDistance (1); - mCamera->setFarClipDistance (1000); - - mTexture = Ogre::TextureManager::getSingleton().createManual(mName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mSizeX, mSizeY, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET, this); - - setupRenderTarget(); - - onSetup (); - } - CharacterPreview::~CharacterPreview () { - if (mSceneMgr) - { - mSceneMgr->destroyAllCameras(); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); - Ogre::TextureManager::getSingleton().remove(mName); - } + mViewer->getSceneData()->asGroup()->removeChild(mCamera); + } + + int CharacterPreview::getTextureWidth() const + { + return mSizeX; + } + + int CharacterPreview::getTextureHeight() const + { + return mSizeY; + } + + void CharacterPreview::onSetup() + { + } + + osg::ref_ptr CharacterPreview::getTexture() + { + return mTexture; } void CharacterPreview::rebuild() { delete mAnimation; mAnimation = NULL; - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - float scale=1.f; - mCharacter.getClass().adjustScale(mCharacter, scale); - mNode->setScale(Ogre::Vector3(scale)); - - mCamera->setPosition(mPosition * mNode->getScale()); - mCamera->lookAt(mLookAt * mNode->getScale()); + mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, 0, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); onSetup(); + + redraw(); } - void CharacterPreview::loadResource(Ogre::Resource *resource) + void CharacterPreview::redraw() { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - - mRenderTarget = NULL; - mViewport = NULL; - mRecover = true; - } - - void CharacterPreview::setupRenderTarget() - { - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - mRenderTarget->removeAllViewports (); - mViewport = mRenderTarget->addViewport(mCamera); - mViewport->setOverlaysEnabled(false); - mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); - mViewport->setShadowsEnabled(false); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated (false); + mCamera->setNodeMask(~0); + mDrawOnceCallback->redrawNextFrame(); } // -------------------------------------------------------------------------------------------------- - InventoryPreview::InventoryPreview(MWWorld::Ptr character) - : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 71, -700), Ogre::Vector3(0,71,0)) - , mSizeX(0) - , mSizeY(0) - , mSelectionBuffer(NULL) + InventoryPreview::InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character) + : CharacterPreview(viewer, resourceSystem, character, 512, 1024, osg::Vec3f(0, 700, 71), osg::Vec3f(0,0,71)) { } - InventoryPreview::~InventoryPreview() + void InventoryPreview::setViewport(int sizeX, int sizeY) { - delete mSelectionBuffer; - } + sizeX = std::max(sizeX, 0); + sizeY = std::max(sizeY, 0); - void InventoryPreview::resize(int sizeX, int sizeY) - { - mSizeX = sizeX; - mSizeY = sizeY; + mCamera->setViewport(0, 0, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); + redraw(); } void InventoryPreview::update() @@ -191,6 +188,7 @@ namespace MWRender if (!mAnimation) return; + mAnimation->showWeapons(true); mAnimation->updateParts(); MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter); @@ -250,70 +248,51 @@ namespace MWRender mAnimation->runAnimation(0.0f); - mNode->setOrientation (Ogre::Quaternion::IDENTITY); - - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); - - mSelectionBuffer->update(); - } - - void InventoryPreview::setupRenderTarget() - { - CharacterPreview::setupRenderTarget(); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); + redraw(); } int InventoryPreview::getSlotSelected (int posX, int posY) { - return mSelectionBuffer->getSelected (posX, posY); + // TODO: implement + return 0; } - void InventoryPreview::onSetup () + void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) { - delete mSelectionBuffer; - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); + mCharacter = MWWorld::Ptr(ptr.getBase(), NULL); + } - mAnimation->showWeapons(true); + void InventoryPreview::onSetup() + { + osg::Vec3f scale (1.f, 1.f, 1.f); + mCharacter.getClass().adjustScale(mCharacter, scale); - mCurrentAnimGroup = "inventoryhandtohand"; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mNode->setScale(scale); + + mCamera->setViewMatrixAsLookAt(mPosition * scale.z(), mLookAt * scale.z(), osg::Vec3f(0,0,1)); } // -------------------------------------------------------------------------------------------------- - RaceSelectionPreview::RaceSelectionPreview() - : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayerPtr(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 8, -125), Ogre::Vector3(0,127,0)) + RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) - , mPitch(Ogre::Degree(6)) + , mPitchRadians(osg::DegreesToRadians(6.f)) { mCharacter = MWWorld::Ptr(&mRef, NULL); } - void RaceSelectionPreview::update(float angle) + RaceSelectionPreview::~RaceSelectionPreview() { - mAnimation->runAnimation(0.0f); - - mNode->setOrientation(Ogre::Quaternion(Ogre::Radian(angle), Ogre::Vector3::UNIT_Z) - * Ogre::Quaternion(mPitch, Ogre::Vector3::UNIT_X)); - - updateCamera(); } - void RaceSelectionPreview::render() + void RaceSelectionPreview::setAngle(float angleRadians) { - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - mRenderTarget->update(); + mNode->setAttitude(osg::Quat(mPitchRadians, osg::Vec3(1,0,0)) + * osg::Quat(angleRadians, osg::Vec3(0,0,1))); + redraw(); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) @@ -321,27 +300,53 @@ namespace MWRender mBase = proto; mBase.mId = "player"; rebuild(); - mAnimation->runAnimation(0.0f); - updateCamera(); } + class UpdateCameraCallback : public osg::NodeCallback + { + public: + UpdateCameraCallback(osg::ref_ptr nodeToFollow, const osg::Vec3& posOffset, const osg::Vec3& lookAtOffset) + : mNodeToFollow(nodeToFollow) + , mPosOffset(posOffset) + , mLookAtOffset(lookAtOffset) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); + + // Update keyframe controllers in the scene graph first... + traverse(node, nv); + + // Now update camera utilizing the updated head position + osg::MatrixList mats = mNodeToFollow->getWorldMatrices(); + if (!mats.size()) + return; + osg::Matrix worldMat = mats[0]; + osg::Vec3 headOffset = worldMat.getTrans(); + + cam->setViewMatrixAsLookAt(headOffset + mPosOffset, headOffset + mLookAtOffset, osg::Vec3(0,0,1)); + } + + private: + osg::ref_ptr mNodeToFollow; + osg::Vec3 mPosOffset; + osg::Vec3 mLookAtOffset; + }; + void RaceSelectionPreview::onSetup () { mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->runAnimation(0.f); - updateCamera(); + // attach camera to follow the head node + if (mUpdateCameraCallback) + mCamera->removeUpdateCallback(mUpdateCameraCallback); + + const osg::Node* head = mAnimation->getNode("Bip01 Head"); + mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); + mCamera->addUpdateCallback(mUpdateCameraCallback); } - void RaceSelectionPreview::updateCamera() - { - Ogre::Vector3 scale = mNode->getScale(); - Ogre::Node* headNode = mAnimation->getNode("Bip01 Head"); - if (!headNode) - return; - Ogre::Vector3 headOffset = headNode->_getDerivedPosition(); - headOffset = mNode->convertLocalToWorldPosition(headOffset); - - mCamera->setPosition(headOffset + mPosition * scale); - mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); - } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 80dbe18b4a..b7722d1f38 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -1,45 +1,48 @@ #ifndef MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H -#include -#include #include +#include + #include +#include + #include "../mwworld/ptr.hpp" -namespace OEngine +namespace osg { -namespace Render -{ -class SelectionBuffer; + class Texture2D; + class Camera; } + +namespace osgViewer +{ + class Viewer; } namespace MWRender { class NpcAnimation; + class DrawOnceCallback; - class CharacterPreview : public Ogre::ManualResourceLoader + class CharacterPreview { public: - CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt); + CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character, int sizeX, int sizeY, + const osg::Vec3f& position, const osg::Vec3f& lookAt); virtual ~CharacterPreview(); - virtual void setup (); - virtual void onSetup(); + int getTextureWidth() const; + int getTextureHeight() const; - virtual void rebuild(); + void redraw(); - void onFrame(); + void rebuild(); - void loadResource(Ogre::Resource *resource); - - private: - bool mRecover; // Texture content was lost and needs to be re-rendered + osg::ref_ptr getTexture(); private: CharacterPreview(const CharacterPreview&); @@ -47,28 +50,23 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return false; } + virtual void onSetup(); - virtual void setupRenderTarget(); + osg::ref_ptr mViewer; + Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mTexture; + osg::ref_ptr mCamera; + osg::ref_ptr mDrawOnceCallback; - Ogre::TexturePtr mTexture; - Ogre::RenderTarget* mRenderTarget; - Ogre::Viewport* mViewport; - - Ogre::Camera* mCamera; - - Ogre::SceneManager* mSceneMgr; - Ogre::SceneNode* mNode; - - Ogre::Vector3 mPosition; - Ogre::Vector3 mLookAt; + osg::Vec3f mPosition; + osg::Vec3f mLookAt; MWWorld::Ptr mCharacter; MWRender::NpcAnimation* mAnimation; + osg::ref_ptr mNode; std::string mCurrentAnimGroup; - std::string mName; - int mSizeX; int mSizeY; }; @@ -77,25 +75,21 @@ namespace MWRender { public: - InventoryPreview(MWWorld::Ptr character); - virtual ~InventoryPreview(); - virtual void onSetup(); + InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character); + + void updatePtr(const MWWorld::Ptr& ptr); void update(); // Render preview again, e.g. after changed equipment - void resize(int sizeX, int sizeY); + void setViewport(int sizeX, int sizeY); int getSlotSelected(int posX, int posY); protected: - virtual void setupRenderTarget(); - - private: - int mSizeX; - int mSizeY; - - OEngine::Render::SelectionBuffer* mSelectionBuffer; + virtual void onSetup(); }; + class UpdateCameraCallback; + class RaceSelectionPreview : public CharacterPreview { ESM::NPC mBase; @@ -104,16 +98,13 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return true; } - - void updateCamera(); + virtual void onSetup(); public: - RaceSelectionPreview(); + RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); + virtual ~RaceSelectionPreview(); - virtual void onSetup(); - void render(); - - void update(float angle); + void setAngle(float angleRadians); const ESM::NPC &getPrototype() const { return mBase; @@ -123,7 +114,9 @@ namespace MWRender private: - Ogre::Radian mPitch; + osg::ref_ptr mUpdateCameraCallback; + + float mPitchRadians; }; } From 8d033f055814ed7c27851fcdfbd343fc41d255a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:12:42 +0200 Subject: [PATCH 0276/1812] Fix UpdateRigBounds not being copied properly --- components/sceneutil/riggeometry.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index df5f65029e..065ee60d99 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -26,6 +26,8 @@ public: { } + META_Object(SceneUtil, UpdateRigBounds) + void update(osg::NodeVisitor* nv, osg::Drawable* drw) { RigGeometry* rig = static_cast(drw); @@ -47,7 +49,7 @@ public: { } - META_Object(NifOsg, UpdateRigGeometry) + META_Object(SceneUtil, UpdateRigGeometry) virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const { From c4452afd89956185c9542842c2f91949df43b67c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:35:52 +0200 Subject: [PATCH 0277/1812] Inventory item picking --- apps/openmw/mwgui/inventorywindow.cpp | 6 +++--- apps/openmw/mwgui/tooltips.cpp | 4 +--- apps/openmw/mwrender/characterpreview.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/npcanimation.cpp | 15 +++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a225b4e111..943d09f1a4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -487,10 +487,8 @@ namespace MWGui { MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance ().getLastPressedPosition (MyGUI::MouseButton::Left); MyGUI::IntPoint relPos = mousePos - mAvatarImage->getAbsolutePosition (); - int realX = int(float(relPos.left) / float(mAvatarImage->getSize().width) * 512.f ); - int realY = int(float(relPos.top) / float(mAvatarImage->getSize().height) * 1024.f ); - MWWorld::Ptr itemSelected = getAvatarSelectedItem (realX, realY); + MWWorld::Ptr itemSelected = getAvatarSelectedItem (relPos.left, relPos.top); if (itemSelected.isEmpty ()) return; @@ -508,6 +506,8 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { + // convert to OpenGL lower-left origin + y = (mAvatarImage->getHeight()-1) - y; int slot = mPreview->getSlotSelected (x, y); if (slot == -1) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 14eed0e103..f423142e0f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -200,9 +200,7 @@ namespace MWGui { MyGUI::IntCoord avatarPos = focus->getAbsoluteCoord(); MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); - int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); - int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (relMousePos.left, relMousePos.top); mFocusObject = item; if (!mFocusObject.isEmpty ()) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 1a7b4ea390..cc6b4a9bbc 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -253,8 +255,21 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { - // TODO: implement - return 0; + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_ONE); + osgUtil::IntersectionVisitor visitor(intersector); + + osg::Node::NodeMask nodeMask = mCamera->getNodeMask(); + mCamera->setNodeMask(~0); + mCamera->accept(visitor); + mCamera->setNodeMask(nodeMask); + + if (intersector->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + return mAnimation->getSlot(intersection.nodePath); + } + return -1; } void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2bb1b66fdd..932da30b92 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -235,6 +235,21 @@ void NpcAnimation::rebuild() MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } +int NpcAnimation::getSlot(const osg::NodePath &path) const +{ + for (int i=0; igetNode().get()) != path.end()) + { + return mPartslots[i]; + } + } + return -1; +} + void NpcAnimation::updateNpcBase() { clearAnimSources(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a58f0fdf33..7ebc42784c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -174,6 +174,9 @@ public: /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); + /// Get the inventory slot that the given node path leads into, or -1 if not found. + int getSlot(const osg::NodePath& path) const; + /// Make the NPC only partially visible virtual void setAlpha(float alpha); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c0eb00ea47..5ece10dc13 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -139,6 +139,8 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); From 7882c3d7f05565409672870089b7c16af16e8619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:38:40 +0200 Subject: [PATCH 0278/1812] Fix incorrect rotation for meshes with BoneOffset --- components/sceneutil/attach.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 49e2acbd24..2432b5eb29 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -82,7 +82,7 @@ namespace SceneUtil trans = new osg::PositionAttitudeTransform; trans->setPosition(boneOffset->getMatrix().getTrans()); // The BoneOffset rotation seems to be incorrect - trans->setAttitude(osg::Quat(-90, osg::Vec3f(1,0,0))); + trans->setAttitude(osg::Quat(osg::DegreesToRadians(-90.f), osg::Vec3f(1,0,0))); } if (attachNode.find("Left") != std::string::npos) From cfe57199d7f8f1c1240664a7d8da47a6bc777e5c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 May 2015 03:54:04 +0200 Subject: [PATCH 0279/1812] Minor cleanup --- apps/openmw/mwrender/npcanimation.cpp | 6 ++---- apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 932da30b92..b23a72e55f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -586,15 +586,13 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; }*/ -Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, int group, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); if (enchantedGlow) addGlow(attached, *glowColor); - // TODO: set group userdata for inventory picking - return PartHolderPtr(new PartHolder(attached)); } @@ -679,7 +677,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g const std::string& bonename = sPartList.at(type); // PRT_Hair seems to be the only type that breaks consistency and uses a filter that's different from the attachment bone const std::string bonefilter = (type == ESM::PRT_Hair) ? "hair" : bonename; - mObjectParts[type] = insertBoundedPart(mesh, group, bonename, bonefilter, enchantedGlow, glowColor); + mObjectParts[type] = insertBoundedPart(mesh, bonename, bonefilter, enchantedGlow, glowColor); } catch (std::exception& e) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 7ebc42784c..eda59f50c5 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -105,7 +105,7 @@ private: void updateNpcBase(); - PartHolderPtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, + PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=NULL); void removeIndividualPart(ESM::PartReferenceType type); From 6031db78825df365327d1e4af012576625c115b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 21:04:48 +0200 Subject: [PATCH 0280/1812] Character sliding fix --- apps/openmw/mwphysics/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 04b53a8e38..db34e04117 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -176,7 +176,8 @@ namespace MWPhysics static inline osg::Vec3f reflect(const osg::Vec3& velocity, const osg::Vec3f& normal) { - return (normal * (normal * velocity)) * 2 - velocity; + return velocity - (normal * (normal * velocity)) * 2; + // ^ dot product } From 0fb97bd2e7ace6656ab975999ee35d3b67d137d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 23:24:22 +0200 Subject: [PATCH 0281/1812] Readded baseonly parameter to Animation::setObjectRoot Fixes the first person view. --- apps/openmw/mwrender/animation.cpp | 44 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3a0f543d9d..df6d6e9f25 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -167,6 +168,38 @@ namespace return 0.0f; } + + + // Removes all drawables from a graph. + class RemoveDrawableVisitor : public osg::NodeVisitor + { + public: + RemoveDrawableVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &node) + { + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(&node); + traverse(node); + } + + void remove() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + } + + private: + std::vector mToRemove; + }; + } namespace MWRender @@ -836,7 +869,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model, bool forceskeleton) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly) { if (mObjectRoot) { @@ -864,6 +897,13 @@ namespace MWRender mObjectRoot = newObjectRoot; } + if (baseonly) + { + RemoveDrawableVisitor removeDrawableVisitor; + mObjectRoot->accept(removeDrawableVisitor); + removeDrawableVisitor.remove(); + } + NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); @@ -1130,7 +1170,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model, false); + setObjectRoot(model, false, false); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0c490b525d..119814135e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -230,8 +230,10 @@ protected: * Note that you must make sure all animation sources are cleared before reseting the object * root. All nodes previously retrieved with getNode will also become invalidated. * @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually. + * @param baseonly If true, then any meshes or particle systems in the model are ignored + * (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files). */ - void setObjectRoot(const std::string &model, bool forceskeleton); + void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 25d9e9e471..e15dee5320 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,7 +23,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model, false /* , baseonly = false */); + setObjectRoot(model, false, false); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) @@ -42,7 +42,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model, true /* , baseonly = false*/); + setObjectRoot(model, true, false); //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b23a72e55f..5fafa6d592 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -299,7 +299,7 @@ void NpcAnimation::updateNpcBase() : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel, true /*, baseonly = true*/); + setObjectRoot(smodel, true, true); if(mViewMode != VM_FirstPerson) { From 9b8e2e9db3bb205175215b02ce0d9c740ae2b8a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 May 2015 23:54:39 +0200 Subject: [PATCH 0282/1812] Port MWRender::Camera --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/engine.cpp | 3 - apps/openmw/mwrender/animation.cpp | 5 + apps/openmw/mwrender/animation.hpp | 2 + apps/openmw/mwrender/camera.cpp | 228 +++++++++++----------- apps/openmw/mwrender/camera.hpp | 39 ++-- apps/openmw/mwrender/renderingmanager.cpp | 111 ++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 20 +- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 61 +++++- apps/openmw/mwworld/worldimp.hpp | 28 +-- 11 files changed, 329 insertions(+), 173 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9fa5e38a28..941222b0c6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap characterpreview -# camera + bulletdebugdraw globalmap characterpreview camera # localmap occlusionquery water shadows # ripplesimulation refraction # terrainstorage weaponanimation diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ca21e36125..5ce1607b5a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -5,7 +5,6 @@ #include -#include #include #include @@ -592,8 +591,6 @@ void OMW::Engine::go() } // Start the main rendering loop - mViewer->setCameraManipulator(new osgGA::TrackballManipulator); - osg::Timer frameTimer; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df6d6e9f25..416f66cec6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -249,6 +249,11 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + MWWorld::Ptr Animation::getPtr() + { + return mPtr; + } + void Animation::setActive(bool active) { if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 119814135e..82b54bdeaa 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -254,6 +254,8 @@ public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + MWWorld::Ptr getPtr(); + /// Set active flag on the object skeleton, if one exists. /// @see SceneUtil::Skeleton::setActive void setActive(bool active); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index c7a27dfe8f..a92f901583 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,9 +1,6 @@ #include "camera.hpp" -#include -#include -#include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -13,12 +10,38 @@ #include "npcanimation.hpp" +namespace +{ + +class UpdateCameraCallback : public osg::NodeCallback +{ +public: + UpdateCameraCallback(MWRender::Camera* cam) + : mCamera(cam) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); + + // traverse first to update animations, in case the camera is attached to an animated node + traverse(node, nv); + + mCamera->updateCamera(cam); + } + +private: + MWRender::Camera* mCamera; +}; + +} + namespace MWRender { - Camera::Camera (Ogre::Camera *camera) + + Camera::Camera (osg::Camera* camera) : mCamera(camera), - mCameraNode(NULL), - mCameraPosNode(NULL), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -27,10 +50,11 @@ namespace MWRender mFurthest(800.f), mIsNearest(false), mHeight(124.f), - mCameraDistance(192.f), + mMaxCameraDistance(192.f), mDistanceAdjusted(false), mVanityToggleQueued(false), - mViewModeToggleQueued(false) + mViewModeToggleQueued(false), + mCameraDistance(0.f) { mVanity.enabled = false; mVanity.allowed = true; @@ -41,10 +65,46 @@ namespace MWRender mMainCam.pitch = 0.f; mMainCam.yaw = 0.f; mMainCam.offset = 400.f; + + mUpdateCallback = new UpdateCameraCallback(this); + mCamera->addUpdateCallback(mUpdateCallback); } Camera::~Camera() { + mCamera->removeUpdateCallback(mUpdateCallback); + } + + MWWorld::Ptr Camera::getTrackingPtr() const + { + return mTrackingPtr; + } + + void Camera::updateCamera(osg::Camera *cam) + { + if (mTrackingPtr.isEmpty()) + return; + const osg::Node* trackNode = mTrackingNode; + if (!trackNode) + return; + osg::MatrixList mats = trackNode->getWorldMatrices(); + if (!mats.size()) + return; + const osg::Matrix& worldMat = mats[0]; + + osg::Vec3 position = worldMat.getTrans(); + if (!isFirstPerson()) + position.z() += mHeight; + + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3(1,0,0)) * osg::Quat(getYaw(), osg::Vec3(0,0,1)); + + osg::Vec3 offset = orient * osg::Vec3(0, -mCameraDistance, 0); + position += offset; + + osg::Vec3 forward = orient * osg::Vec3(0,1,0); + osg::Vec3 up = orient * osg::Vec3(0,0,1); + + cam->setViewMatrixAsLookAt(position, position + forward, up); } void Camera::reset() @@ -55,68 +115,20 @@ namespace MWRender toggleViewMode(); } - void Camera::rotateCamera(const Ogre::Vector3 &rot, bool adjust) + void Camera::rotateCamera(float pitch, float yaw, bool adjust) { - if (adjust) { - setYaw(getYaw() + rot.z); - setPitch(getPitch() + rot.x); - } else { - setYaw(rot.z); - setPitch(rot.x); + if (adjust) + { + pitch += getPitch(); + yaw += getYaw(); } - - Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); - Ogre::Quaternion orient = xr; - if (mVanity.enabled || mPreviewMode) { - Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z); - orient = zr * xr; - } - - if (isFirstPerson()) - mCamera->getParentNode()->setOrientation(orient); - else - mCameraNode->setOrientation(orient); + setYaw(yaw); + setPitch(pitch); } - const std::string &Camera::getHandle() const - { - return mTrackingPtr.getRefData().getHandle(); - } - - Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr) + void Camera::attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; - Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); - node->setInheritScale(false); - Ogre::SceneNode *posNode = node->createChildSceneNode(); - posNode->setInheritScale(false); - if(mCameraNode) - { - node->setOrientation(mCameraNode->getOrientation()); - posNode->setPosition(mCameraPosNode->getPosition()); - mCameraNode->getCreator()->destroySceneNode(mCameraNode); - mCameraNode->getCreator()->destroySceneNode(mCameraPosNode); - } - mCameraNode = node; - mCameraPosNode = posNode; - - if (!isFirstPerson()) - { - mCamera->detachFromParent(); - mCameraPosNode->attachObject(mCamera); - } - - return mCameraPosNode; - } - - void Camera::setPosition(const Ogre::Vector3& position) - { - mCameraPosNode->setPosition(position); - } - - void Camera::setPosition(float x, float y, float z) - { - setPosition(Ogre::Vector3(x,y,z)); } void Camera::update(float duration, bool paused) @@ -147,9 +159,7 @@ namespace MWRender if(mVanity.enabled) { - Ogre::Vector3 rot(0.f, 0.f, 0.f); - rot.z = Ogre::Degree(3.f * duration).valueRadians(); - rotateCamera(rot, true); + rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); } } @@ -169,9 +179,9 @@ namespace MWRender processViewChange(); if (mFirstPersonView) { - setPosition(0.f, 0.f, 0.f); + mCameraDistance = 0.f; } else { - setPosition(0.f, 0.f, mCameraDistance); + mCameraDistance = mMaxCameraDistance; } } @@ -202,18 +212,15 @@ namespace MWRender processViewChange(); float offset = mPreviewCam.offset; - Ogre::Vector3 rot(0.f, 0.f, 0.f); + if (mVanity.enabled) { - rot.x = Ogre::Degree(-30.f).valueRadians(); - mMainCam.offset = mCameraPosNode->getPosition().z; + setPitch(osg::DegreesToRadians(-30.f)); + mMainCam.offset = mCameraDistance; } else { - rot.x = getPitch(); offset = mMainCam.offset; } - rot.z = getYaw(); - setPosition(0.f, 0.f, offset); - rotateCamera(rot, false); + mCameraDistance = offset; return true; } @@ -229,7 +236,7 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCameraPosNode->getPosition().z; + float offset = mCameraDistance; if (mPreviewMode) { mMainCam.offset = offset; offset = mPreviewCam.offset; @@ -238,13 +245,12 @@ namespace MWRender offset = mMainCam.offset; } - setPosition(0.f, 0.f, offset); + mCameraDistance = offset; } void Camera::setSneakOffset(float offset) { - if(mAnimation) - mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -offset)); + // TODO: implement } float Camera::getYaw() @@ -256,10 +262,10 @@ namespace MWRender void Camera::setYaw(float angle) { - if (angle > Ogre::Math::PI) { - angle -= Ogre::Math::TWO_PI; - } else if (angle < -Ogre::Math::PI) { - angle += Ogre::Math::TWO_PI; + if (angle > osg::PI) { + angle -= osg::PI*2; + } else if (angle < -osg::PI) { + angle += osg::PI*2; } if (mVanity.enabled || mPreviewMode) { mPreviewCam.yaw = angle; @@ -279,7 +285,7 @@ namespace MWRender void Camera::setPitch(float angle) { const float epsilon = 0.000001f; - float limit = Ogre::Math::HALF_PI - epsilon; + float limit = osg::PI_2 - epsilon; if(mPreviewMode) limit /= 2; @@ -297,7 +303,7 @@ namespace MWRender float Camera::getCameraDistance() const { - return mCameraPosNode->getPosition().z; + return mCameraDistance; } void Camera::setCameraDistance(float dist, bool adjust, bool override) @@ -307,25 +313,24 @@ namespace MWRender mIsNearest = false; - Ogre::Vector3 v(0.f, 0.f, dist); - if (adjust) { - v += mCameraPosNode->getPosition(); - } - if (v.z >= mFurthest) { - v.z = mFurthest; - } else if (!override && v.z < 10.f) { - v.z = 10.f; - } else if (override && v.z <= mNearest) { - v.z = mNearest; + if (adjust) + dist += mCameraDistance; + + if (dist >= mFurthest) { + dist = mFurthest; + } else if (!override && dist < 10.f) { + dist = -10.f; + } else if (override && dist <= mNearest) { + dist = -mNearest; mIsNearest = true; } - setPosition(v); + mCameraDistance = dist; if (override) { if (mVanity.enabled || mPreviewMode) { - mPreviewCam.offset = v.z; + mPreviewCam.offset = mCameraDistance; } else if (!mFirstPersonView) { - mCameraDistance = v.z; + mMaxCameraDistance = mCameraDistance; } } else { mDistanceAdjusted = true; @@ -336,9 +341,9 @@ namespace MWRender { if (mDistanceAdjusted) { if (mVanity.enabled || mPreviewMode) { - setPosition(0, 0, mPreviewCam.offset); + mCameraDistance = mPreviewCam.offset; } else if (!mFirstPersonView) { - setPosition(0, 0, mCameraDistance); + mCameraDistance = mMaxCameraDistance; } } mDistanceAdjusted = false; @@ -351,7 +356,6 @@ namespace MWRender if(mAnimation && mAnimation != anim) { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mAnimation->detachObjectFromBone(mCamera); } mAnimation = anim; @@ -360,29 +364,25 @@ namespace MWRender void Camera::processViewChange() { - mAnimation->detachObjectFromBone(mCamera); - mCamera->detachFromParent(); - if(isFirstPerson()) { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); - Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera); - tag->setInheritOrientation(false); + mTrackingNode = mAnimation->getNode("Head"); } else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mCameraPosNode->attachObject(mCamera); + mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); } - rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); + rotateCamera(getPitch(), getYaw(), false); } - void Camera::getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera) + void Camera::getPosition(osg::Vec3 &focal, osg::Vec3 &camera) { - mCamera->getParentSceneNode()->needUpdate(true); + //mCamera->getParentSceneNode()->needUpdate(true); - camera = mCamera->getRealPosition(); - focal = mCameraNode->_getDerivedPosition(); + //camera = mCamera->getRealPosition(); + //focal = mCameraNode->_getDerivedPosition(); } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 691a80862b..68f0870d71 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -3,13 +3,16 @@ #include +#include +#include + #include "../mwworld/ptr.hpp" -namespace Ogre +namespace osg { - class Vector3; class Camera; - class SceneNode; + class NodeCallback; + class Node; } namespace MWRender @@ -24,10 +27,9 @@ namespace MWRender }; MWWorld::Ptr mTrackingPtr; + osg::ref_ptr mTrackingNode; - Ogre::Camera *mCamera; - Ogre::SceneNode *mCameraNode; - Ogre::SceneNode *mCameraPosNode; + osg::ref_ptr mCamera; NpcAnimation *mAnimation; @@ -42,7 +44,7 @@ namespace MWRender bool enabled, allowed; } mVanity; - float mHeight, mCameraDistance; + float mHeight, mMaxCameraDistance; CamData mMainCam, mPreviewCam; bool mDistanceAdjusted; @@ -50,19 +52,25 @@ namespace MWRender bool mVanityToggleQueued; bool mViewModeToggleQueued; - void setPosition(const Ogre::Vector3& position); - void setPosition(float x, float y, float z); + float mCameraDistance; + + osg::ref_ptr mUpdateCallback; public: - Camera(Ogre::Camera *camera); + Camera(osg::Camera* camera); ~Camera(); + MWWorld::Ptr getTrackingPtr() const; + + /// Update the view matrix of \a cam + void updateCamera(osg::Camera* cam); + /// Reset to defaults void reset(); /// Set where the camera is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians - void rotateCamera(const Ogre::Vector3 &rot, bool adjust); + void rotateCamera(float pitch, float yaw, bool adjust); float getYaw(); void setYaw(float angle); @@ -70,10 +78,8 @@ namespace MWRender float getPitch(); void setPitch(float angle); - const std::string &getHandle() const; - /// Attach camera to object - Ogre::SceneNode* attachTo(const MWWorld::Ptr &); + void attachTo(const MWWorld::Ptr &); /// @param Force view mode switch, even if currently not allowed by the animation. void toggleViewMode(bool force=false); @@ -85,9 +91,6 @@ namespace MWRender void togglePreviewMode(bool enable); /// \brief Lowers the camera for sneak. - /// As animation is tied to the camera, this needs - /// to be set each frame after the animation is - /// applied. void setSneakOffset(float offset); bool isFirstPerson() const @@ -111,7 +114,7 @@ namespace MWRender void setAnimation(NpcAnimation *anim); /// Stores focal and camera world positions in passed arguments - void getPosition(Ogre::Vector3 &focal, Ogre::Vector3 &camera); + void getPosition(osg::Vec3 &focal, osg::Vec3 &camera); void togglePlayerLooking(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5ece10dc13..bbff16a10f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,6 +31,7 @@ #include "npcanimation.hpp" #include "vismask.hpp" #include "pathgrid.hpp" +#include "camera.hpp" namespace MWRender { @@ -104,6 +105,8 @@ namespace MWRender mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mCamera.reset(new Camera(mViewer->getCamera())); + mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -253,11 +256,21 @@ namespace MWRender mSky->update(dt); } + void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) + { + if(mPlayerAnimation.get()) + mPlayerAnimation->updatePtr(ptr); + + mCamera->attachTo(ptr); + } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) { - //if(ptr.getRefData().getHandle() == mCamera->getHandle() && - // !mCamera->isVanityOrPreviewModeEnabled()) - // mCamera->rotateCamera(-rot, false); + if(ptr == mCamera->getTrackingPtr() && + !mCamera->isVanityOrPreviewModeEnabled()) + { + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[2], false); + } ptr.getRefData().getBaseNode()->setAttitude(rot); } @@ -321,11 +334,30 @@ namespace MWRender { mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); - //mCamera->setAnimation(mPlayerAnimation); + mCamera->setAnimation(mPlayerAnimation.get()); + mCamera->attachTo(player); //mWater->removeEmitter(ptr); //mWater->addEmitter(ptr); } + void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) + { + NpcAnimation *anim = NULL; + if(ptr == mPlayerAnimation->getPtr()) + anim = mPlayerAnimation.get(); + else + anim = dynamic_cast(mObjects->getAnimation(ptr)); + if(anim) + { + anim->rebuild(); + if(mCamera->getTrackingPtr() == ptr) + { + mCamera->attachTo(ptr); + mCamera->setAnimation(anim); + } + } + } + void RenderingManager::updateProjectionMatrix() { double fovy, aspect, zNear, zFar; @@ -370,4 +402,75 @@ namespace MWRender } } + bool RenderingManager::vanityRotateCamera(const float *rot) + { + if(!mCamera->isVanityOrPreviewModeEnabled()) + return false; + + mCamera->rotateCamera(rot[0], rot[2], true); + return true; + } + + void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) + { + if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) + { + if(mCamera->isNearest() && dist > 0.f) + mCamera->toggleViewMode(); + else + mCamera->setCameraDistance(-dist / 120.f * 10, adjust, override); + } + else if(mCamera->isFirstPerson() && dist < 0.f) + { + mCamera->toggleViewMode(); + mCamera->setCameraDistance(0.f, false, override); + } + } + + void RenderingManager::resetCamera() + { + mCamera->reset(); + } + + float RenderingManager::getCameraDistance() const + { + return mCamera->getCameraDistance(); + } + + Camera* RenderingManager::getCamera() + { + return mCamera.get(); + } + + void RenderingManager::togglePOV() + { + mCamera->toggleViewMode(); + } + + void RenderingManager::togglePreviewMode(bool enable) + { + mCamera->togglePreviewMode(enable); + } + + bool RenderingManager::toggleVanityMode(bool enable) + { + return mCamera->toggleVanityMode(enable); + } + + void RenderingManager::allowVanityMode(bool allow) + { + mCamera->allowVanityMode(allow); + } + + void RenderingManager::togglePlayerLooking(bool enable) + { + mCamera->togglePlayerLooking(enable); + } + + void RenderingManager::changeVanityModeScale(float factor) + { + if(mCamera->isVanityOrPreviewModeEnabled()) + mCamera->setCameraDistance(-factor/120.f*10, true, true); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 32e081995e..bb04d04e17 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -41,6 +41,7 @@ namespace MWRender class SkyManager; class NpcAnimation; class Pathgrid; + class Camera; class RenderingManager : public MWRender::RenderingInterface { @@ -66,7 +67,6 @@ namespace MWRender void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated); - // TODO rename to setRotation/setPosition/setScale, along with the World equivalents void rotateObject(const MWWorld::Ptr& ptr, const osg::Quat& rot); void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); @@ -92,11 +92,28 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); Animation* getPlayerAnimation(); + void updatePlayerPtr(const MWWorld::Ptr &ptr); + void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); + void rebuildPtr(const MWWorld::Ptr& ptr); + void processChangedSettings(const Settings::CategorySettingVector& settings); + // camera stuff + bool vanityRotateCamera(const float *rot); + void setCameraDistance(float dist, bool adjust, bool override); + void resetCamera(); + float getCameraDistance() const; + Camera* getCamera(); + void togglePOV(); + void togglePreviewMode(bool enable); + bool toggleVanityMode(bool enable); + void allowVanityMode(bool allow); + void togglePlayerLooking(bool enable); + void changeVanityModeScale(float factor); + private: void updateProjectionMatrix(); void updateTextureFiltering(); @@ -114,6 +131,7 @@ namespace MWRender std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; + std::auto_ptr mCamera; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d087a40d8c..fd63146f26 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -406,7 +406,7 @@ namespace MWWorld world->getPlayer().setCell(cell); MWWorld::Ptr player = world->getPlayerPtr(); - //mRendering.updatePlayerPtr(player); + mRendering.updatePlayerPtr(player); if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 91484a6ba7..110ed61beb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,6 +37,7 @@ //#include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" +#include "../mwrender/camera.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" @@ -211,7 +212,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); - //mRendering->resetCamera(); + mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -531,7 +532,6 @@ namespace MWWorld void World::useDeathCamera() { -#if 0 if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) { mRendering->getCamera()->togglePreviewMode(false); @@ -539,7 +539,6 @@ namespace MWWorld } if(mRendering->getCamera()->isFirstPerson()) mRendering->getCamera()->toggleViewMode(true); -#endif } MWWorld::Player& World::getPlayer() @@ -1479,7 +1478,7 @@ namespace MWWorld bool World::toggleCollisionMode() { - return 0;//mPhysics->toggleCollisionMode(); + return mPhysics->toggleCollisionMode(); } bool World::toggleRenderMode (MWRender::RenderMode mode) @@ -1607,7 +1606,16 @@ namespace MWWorld } */ - //mWorldScene->playerMoved(mRendering->getEyePos()); + // Sink the camera while sneaking + bool sneaking = getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !isOnGround(getPlayerPtr()); + bool swimming = isSwimming(getPlayerPtr()); + + static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); + if(!paused && sneaking && !(swimming || inair)) + mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); + else + mRendering->getCamera()->setSneakOffset(0.f); } void World::updateSoundListener() @@ -2091,14 +2099,49 @@ namespace MWWorld */ } + void World::togglePOV() + { + mRendering->togglePOV(); + } + + bool World::isFirstPerson() const + { + return mRendering->getCamera()->isFirstPerson(); + } + + void World::togglePreviewMode(bool enable) + { + mRendering->togglePreviewMode(enable); + } + + bool World::toggleVanityMode(bool enable) + { + return mRendering->toggleVanityMode(enable); + } + + void World::allowVanityMode(bool allow) + { + mRendering->allowVanityMode(allow); + } + + void World::togglePlayerLooking(bool enable) + { + mRendering->togglePlayerLooking(enable); + } + + void World::changeVanityModeScale(float factor) + { + mRendering->changeVanityModeScale(factor); + } + bool World::vanityRotateCamera(float * rot) { - return 0;//mRendering->vanityRotateCamera(rot); + return mRendering->vanityRotateCamera(rot); } void World::setCameraDistance(float dist, bool adjust, bool override_) { - //mRendering->setCameraDistance(dist, adjust, override_); + mRendering->setCameraDistance(dist, adjust, override_); } void World::setupPlayer() @@ -2509,7 +2552,7 @@ namespace MWWorld void World::reattachPlayerCamera() { - //mRendering->rebuildPtr(getPlayerPtr()); + mRendering->rebuildPtr(getPlayerPtr()); } void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) @@ -2542,7 +2585,7 @@ namespace MWWorld // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. // the following is just for reattaching the camera properly. - //mRendering->rebuildPtr(actor); + mRendering->rebuildPtr(actor); if(actor == getPlayerPtr()) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 21ad2d7ef2..67d4f863a7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -467,33 +467,19 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; - virtual void togglePOV() { - //mRendering->togglePOV(); - } + virtual void togglePOV(); - virtual bool isFirstPerson() const { - return 0;//mRendering->getCamera()->isFirstPerson(); - } + virtual bool isFirstPerson() const; - virtual void togglePreviewMode(bool enable) { - //mRendering->togglePreviewMode(enable); - } + virtual void togglePreviewMode(bool enable); - virtual bool toggleVanityMode(bool enable) { - return 0;//mRendering->toggleVanityMode(enable); - } + virtual bool toggleVanityMode(bool enable); - virtual void allowVanityMode(bool allow) { - //mRendering->allowVanityMode(allow); - } + virtual void allowVanityMode(bool allow); - virtual void togglePlayerLooking(bool enable) { - //mRendering->togglePlayerLooking(enable); - } + virtual void togglePlayerLooking(bool enable); - virtual void changeVanityModeScale(float factor) { - //mRendering->changeVanityModeScale(factor); - } + virtual void changeVanityModeScale(float factor); virtual bool vanityRotateCamera(float * rot); virtual void setCameraDistance(float dist, bool adjust = false, bool override = true); From 2235d2978b2609db5c94f7e2ef0bfe7b81d77c4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 00:55:43 +0200 Subject: [PATCH 0283/1812] Restore animation text key handling --- apps/openmw/mwmechanics/character.cpp | 141 ++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 7 +- apps/openmw/mwrender/animation.cpp | 9 +- apps/openmw/mwrender/animation.hpp | 11 ++ apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 + apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwworld/scene.cpp | 6 +- 9 files changed, 178 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5769138fad..a89a06091c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -648,6 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; + mAnimation->setTextKeyListener(this); + const MWWorld::Class &cls = mPtr.getClass(); if(cls.isActor()) { @@ -698,8 +700,147 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::~CharacterController() { + if (mAnimation) + mAnimation->setTextKeyListener(NULL); } +void split(const std::string &s, char delim, std::vector &elems) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } +} + +void CharacterController::handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap &map) +{ + const std::string &evt = key->second; + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + std::string soundgen = evt.substr(10); + + // The event can optionally contain volume and pitch modifiers + float volume=1.f, pitch=1.f; + if (soundgen.find(" ") != std::string::npos) + { + std::vector tokens; + split(soundgen, ' ', tokens); + soundgen = tokens[0]; + if (tokens.size() >= 2) + volume = Ogre::StringConverter::parseReal(tokens[1]); + if (tokens.size() >= 3) + pitch = Ogre::StringConverter::parseReal(tokens[2]); + } + + std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); + if(!sound.empty()) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; + if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) + type = MWBase::SoundManager::Play_TypeFoot; + sndMgr->playSound3D(mPtr, sound, volume, pitch, type); + } + return; + } + + if(evt.compare(0, groupname.size(), groupname) != 0 || + evt.compare(groupname.size(), 2, ": ") != 0) + { + // Not ours, skip it + return; + } + size_t off = groupname.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "equip attach") == 0) + mAnimation->showWeapons(true); + else if(evt.compare(off, len, "unequip detach") == 0) + mAnimation->showWeapons(false); + else if(evt.compare(off, len, "chop hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if(evt.compare(off, len, "slash hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if(evt.compare(off, len, "thrust hit") == 0) + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + else if(evt.compare(off, len, "hit") == 0) + { + if (groupname == "attack1") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if (groupname == "attack2") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if (groupname == "attack3") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + else + mPtr.getClass().hit(mPtr); + } + else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 + && evt.compare(off, len, "start") == 0) + { + std::multimap::const_iterator hitKey = key; + + // Not all animations have a hit key defined. If there is none, the hit happens with the start key. + bool hasHitKey = false; + while (hitKey != map.end()) + { + if (hitKey->second == groupname + ": hit") + { + hasHitKey = true; + break; + } + if (hitKey->second == groupname + ": stop") + break; + ++hitKey; + } + if (!hasHitKey) + { + if (groupname == "attack1") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + else if (groupname == "attack2") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + else if (groupname == "attack3") + mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + } + } + else if (evt.compare(off, len, "shoot attach") == 0) + mAnimation->attachArrow(); + else if (evt.compare(off, len, "shoot release") == 0) + {;}//mAnimation->releaseArrow(); + else if (evt.compare(off, len, "shoot follow attach") == 0) + mAnimation->attachArrow(); + + else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") + { + // Make sure this key is actually for the RangeType we are casting. The flame atronach has + // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. + // FIXME: compare with mCurrentWeapon instead + const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); + const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); + int range = 0; + if (evt.compare(off, len, "self release") == 0) + range = 0; + else if (evt.compare(off, len, "touch release") == 0) + range = 1; + else if (evt.compare(off, len, "target release") == 0) + range = 2; + if (effectentry.mRange == range) + { + MWBase::Environment::get().getWorld()->castSpell(mPtr); + } + std::cout << "current attack: " << mCurrentWeapon << std::endl; + } + + else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) + mPtr.getClass().block(mPtr); +} void CharacterController::updatePtr(const MWWorld::Ptr &ptr) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 987a0d29a5..2b21310616 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,6 +7,8 @@ #include "../mwworld/ptr.hpp" +#include "../mwrender/animation.hpp" + namespace MWWorld { class ContainerStoreIterator; @@ -134,7 +136,7 @@ enum JumpingState { JumpState_Landing }; -class CharacterController +class CharacterController : public MWRender::Animation::TextKeyListener { MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; @@ -205,6 +207,9 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map); + // Be careful when to call this, see comment in Actors void updateContinuousVfx(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 416f66cec6..e8d6bbcc94 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -238,6 +238,7 @@ namespace MWRender , mInsert(parentNode) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) + , mTextKeyListener(NULL) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime(this)); @@ -426,7 +427,8 @@ namespace MWRender else if(evt.compare(off, len, "loop stop") == 0) state.mLoopStopTime = key->first; - // TODO: forward to listener? + if (mTextKeyListener) + mTextKeyListener->handleTextKey(groupname, key, map); } void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, @@ -590,6 +592,11 @@ namespace MWRender return true; } + void Animation::setTextKeyListener(Animation::TextKeyListener *listener) + { + mTextKeyListener = listener; + } + void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 82b54bdeaa..20fbbed5ce 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,6 +54,15 @@ public: Group_All = Group_LowerBody | Group_UpperBody }; + class TextKeyListener + { + public: + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) = 0; + }; + + void setTextKeyListener(TextKeyListener* listener); + protected: /* This is the number of *discrete* groups. */ static const size_t sNumGroups = 4; @@ -203,6 +212,8 @@ protected: std::vector mEffects; + TextKeyListener* mTextKeyListener; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 5face96a6e..6c5709b5db 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -158,7 +158,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) mObjects.insert(std::make_pair(ptr, anim.release())); } -bool Objects::deleteObject (const MWWorld::Ptr& ptr) +bool Objects::removeObject (const MWWorld::Ptr& ptr) { if(!ptr.getRefData().getBaseNode()) return true; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 3e1af60873..298dc97bbe 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -66,7 +66,7 @@ public: //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell - bool deleteObject (const MWWorld::Ptr& ptr); + bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? void removeCell(const MWWorld::CellStore* store); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bbff16a10f..9b796a359e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -285,6 +285,11 @@ namespace MWRender ptr.getRefData().getBaseNode()->setScale(scale); } + void RenderingManager::removeObject(const MWWorld::Ptr &ptr) + { + mObjects->removeObject(ptr); + } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { mObjects->updatePtr(old, updated); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bb04d04e17..8a81aacd71 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -71,6 +71,8 @@ namespace MWRender void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos); void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale); + void removeObject(const MWWorld::Ptr& ptr); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fd63146f26..d210ff162f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -210,12 +210,12 @@ namespace MWWorld mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } + MWBase::Environment::get().getMechanicsManager()->drop (*iter); + mRendering.removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); - MWBase::Environment::get().getMechanicsManager()->drop (*iter); - MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); } @@ -563,7 +563,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); - //mRendering.removeObject (ptr); + mRendering.removeObject (ptr); } bool Scene::isCellActive(const CellStore &cell) From 5ea61af6ac19e210b9afc1bfadd043343663f760 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:04 +0200 Subject: [PATCH 0284/1812] Fix for applying view distance --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9b796a359e..def16ae307 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -400,6 +400,7 @@ namespace MWRender else if (it->first == "Viewing distance" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) From d6da5c8007b8798e02002d3ea920f16d1394f515 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:16 +0200 Subject: [PATCH 0285/1812] Fix for crosshair not showing --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index def16ae307..4a28ba9de2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -254,6 +254,7 @@ namespace MWRender { mEffectManager->update(dt); mSky->update(dt); + mCamera->update(dt, paused); } void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) From cac7c1e5351e46d65ec9e80077f1ddc4b0c34fab Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:43:45 +0200 Subject: [PATCH 0286/1812] Restore various physics features --- apps/openmw/mwphysics/physicssystem.cpp | 30 +++++------ apps/openmw/mwphysics/physicssystem.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 69 ++++++++++++------------- 3 files changed, 49 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index db34e04117..840bb3bd61 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -396,16 +396,16 @@ namespace MWPhysics if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { - /* const btCollisionObject* standingOn = tracer.mHitObject; - + /* if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) { standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; } + */ + if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); - */ if (!isFlying) newPosition.z() = tracer.mEndPos.z() + 1.0f; @@ -698,23 +698,21 @@ namespace MWPhysics */ } - std::pair - PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len) + std::pair PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to) { - return std::make_pair(false, Ogre::Vector3()); - /* - Ogre::Ray ray = Ogre::Ray(orig, dir); - Ogre::Vector3 to = ray.getPoint(len); + btVector3 btFrom = toBullet(from); + btVector3 btTo = toBullet(to); - btVector3 btFrom = btVector3(orig.x, orig.y, orig.z); - btVector3 btTo = btVector3(to.x, to.y, to.z); + btCollisionWorld::ClosestRayResultCallback resultCallback(btFrom, btTo); + resultCallback.m_collisionFilterGroup = 0xff; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; - std::pair test = mEngine->rayTest(btFrom, btTo); - if (test.second == -1) { - return std::make_pair(false, Ogre::Vector3()); + mDynamicsWorld->rayTest(btFrom, btTo, resultCallback); + if (resultCallback.hasHit()) + { + return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); } - return std::make_pair(true, ray.getPoint(len * test.second)); - */ + return std::make_pair(false, osg::Vec3f()); } std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 91e166bef4..5f89b1b435 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -86,8 +86,8 @@ namespace MWPhysics // cast ray, return true if it hit something. bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); - std::pair - castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); + /// @return + std::pair castRay(const osg::Vec3f &from, const osg::Vec3f &to); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 110ed61beb..c81a3f71b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include @@ -1888,29 +1890,6 @@ namespace MWWorld Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { -#if 0 - if (!object.getClass().isActor() && adjustPos) - { - // Adjust position so the location we wanted ends up in the middle of the object bounding box - Ogre::Vector3 min, max; - if (mPhysics->getObjectAABB(object, min, max)) { - Ogre::Quaternion xr(Ogre::Radian(-pos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(-pos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(-pos.rot[2]), Ogre::Vector3::UNIT_Z); - - Ogre::Vector3 adjust ( - (min.x + max.x) / 2, - (min.y + max.y) / 2, - min.z - ); - adjust = (xr*yr*zr) * adjust; - pos.pos[0] -= adjust.x; - pos.pos[1] -= adjust.y; - pos.pos[2] -= adjust.z; - } - } -#endif - if (cell->isExterior()) { int cellX, cellY; @@ -1941,6 +1920,28 @@ namespace MWWorld addContainerScripts(dropped, cell); } + if (!object.getClass().isActor() && adjustPos && dropped.getRefData().getBaseNode()) + { + // Adjust position so the location we wanted ends up in the middle of the object bounding box + osg::ComputeBoundsVisitor computeBounds; + dropped.getRefData().getBaseNode()->accept(computeBounds); + osg::BoundingBox bounds = computeBounds.getBoundingBox(); + if (bounds.valid()) + { + bounds.set(bounds._min - pos.asVec3(), bounds._max - pos.asVec3()); + + osg::Vec3f adjust ( + (bounds.xMin() + bounds.xMax()) / 2, + (bounds.yMin() + bounds.yMax()) / 2, + bounds.zMin() + ); + pos.pos[0] -= adjust.x(); + pos.pos[1] -= adjust.y(); + pos.pos[2] -= adjust.z(); + moveObject(dropped, pos.pos[0], pos.pos[1], pos.pos[2]); + } + } + return dropped; } @@ -1954,17 +1955,15 @@ namespace MWWorld pos.rot[0] = 0; pos.rot[1] = 0; - Ogre::Vector3 orig = - Ogre::Vector3(pos.pos); - orig.z += 20; - //Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); + osg::Vec3f orig = pos.asVec3(); + orig.z() += 20; + osg::Vec3f dir (0, 0, -1); - //float len = 100.0; + float len = 100.0; - std::pair hit;// = - //mPhysics->castRay(orig, dir, len); + std::pair hit = mPhysics->castRay(orig, dir*len); if (hit.first) - pos.pos[2] = hit.second.z; + pos.pos[2] = hit.second.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); @@ -2069,14 +2068,12 @@ namespace MWWorld // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - return true; - /* - //RefData &refdata = ptr.getRefData(); - OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle()); + MWPhysics::Actor* physactor = mPhysics->getActor(ptr); if(!physactor) return false; - + return physactor->getOnGround(); + /* if(physactor->getOnGround()) return true; else From 627fee07bc2f91d7b062665f9e24984206e24240 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 01:54:06 +0200 Subject: [PATCH 0287/1812] Minor cleanup --- apps/openmw/mwrender/characterpreview.hpp | 2 -- apps/openmw/mwrender/creatureanimation.cpp | 16 +++------------- apps/openmw/mwrender/objects.hpp | 3 --- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwrender/sky.hpp | 8 ++++---- apps/openmw/mwworld/weather.cpp | 2 +- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index b7722d1f38..0f85cc3bf9 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -1,8 +1,6 @@ #ifndef MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H -#include - #include #include diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index e15dee5320..810fc8b196 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -145,16 +145,6 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) */ } -/* -void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) -{ - //Ogre::Vector3 glowColor = getEnchantmentColor(ptr); - - //setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0, - // !ptr.getClass().getEnchantment(ptr).empty(), &glowColor); -} -*/ - void CreatureWeaponAnimation::attachArrow() { //WeaponAnimation::attachArrow(mPtr); @@ -167,14 +157,14 @@ void CreatureWeaponAnimation::releaseArrow() osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { - /* - Ogre::Vector3 ret = Animation::runAnimation(duration); + osg::Vec3f ret = Animation::runAnimation(duration); + /* if (mSkelBase) pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); */ - return osg::Vec3f(); + return ret; } } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 298dc97bbe..716192959d 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -63,9 +63,6 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - //Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); - ///< get a bounding box that encloses all objects in the specified cell - bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 2f3a87c5b2..6b432ae5e1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -799,7 +799,7 @@ void SkyManager::sunDisable() mSun->setVisible(false); } -void SkyManager::setStormDirection(const Ogre::Vector3 &direction) +void SkyManager::setStormDirection(const osg::Vec3f &direction) { mStormDirection = direction; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ebf3ee87fc..652de28b42 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -59,7 +59,7 @@ namespace MWRender void setRainSpeed(float speed); - void setStormDirection(const Ogre::Vector3& direction); + void setStormDirection(const osg::Vec3f& direction); void setSunDirection(const osg::Vec3f& direction); @@ -123,11 +123,11 @@ namespace MWRender float mRainTimer; - Ogre::Vector3 mStormDirection; + osg::Vec3f mStormDirection; // remember some settings so we don't have to apply them again if they didnt change - Ogre::String mClouds; - Ogre::String mNextClouds; + std::string mClouds; + std::string mNextClouds; float mCloudBlendFactor; float mCloudOpacity; float mCloudSpeed; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b37a383530..655e0a0734 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -420,7 +420,7 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; - //mRendering->getSkyManager()->setStormDirection(mStormDirection); + mRendering->getSkyManager()->setStormDirection(mStormDirection); } mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); From 85345e663a19c5dc3920822730b994ca6c077bc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 04:36:17 +0200 Subject: [PATCH 0288/1812] Restore getHitContact --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwphysics/actor.hpp | 5 ++ apps/openmw/mwphysics/physicssystem.cpp | 77 ++++++++++++++++++----- apps/openmw/mwphysics/physicssystem.hpp | 8 ++- apps/openmw/mwrender/renderingmanager.cpp | 3 + apps/openmw/mwworld/worldimp.cpp | 36 +++++------ apps/openmw/mwworld/worldimp.hpp | 2 +- 9 files changed, 97 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 008d64aafc..88dbf89f89 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -262,7 +262,7 @@ namespace MWBase /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1e41aea247..b6eb930c94 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -238,7 +238,7 @@ namespace MWClass const float fCombatDistance = gmst.find("fCombatDistance")->getFloat(); dist = fCombatDistance * weapon.get()->mBase->mData.mReach; } - std::pair result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist); + std::pair result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist); if (result.first.isEmpty()) return; // Didn't hit anything @@ -247,7 +247,7 @@ namespace MWClass if (!victim.getClass().isActor()) return; // Can't hit non-actors - Ogre::Vector3 hitPosition = result.second; + Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 463209df8d..829862ad19 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -491,9 +491,9 @@ namespace MWClass store.find("fHandToHandReach")->getFloat()); // TODO: Use second to work out the hit angle - std::pair result = world->getHitContact(ptr, dist); + std::pair result = world->getHitContact(ptr, dist); MWWorld::Ptr victim = result.first; - Ogre::Vector3 hitPosition = result.second; + Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); if(victim.isEmpty()) // Didn't hit anything return; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 513985c94c..60de421511 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -31,6 +31,11 @@ namespace MWPhysics mPtr = updated; } + MWWorld::Ptr getPtr() const + { + return mPtr; + } + protected: MWWorld::Ptr mPtr; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 840bb3bd61..afc81da8b6 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -653,35 +653,78 @@ namespace MWPhysics return mDebugDrawEnabled; } - std::pair PhysicsSystem::getHitContact(const std::string &name, - const Ogre::Vector3 &origin, - const Ogre::Quaternion &orient, + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + const btCollisionObject* mMe; + + // Store the real origin, since the shape's origin is its center + btVector3 mOrigin; + + public: + const btCollisionObject *mObject; + btVector3 mContactPoint; + btScalar mLeastDistSqr; + + DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const btVector3 &origin) + : mMe(me), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0), + mLeastDistSqr(std::numeric_limits::max()) + { } + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + if (col1Wrap->m_collisionObject != mMe) + { + btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); + if(!mObject || distsqr < mLeastDistSqr) + { + mObject = col1Wrap->m_collisionObject; + mLeastDistSqr = distsqr; + mContactPoint = cp.getPositionWorldOnA(); + } + } + + return 0.f; + } + }; + + std::pair PhysicsSystem::getHitContact(const MWWorld::Ptr& actor, + const osg::Vec3f &origin, + const osg::Quat &orient, float queryDistance) { - return std::make_pair(std::string(), Ogre::Vector3()); - /* const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(), - queryDistance); - shape.setLocalScaling(btVector3(1, 1, Ogre::Degree(store.find("fCombatAngleZ")->getFloat()/2.0f).valueRadians() / + btConeShape shape (osg::DegreesToRadians(store.find("fCombatAngleXY")->getFloat()/2.0f), queryDistance); + shape.setLocalScaling(btVector3(1, 1, osg::DegreesToRadians(store.find("fCombatAngleZ")->getFloat()/2.0f) / shape.getRadius())); // The shape origin is its center, so we have to move it forward by half the length. The // real origin will be provided to getFilteredContact to find the closest. - Ogre::Vector3 center = origin + (orient * Ogre::Vector3(0.0f, queryDistance*0.5f, 0.0f)); + osg::Vec3f center = origin + (orient * osg::Vec3f(0.0f, queryDistance*0.5f, 0.0f)); btCollisionObject object; object.setCollisionShape(&shape); - object.setWorldTransform(btTransform(btQuaternion(orient.x, orient.y, orient.z, orient.w), - btVector3(center.x, center.y, center.z))); + object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); - std::pair result = mEngine->getFilteredContact( - name, btVector3(origin.x, origin.y, origin.z), &object); - if(!result.first) - return std::make_pair(std::string(), Ogre::Vector3(&result.second[0])); - return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0])); - */ + const btCollisionObject* me = NULL; + Actor* physactor = getActor(actor); + if (physactor) + me = physactor->getCollisionObject(); + + DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); + resultCallback.m_collisionFilterGroup = CollisionType_Actor; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; + mDynamicsWorld->contactTest(&object, resultCallback); + + if (resultCallback.mObject) + { + const PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); + if (holder) + return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); + } + return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 5f89b1b435..aca24105ed 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -11,6 +11,8 @@ #include "../mwworld/ptr.hpp" +#include + namespace osg { class Group; @@ -78,9 +80,9 @@ namespace MWPhysics std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getHitContact(const std::string &name, - const Ogre::Vector3 &origin, - const Ogre::Quaternion &orientation, + std::pair getHitContact(const MWWorld::Ptr& actor, + const osg::Vec3f &origin, + const osg::Quat &orientation, float queryDistance); // cast ray, return true if it hit something. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a28ba9de2..af4e46f627 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -315,6 +315,9 @@ namespace MWRender MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { + if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) + return mPlayerAnimation.get(); + return mObjects->getAnimation(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c81a3f71b9..35b6fc1035 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,7 +37,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" #include "../mwrender/camera.hpp" @@ -1052,32 +1052,32 @@ namespace MWWorld //return getPtrViaHandle(facedHandle); } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { - /* const ESM::Position &posdata = ptr.getRefData().getPosition(); - Ogre::Vector3 pos(posdata.pos); - Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(posdata.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); - MWRender::Animation *anim = mRendering->getAnimation(ptr); - if(anim != NULL) + osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos (posdata.asVec3()); + + MWRender::Animation* anim = mRendering->getAnimation(ptr); + if (anim != NULL) { - Ogre::Node *node = anim->getNode("Head"); + const osg::Node* node = anim->getNode("Head"); if (node == NULL) node = anim->getNode("Bip01 Head"); - if(node != NULL) - pos += node->_getDerivedPosition(); + if (node != NULL) + { + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + pos = mats[0].getTrans(); + } } - std::pair result;// = mPhysics->getHitContact(ptr.getRefData().getHandle(), - // pos, rot, distance); - if(result.first.empty()) - return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); + std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); + if(result.first.isEmpty()) + return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); - return std::make_pair(searchPtrViaHandle(result.first), result.second); - */ - return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); + return std::make_pair(result.first, result.second); } void World::deleteObject (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 67d4f863a7..8b47723095 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -344,7 +344,7 @@ namespace MWWorld /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); virtual void deleteObject (const Ptr& ptr); virtual void undeleteObject (const Ptr& ptr); From 0fb59178b614530a2a1ce5bb0ce81140217e882f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 May 2015 20:15:50 +0200 Subject: [PATCH 0289/1812] Settings file cleanup --- files/settings-default.cfg | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index fc8571bf86..64ef4e302c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -87,13 +87,6 @@ crosshair = true [Objects] shaders = true -# Max. number of lights that affect objects. Setting to 1 will only reflect sunlight -# Note: has no effect when shaders are turned off -num lights = 8 - -# Use static geometry for static objects. Improves rendering speed. -use static geometry = true - [Map] # Adjusts the scale of the global map global map cell size = 18 @@ -114,12 +107,6 @@ exterior grid size = 3 # exact factor would depend on FOV viewing distance = 4600 -# Distance at which fog starts (proportional to viewing distance) -fog start factor = 0.5 - -# Distance at which fog ends (proportional to viewing distance) -fog end factor = 1.0 - # Culling of objects smaller than a pixel small feature culling = true From 8092f37ce5e9ef6dd7009c703fd1c01f395f6b44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:40:24 +0200 Subject: [PATCH 0290/1812] New game crash fix --- apps/openmw/mwrender/camera.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index a92f901583..3982e5ad40 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -351,12 +351,6 @@ namespace MWRender void Camera::setAnimation(NpcAnimation *anim) { - // If we're switching to a new NpcAnimation, ensure the old one is - // using a normal view mode - if(mAnimation && mAnimation != anim) - { - mAnimation->setViewMode(NpcAnimation::VM_Normal); - } mAnimation = anim; processViewChange(); From cd81ec92db13d8ca440b75b3a8b1fe21a8378b42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:41:53 +0200 Subject: [PATCH 0291/1812] Minor cleanup --- apps/openmw/mwworld/refdata.cpp | 4 ---- apps/openmw/mwworld/refdata.hpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index a95a66f7e2..c14ad69300 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -128,10 +128,6 @@ namespace MWWorld return mBaseNode; } - void RefData::setBaseNodeOld(Ogre::SceneNode* base) - { - } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) { mBase = base; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 5951cb1015..b5b1f15604 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -88,10 +88,6 @@ namespace MWWorld /// Return base node (can be a null pointer). osg::PositionAttitudeTransform* getBaseNode(); - /// Set OGRE base node (can be a null pointer). - /// obsolete - void setBaseNodeOld (Ogre::SceneNode* base); - /// Set base node (can be a null pointer). void setBaseNode (osg::PositionAttitudeTransform* base); From 04e827ecf6446910dc8127ab10fe689ad8d3c684 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:42:21 +0200 Subject: [PATCH 0292/1812] Don't try to play an empty video --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 35b6fc1035..30be5a00cf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -260,7 +260,11 @@ namespace MWWorld } if (!bypass) - MWBase::Environment::get().getWindowManager()->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); + { + std::string video = mFallback.getFallbackString("Movies_New_Game"); + if (!video.empty()) + MWBase::Environment::get().getWindowManager()->playVideo(video, true); + } // enable collision //if (!mPhysics->toggleCollisionMode()) From 0b042b75cc9b098f66d555d534c04a7f41fc0fd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 05:42:37 +0200 Subject: [PATCH 0293/1812] Restore actor visibility mask --- apps/openmw/mwrender/objects.cpp | 3 +++ apps/openmw/mwrender/vismask.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6c5709b5db..237e90b742 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -22,6 +22,7 @@ #include "animation.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" +#include "vismask.hpp" namespace { @@ -131,6 +132,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, bool weaponsShields) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); // CreatureAnimation std::auto_ptr anim; @@ -149,6 +151,7 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b void Objects::insertNPC(const MWWorld::Ptr &ptr) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 8726955568..512f9f4ad6 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -12,6 +12,7 @@ namespace MWRender // child of Scene Mask_Effect = 0x2, Mask_Debug = 0x4, + Mask_Actor = 0x8, // top level masks Mask_Scene = 0x10, From 0de6839890a397e883258bdf533f76040709dcac Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 06:07:11 +0200 Subject: [PATCH 0294/1812] Minor cleanup --- apps/openmw/mwworld/worldimp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 30be5a00cf..70751e445c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -267,8 +267,8 @@ namespace MWWorld } // enable collision - //if (!mPhysics->toggleCollisionMode()) - // mPhysics->toggleCollisionMode(); + if (!mPhysics->toggleCollisionMode()) + mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game delete mWeatherManager; @@ -972,7 +972,7 @@ namespace MWWorld void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - //mPhysics->clearQueuedMovement(); + mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != cellName) { @@ -992,7 +992,7 @@ namespace MWWorld void World::changeToExteriorCell (const ESM::Position& position) { - //mPhysics->clearQueuedMovement(); + mPhysics->clearQueuedMovement(); if (mCurrentWorldSpace != "sys::default") // FIXME { From f2809ab63b92c9ec7d17c301dafaf2760ec9ded4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 06:53:26 +0200 Subject: [PATCH 0295/1812] Delete nifosgtest again --- CMakeLists.txt | 2 - apps/nifosgtest/CMakeLists.txt | 7 -- apps/nifosgtest/test.cpp | 166 --------------------------------- 3 files changed, 175 deletions(-) delete mode 100644 apps/nifosgtest/CMakeLists.txt delete mode 100644 apps/nifosgtest/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d0515a1fb6..4b6ede3ddc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,8 +473,6 @@ if (BUILD_NIFTEST) endif(BUILD_NIFTEST) # Apps and tools -add_subdirectory( apps/nifosgtest ) - if (BUILD_OPENMW) add_subdirectory( apps/openmw ) endif() diff --git a/apps/nifosgtest/CMakeLists.txt b/apps/nifosgtest/CMakeLists.txt deleted file mode 100644 index 265577d989..0000000000 --- a/apps/nifosgtest/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set (FILES - test.cpp -) - -add_executable (test ${FILES}) - -target_link_libraries (test ${OPENSCENEGRAPH_LIBRARIES} "components") diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp deleted file mode 100644 index 6d05867755..0000000000 --- a/apps/nifosgtest/test.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#include - -#include -#include - -#include - -#include - -// EventHandler to toggle wireframe when 'w' key is pressed -class WireframeKeyHandler : public osgGA::GUIEventHandler -{ -public: - WireframeKeyHandler(osg::Node* node) - : mWireframe(false) - , mNode(node) - { - - } - - virtual bool handle(const osgGA::GUIEventAdapter& adapter,osgGA::GUIActionAdapter& action) - { - switch (adapter.getEventType()) - { - case osgGA::GUIEventAdapter::KEYDOWN: - if (adapter.getKey() == osgGA::GUIEventAdapter::KEY_W) - { - mWireframe = !mWireframe; - osg::PolygonMode* mode = new osg::PolygonMode; - mode->setMode(osg::PolygonMode::FRONT_AND_BACK, - mWireframe ? osg::PolygonMode::LINE : osg::PolygonMode::FILL); - - // Create a new stateset instead of changing the old one, this alleviates the need to set - // the StateSet to DYNAMIC DataVariance, which would have a performance impact. - - osg::StateSet* stateset = new osg::StateSet; - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, mWireframe ? osg::StateAttribute::OFF - : osg::StateAttribute::ON); - - mNode->setStateSet(stateset); - - return true; - } - default: - break; - } - return false; - } - -private: - bool mWireframe; - osg::Node* mNode; -}; - -int main(int argc, char** argv) -{ - if (argc < 2) - { - std::cout << "Usage: " << argv[0] << " " << std::endl; - return 1; - } - - Files::ConfigurationManager cfgMgr; - boost::program_options::options_description desc(""); - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()); - - boost::program_options::variables_map variables; - cfgMgr.readConfiguration(variables, desc); - - std::vector archives = variables["fallback-archive"].as >(); - bool fsStrict = variables["fs-strict"].as(); - Files::PathContainer dataDirs; - if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); - } - - cfgMgr.processPaths(dataDirs); - - VFS::Manager resourceMgr (fsStrict); - Files::Collections collections (dataDirs, !fsStrict); - - for (std::vector::const_iterator it = archives.begin(); it != archives.end(); ++it) - { - std::string filepath = collections.getPath(*it).string(); - resourceMgr.addArchive(new VFS::BsaArchive(filepath)); - } - for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) - { - resourceMgr.addArchive(new VFS::FileSystemArchive(it->string())); - } - - resourceMgr.buildIndex(); - - Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); - - // For NiStencilProperty - osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); - - osgViewer::Viewer viewer; - - osg::ref_ptr root(new osg::Group()); - root->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - // To prevent lighting issues with scaled meshes - root->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); - - - //osgDB::writeNodeFile(*newNode, "out.osg"); - osg::Group* newNode = new osg::Group; - NifOsg::Loader loader; - Resource::TextureManager texMgr(&resourceMgr); - newNode->addChild(loader.load(nif, &texMgr)); - - SceneUtil::AssignControllerSourcesVisitor visitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - newNode->accept(visitor); - - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - root->addChild(trans); - - for (int x=0; x<1;++x) - { - //root->addChild(newNode); - trans->addChild(newNode); - } - - viewer.setSceneData(root); - - viewer.setUpViewInWindow(0, 0, 800, 600); - viewer.realize(); - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - viewer.addEventHandler(new WireframeKeyHandler(root)); - - // Mask to separate cull visitors from update visitors - viewer.getCamera()->setCullMask(~(0x1)); - - viewer.addEventHandler(new osgViewer::StatsHandler); - - while (!viewer.done()) - { - //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); - - viewer.frame(); - } - - return 0; -} From da24e298ee152807ae2bc6cff30c4b13ae5b395e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 22:44:00 +0200 Subject: [PATCH 0296/1812] Fix -Wreorder warnings --- apps/opencs/view/render/object.cpp | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 6 +++--- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- apps/openmw/mwrender/objects.cpp | 4 ++-- apps/openmw/mwrender/pathgrid.cpp | 6 +++--- apps/openmw/mwrender/sky.cpp | 4 ++-- components/nif/niffile.cpp | 2 +- components/nifosg/controller.cpp | 2 +- components/nifosg/particle.cpp | 2 +- components/nifosg/particle.hpp | 2 +- components/sceneutil/lightcontroller.cpp | 2 +- components/sceneutil/skeleton.cpp | 4 ++-- 16 files changed, 26 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ec184a5636..6ddea913ad 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -115,7 +115,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mResourceSystem(data.getResourceSystem()), mData (data), mBaseNode(0), mParentNode(parentNode), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5ce1607b5a..08dba334fa 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -204,8 +204,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFSStrict (false) , mScriptBlacklistUse (true) , mNewGame (false) - , mCfgMgr(configurationManager) , mSimulationTime(0.0) + , mCfgMgr(configurationManager) { Misc::Rng::init(); MWClass::registerClasses(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e9c973fc37..b96e79ca92 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -54,8 +54,6 @@ namespace MWGui InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") - , mViewer(viewer) - , mResourceSystem(resourceSystem) , mDragAndDrop(dragAndDrop) , mSelectedItem(-1) , mSortModel(NULL) @@ -63,6 +61,8 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) + , mResourceSystem(resourceSystem) + , mViewer(viewer) , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mTrading(false) { diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7a3dd5e18f..1b5abc099f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -131,8 +131,8 @@ namespace MWInput , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) , mSneaking(false) , mAttemptJump(false) - , mFakeDeviceID(1) , mInvUiScalingFactor(1.f) + , mFakeDeviceID(1) { mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setMouseEventCallback (this); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index afc81da8b6..b32ac2f52c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -590,10 +590,10 @@ namespace MWPhysics PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) - , mTimeAccum(0.0f) - , mWaterEnabled(false) - , mWaterHeight(0) , mDebugDrawEnabled(false) + , mTimeAccum(0.0f) + , mWaterHeight(0) + , mWaterEnabled(false) , mParentNode(parentNode) { mCollisionConfiguration = new btDefaultCollisionConfiguration(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e8d6bbcc94..1c436d4403 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -234,8 +234,8 @@ namespace MWRender }; Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) - : mPtr(ptr) - , mInsert(parentNode) + : mInsert(parentNode) + , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) , mTextKeyListener(NULL) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5fafa6d592..aeff1f60ae 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -186,17 +186,16 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } - NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) : Animation(ptr, parentNode, resourceSystem), - mVisibilityFlags(visibilityFlags), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), //mFirstPersonOffset(0.f, 0.f, 0.f), - mAlpha(1.f), mNpcType(Type_Normal), + mVisibilityFlags(visibilityFlags), + mAlpha(1.f), mSoundsDisabled(disableSounds) //mHeadPitch(0.f), //mHeadYaw(0.f) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 237e90b742..3d981a9c7b 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -65,8 +65,8 @@ namespace MWRender { Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode) - : mResourceSystem(resourceSystem) - , mRootNode(rootNode) + : mRootNode(rootNode) + , mResourceSystem(resourceSystem) { } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 5e559eeed1..9fffd76d10 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -125,10 +125,10 @@ osg::ref_ptr Pathgrid::createPathgridPoints(const ESM::Pathgrid * } Pathgrid::Pathgrid(osg::ref_ptr root) - : mRootNode(root) - , mPathgridEnabled(false) - , mInteriorPathgridNode(NULL) + : mPathgridEnabled(false) + , mRootNode(root) , mPathGridRoot(NULL) + , mInteriorPathgridNode(NULL) { } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6b432ae5e1..43c88427ec 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -326,8 +326,8 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) - , mPhase(Phase_Unspecified) , mType(type) + , mPhase(Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); @@ -487,6 +487,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mMonth(0) , mCloudAnimationTimer(0.f) , mRainTimer(0.f) + , mStormDirection(0,-1,0) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) @@ -503,7 +504,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSunEnabled(true) , mMasserEnabled(true) , mSecundaEnabled(true) - , mStormDirection(0,-1,0) { osg::ref_ptr skyroot (new CameraRelativeTransform); parentNode->addChild(skyroot); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index a73985cfb1..0a6f8f505f 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -11,8 +11,8 @@ namespace Nif NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) - , mStream(stream) , mUseSkinning(false) + , mStream(stream) { parse(); } diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 27665b6c64..d676bc3f8d 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -349,7 +349,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetUpdater(copy, copyop), ValueInterpolator(), Controller(copy) + : StateSetUpdater(copy, copyop), Controller(copy), ValueInterpolator() , mData(copy.mData) { } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 3cfd91f1f0..b733987d03 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -155,9 +155,9 @@ void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* d GravityAffector::GravityAffector(const Nif::NiGravity *gravity) : mForce(gravity->mForce) , mType(static_cast(gravity->mType)) - , mDecay(gravity->mDecay) , mPosition(gravity->mPosition) , mDirection(gravity->mDirection) + , mDecay(gravity->mDecay) { } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 416477cddb..5e463aae3d 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -61,7 +61,7 @@ namespace NifOsg { } InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) - : osg::NodeCallback(), osg::Object() + : osg::Object(), osg::NodeCallback() { } diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 484cea4476..d31e3d1075 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -47,9 +47,9 @@ namespace SceneUtil LightController::LightController() : mType(LT_Normal) , mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f) - , mLastTime(0.0) , mDeltaCount(0.f) , mDirection(1.f) + , mLastTime(0.0) { } diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index f105977bad..96941126b9 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -34,8 +34,8 @@ private: Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) - , mLastFrameNumber(0) , mActive(true) + , mLastFrameNumber(0) { } @@ -44,8 +44,8 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) - , mLastFrameNumber(0) , mActive(copy.mActive) + , mLastFrameNumber(0) { } From 152d690a7aea9b0f890aaa0fe9185e96609a1a37 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 May 2015 23:10:53 +0200 Subject: [PATCH 0297/1812] Minor cleanup --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/npc.cpp | 6 +-- apps/openmw/mwrender/localmap.cpp | 60 ++++++++++++++----------- apps/openmw/mwrender/localmap.hpp | 9 +--- apps/openmw/mwsound/loudness.cpp | 3 +- apps/openmw/mwsound/soundmanagerimp.hpp | 2 - 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 941222b0c6..d45e76f258 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap characterpreview camera -# localmap occlusionquery water shadows + bulletdebugdraw globalmap characterpreview camera localmap +# occlusionquery water shadows # ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b55ececc21..791c2f57e2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1148,9 +1148,9 @@ namespace MWClass if (ptr.getClass().getNpcStats(ptr).isWerewolf() && ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)) { - //MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; - //MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); - //if (weaponType == MWMechanics::WeapType_None) + MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None; + MWMechanics::getActiveWeapon(ptr.getClass().getCreatureStats(ptr), ptr.getClass().getInventoryStore(ptr), &weaponType); + if (weaponType == MWMechanics::WeapType_None) return ""; } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b692226642..f675fe1d8e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -18,30 +19,20 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" -#include "renderconst.hpp" -#include "renderingmanager.hpp" using namespace MWRender; using namespace Ogre; -LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) +LocalMap::LocalMap() : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) , mAngle(0.f) , mInterior(false) { - mRendering = rend; - mRenderingManager = rendering; - - mCameraPosNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); - mCameraRotNode = mCameraPosNode->createChildSceneNode(); - mCameraNode = mCameraRotNode->createChildSceneNode(); - - mCellCamera = mRendering->getScene()->createCamera("CellCamera"); + // mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); mCameraNode->attachObject(mCellCamera); - mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); mLight->setVisible (false); @@ -62,7 +53,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setVisibilityMask(RV_Map); vp->setMaterialScheme("local_map"); } @@ -83,12 +73,11 @@ std::string LocalMap::coordStr(const int x, const int y) void LocalMap::clear() { - // Not actually removing the Textures here. That doesnt appear to work properly. It seems MyGUI still keeps some pointers. - mBuffers.clear(); } void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { + /* if (!mInterior) { std::string textureName = "Cell_"+coordStr(cell->getCell()->getGridX(), cell->getCell()->getGridY())+"_fog"; @@ -156,6 +145,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) cell->setFog(fog.release()); } + */ } void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) @@ -177,6 +167,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) // (and objects in a different cell can "bleed" into another cell's map if they cross the border) render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); + /* if (mBuffers.find(name) == mBuffers.end()) { if (cell->getFog()) @@ -184,6 +175,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) else createFogOfWar(name); } + */ } void LocalMap::requestMap(MWWorld::CellStore* cell, @@ -241,6 +233,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not // be covered by the map anymore. // The following code detects this, and discards the CellStore's fog state if it needs to. + /* if (cell->getFog()) { ESM::FogState* fog = cell->getFog(); @@ -265,6 +258,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mAngle = fog->mNorthMarkerAngle; } } + */ Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); @@ -296,6 +290,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + /* if (!cell->getFog()) createFogOfWar(texturePrefix); else @@ -309,6 +304,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, ESM::FogTexture& esm = fog->mFogTextures[i]; loadFogOfWar(texturePrefix, esm); } + */ ++i; } } @@ -316,6 +312,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, void LocalMap::createFogOfWar(const std::string& texturePrefix) { + /* const std::string texName = texturePrefix + "_fog"; TexturePtr tex = createFogOfWarTexture(texName); @@ -331,12 +328,14 @@ void LocalMap::createFogOfWar(const std::string& texturePrefix) tex->getBuffer()->unlock(); mBuffers[texturePrefix] = buffer; + */ } Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) { - TexturePtr tex = TextureManager::getSingleton().getByName(texName); - if (tex.isNull()) + TexturePtr tex;// = TextureManager::getSingleton().getByName(texName); + /* + * if (tex.isNull()) { tex = TextureManager::getSingleton().createManual( texName, @@ -349,12 +348,14 @@ Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D) ); } + */ return tex; } void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) { + /* std::vector& data = esm.mImageData; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; @@ -376,6 +377,7 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& memcpy(&buffer[0], image.getData(), image.getSize()); mBuffers[texturePrefix] = buffer; + */ } void LocalMap::render(const float x, const float y, @@ -390,15 +392,12 @@ void LocalMap::render(const float x, const float y, // disable fog (only necessary for fixed function, the shader based // materials already do this through local_map material configuration) - float oldFogStart = mRendering->getScene()->getFogStart(); - float oldFogEnd = mRendering->getScene()->getFogEnd(); - Ogre::ColourValue oldFogColour = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); + //mRendering->getScene()->setFog(FOG_NONE); // set up lighting - Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); - mRenderingManager->disableLights(true); + //Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); + //mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); + //mRenderingManager->disableLights(true); mLight->setVisible(true); TexturePtr tex; @@ -425,12 +424,12 @@ void LocalMap::render(const float x, const float y, tex->getBuffer()->blit(mRenderTexture->getBuffer()); } - mRenderingManager->enableLights(true); + //mRenderingManager->enableLights(true); mLight->setVisible(false); // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); - mRendering->getScene()->setAmbientLight(oldAmbient); + //mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); + //mRendering->getScene()->setAmbientLight(oldAmbient); } void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) @@ -460,6 +459,8 @@ Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, i bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { + return false; + /* std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); if (mBuffers.find(texName) == mBuffers.end()) @@ -474,10 +475,12 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; uint8 alpha = (clr >> 24); return alpha < 200; + */ } void LocalMap::loadResource(Ogre::Resource* resource) { + /* std::string resourceName = resource->getName(); size_t pos = resourceName.find("_fog"); if (pos != std::string::npos) @@ -498,10 +501,12 @@ void LocalMap::loadResource(Ogre::Resource* resource) tex->createInternalResources(); memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); tex->getBuffer()->unlock(); + */ } void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) { + /* if (sFogOfWarSkip != 0) { static int count=0; @@ -607,4 +612,5 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } } } + */ } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 014c67f164..d0d7d73d25 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,8 +1,6 @@ #ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H -#include - #include #include #include @@ -24,10 +22,10 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap : public Ogre::ManualResourceLoader + class LocalMap { public: - LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); + LocalMap(); ~LocalMap(); virtual void loadResource(Ogre::Resource* resource); @@ -84,9 +82,6 @@ namespace MWRender bool isPositionExplored (float nX, float nY, int x, int y, bool interior); private: - OEngine::Render::OgreRenderer* mRendering; - MWRender::RenderingManager* mRenderingManager; - int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 9446a1daea..1e6872a766 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -1,6 +1,7 @@ #include "loudness.hpp" #include +#include #include "soundmanagerimp.hpp" @@ -31,7 +32,7 @@ namespace MWSound else if (type == SampleType_Int16) { value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); + value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 27af1e65b9..f79bfce155 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -7,8 +7,6 @@ #include -#include - #include #include "../mwbase/soundmanager.hpp" From 9a0db5d55ae1976d80d677ebfd9ee481e30a41e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 01:32:00 +0200 Subject: [PATCH 0298/1812] Restore cell changes --- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4f7a5b87f9..442f493c13 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1128,7 +1128,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - Ogre::Vector3 vec(x, y, z); + osg::Vec3f vec(x, y, z); CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup bool isPlayer = ptr == mPlayer->getPlayer(); @@ -1207,12 +1207,12 @@ namespace MWWorld } if (haveToMove && newPtr.getRefData().getBaseNode()) { - mRendering->moveObject(newPtr, osg::Vec3f(vec.x, vec.y, vec.z)); + mRendering->moveObject(newPtr, vec); mPhysics->updatePosition(newPtr); } if (isPlayer) { - //mWorldScene->playerMoved (vec); + mWorldScene->playerMoved(vec); } return newPtr; } From c748ea73632d86a18be87f0bb58956433c9b5b63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 01:40:49 +0200 Subject: [PATCH 0299/1812] Fix view distance slider --- files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 66514c886e..3fb4adf42f 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -345,7 +345,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 64ef4e302c..6653966cfa 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -102,10 +102,10 @@ exterior grid size = 3 [Viewing distance] # Viewing distance at normal weather conditions # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) -# viewing distance / minimum weather fog depth (.69) * view frustum factor <= cell size (8192) - loading threshold (1024) +# viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) # view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. # exact factor would depend on FOV -viewing distance = 4600 +viewing distance = 6666 # Culling of objects smaller than a pixel small feature culling = true From c2131e7c31cb331ce8c9bfe48d26fcb2d4a2bbda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 02:34:20 +0200 Subject: [PATCH 0300/1812] Make near clip distance configurable --- apps/openmw/mwrender/renderingmanager.cpp | 11 ++++++----- apps/openmw/mwrender/renderingmanager.hpp | 1 + files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 5 +++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index af4e46f627..b8620d60b0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -132,7 +132,7 @@ namespace MWRender osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; - if (!Settings::Manager::getBool("small feature culling", "Viewing distance")) + if (!Settings::Manager::getBool("small feature culling", "Camera")) cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); else cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; @@ -144,7 +144,8 @@ namespace MWRender mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); - mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mNearClip = Settings::Manager::getFloat("near clip", "Camera"); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); } @@ -372,7 +373,7 @@ namespace MWRender double fovy, aspect, zNear, zFar; mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); fovy = mFieldOfView; - zNear = 5.f; + zNear = mNearClip; zFar = mViewDistance; mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); } @@ -401,9 +402,9 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); } - else if (it->first == "Viewing distance" && it->second == "viewing distance") + else if (it->first == "Camera" && it->second == "viewing distance") { - mViewDistance = Settings::Manager::getFloat("viewing distance", "Viewing distance"); + mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8a81aacd71..2978c99835 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -137,6 +137,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 3fb4adf42f..19e3bcf886 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -341,7 +341,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6653966cfa..0581d73562 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -99,8 +99,9 @@ local map hud widget size = 256 [Cells] exterior grid size = 3 -[Viewing distance] -# Viewing distance at normal weather conditions +[Camera] +near clip = 5 + # The maximum distance with no pop-in will be: (see RenderingManager::configureFog) # viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) # view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. From 8b322fcd062d7786cdcc0d97979987e40fca881f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 03:36:34 +0200 Subject: [PATCH 0301/1812] Implement getFacedObject using osgUtil::IntersectionVisitor --- apps/openmw/mwrender/objects.cpp | 11 +++ apps/openmw/mwrender/objects.hpp | 25 ++++++- apps/openmw/mwrender/renderingmanager.cpp | 82 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 7 ++ apps/openmw/mwrender/vismask.hpp | 11 +-- apps/openmw/mwworld/worldimp.cpp | 67 ++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 +- 7 files changed, 145 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d981a9c7b..cb53105a79 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -103,6 +104,8 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) osg::ref_ptr insert (new osg::PositionAttitudeTransform); cellnode->addChild(insert); + insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr)); + const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(osg::Vec3(f[0], f[1], f[2])); @@ -216,6 +219,14 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) osg::Node* objectNode = cur.getRefData().getBaseNode(); + osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); + if (userDataContainer) + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (dynamic_cast(userDataContainer->getUserObject(i))) + userDataContainer->setUserObject(i, new PtrHolder(cur)); + } + if (objectNode->getNumParents()) objectNode->getParent(0)->removeChild(objectNode); cellnode->addChild(objectNode); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 716192959d..b3799d0efb 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -6,6 +6,9 @@ #include #include +#include + +#include "../mwworld/ptr.hpp" namespace osg { @@ -24,7 +27,6 @@ namespace Resource namespace MWWorld { - class Ptr; class CellStore; } @@ -32,6 +34,27 @@ namespace MWRender{ class Animation; +class PtrHolder : public osg::Object +{ +public: + PtrHolder(MWWorld::Ptr ptr) + : mPtr(ptr) + { + } + + PtrHolder() + { + } + + PtrHolder(const PtrHolder& copy, const osg::CopyOp& copyop) + : mPtr(copy.mPtr) + { + } + + META_Object(MWRender, PtrHolder) + + MWWorld::Ptr mPtr; +}; class Objects{ typedef std::map PtrAnimationMap; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b8620d60b0..c49a444939 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -8,7 +8,10 @@ #include #include #include +#include +#include +#include #include #include @@ -292,6 +295,84 @@ namespace MWRender mObjects->removeObject(ptr); } + osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) + { + if (!ptr.getRefData().getBaseNode()) + return osg::Vec4f(); + + osg::ComputeBoundsVisitor computeBoundsVisitor; + ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); + + osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + for (int i=0; i<8; ++i) + { + osg::Vec3f corner = computeBoundsVisitor.getBoundingBox().corner(i); + corner = corner * viewProj; + + float x = (corner.x() + 1.f) * 0.5f; + float y = (corner.y() - 1.f) * (-0.5f); + + if (x < min_x) + min_x = x; + + if (x > max_x) + max_x = x; + + if (y < min_y) + min_y = y; + + if (y > max_y) + max_y = y; + } + + return osg::Vec4f(min_x, min_y, max_x, max_y); + } + + MWWorld::Ptr RenderingManager::getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, + nX * 2.f - 1.f, nY * (-2.f) + 1.f)); + + osg::Vec3d dist (0.f, 0.f, -maxDistance); + + dist = dist * mViewer->getCamera()->getProjectionMatrix(); + + osg::Vec3d end = intersector->getEnd(); + end.z() = dist.z(); + intersector->setEnd(end); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); + + osgUtil::IntersectionVisitor intersectionVisitor(intersector); + if (ignorePlayer) + intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + + mViewer->getCamera()->accept(intersectionVisitor); + + if (intersector->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + + PtrHolder* ptrHolder = NULL; + for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); + if (!userDataContainer) + continue; + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + ptrHolder = p; + } + } + + if (ptrHolder) + return ptrHolder->mPtr; + } + + return MWWorld::Ptr(); + } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { mObjects->updatePtr(old, updated); @@ -332,6 +413,7 @@ namespace MWRender if (!mPlayerNode) { mPlayerNode = new osg::PositionAttitudeTransform; + mPlayerNode->setNodeMask(Mask_Player); mLightRoot->addChild(mPlayerNode); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2978c99835..011ceee09d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -73,6 +73,13 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, + /// where (0,0) is the top left corner. + MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); + + /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. + osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 512f9f4ad6..7382438d17 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -10,13 +10,14 @@ namespace MWRender Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors // child of Scene - Mask_Effect = 0x2, - Mask_Debug = 0x4, - Mask_Actor = 0x8, + Mask_Effect = (1<<1), + Mask_Debug = (1<<2), + Mask_Actor = (1<<3), + Mask_Player = (1<<4), // top level masks - Mask_Scene = 0x10, - Mask_GUI = 0x20 + Mask_Scene = (1<<5), + Mask_GUI = (1<<6) }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 442f493c13..5689b12cc0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1031,11 +1031,11 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { - std::string facedHandle; + MWWorld::Ptr facedObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - getFacedHandle(facedHandle, getMaxActivationDistance() * 50, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, false); else { float telekinesisRangeBonus = @@ -1045,13 +1045,10 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - getFacedHandle(facedHandle, activationDistance); + facedObject = getFacedObject(activationDistance); } - //if (facedHandle.empty()) - return MWWorld::Ptr(); - - //return getPtrViaHandle(facedHandle); + return facedObject; } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -1593,11 +1590,8 @@ namespace MWWorld mWorldScene->update (duration, paused); - /* - performUpdateSceneQueries (); - updateWindowManager (); - */ + updateSoundListener(); /* if (!paused && mPlayer->getPlayer().getCell()->isExterior()) @@ -1648,57 +1642,27 @@ namespace MWWorld // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) { - Ogre::SceneNode* node = object.getRefData().getBaseNodeOld(); - Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); - if (bounds.isFinite()) - { - Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); - MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( - screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); - } + osg::Vec4f screenBounds = mRendering->getScreenBounds(object); + + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w()); } } - void World::performUpdateSceneQueries () + MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) { -#if 0 - if (!mRendering->occlusionQuerySupported()) - { - // cast a ray from player to sun to detect if the sun is visible - // this is temporary until we find a better place to put this code - // currently its here because we need to access the physics system - const float* p = mPlayer->getPlayer().getRefData().getPosition().pos; - Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); - } -#endif - } + maxDistance += mRendering->getCameraDistance(); - void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) - { - //maxDistance += mRendering->getCameraDistance(); - - std::vector < std::pair < float, std::string > > results; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - //results = mPhysics->getFacedHandles(x, y, maxDistance); + return mRendering->getFacedObject(x, y, maxDistance, ignorePlayer); } else { - //results = mPhysics->getFacedHandles(maxDistance); + return mRendering->getFacedObject(0.5f, 0.5f, maxDistance, ignorePlayer); } - - if (ignorePlayer && - !results.empty() && results.front().second == "player") - results.erase(results.begin()); - - if (results.empty() - || results.front().second.find("HeightField") != std::string::npos) // Blocked by terrain - facedHandle = ""; - else - facedHandle = results.front().second; } bool World::isCellExterior() const @@ -2744,10 +2708,7 @@ namespace MWWorld if (actor == getPlayerPtr()) { // For the player, use camera to aim - std::string facedHandle; - getFacedHandle(facedHandle, distance); - //if (!facedHandle.empty()) - // target = getPtrViaHandle(facedHandle); + target = getFacedObject(distance); } else { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index af1e68af1b..e217f4bc4e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,8 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); - void performUpdateSceneQueries (); - void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); + MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell); From d84990be85a0041c66effb8d622853adb408d286 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 03:59:22 +0200 Subject: [PATCH 0302/1812] Restore getCollisions --- apps/openmw/mwphysics/physicssystem.cpp | 32 +++++++++++++++++++++++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 14 +++++------ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b32ac2f52c..065be083df 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -758,9 +758,37 @@ namespace MWPhysics return std::make_pair(false, osg::Vec3f()); } - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { - return std::vector();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask); + public: + std::vector mResult; + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) + { + const PtrHolder* holder = static_cast(colObj0Wrap->m_collisionObject->getUserPointer()); + if (holder) + mResult.push_back(holder->getPtr()); + return 0.f; + } + }; + + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + { + btCollisionObject* me = NULL; + + ObjectMap::iterator found = mObjects.find(ptr); + if (found != mObjects.end()) + me = found->second->getCollisionObject(); + else + return std::vector(); + + ContactTestResultCallback resultCallback; + resultCallback.m_collisionFilterGroup = collisionGroup; + resultCallback.m_collisionFilterMask = collisionMask; + mDynamicsWorld->contactTest(me, resultCallback); + return resultCallback.mResult; } osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index aca24105ed..2ebe16e3bd 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -77,7 +77,7 @@ namespace MWPhysics void stepSimulation(float dt); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with + std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5689b12cc0..57b8b67a4d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -48,6 +48,7 @@ #include "../mwphysics/physicssystem.hpp" #include "../mwphysics/actor.hpp" +#include "../mwphysics/collisiontype.hpp" #include "player.hpp" #include "manualref.hpp" @@ -1420,7 +1421,6 @@ namespace MWWorld void World::processDoors(float duration) { -#if 0 std::map::iterator it = mDoorStates.begin(); while (it != mDoorStates.end()) { @@ -1433,19 +1433,18 @@ namespace MWWorld } else { - float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); - float diff = duration * 90; + float oldRot = osg::RadiansToDegrees(it->first.getRefData().getLocalRotation().rot[2]); + float diff = duration * 90.f; float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second == 1 ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); bool reached = (targetRot == 90.f && it->second) || targetRot == 0.f; /// \todo should use convexSweepTest here - std::vector collisions = mPhysics->getCollisions(it->first, OEngine::Physic::CollisionType_Actor - , OEngine::Physic::CollisionType_Actor); - for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); + for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { - MWWorld::Ptr ptr = getPtrViaHandle(*cit); + MWWorld::Ptr ptr = *cit; if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door @@ -1471,7 +1470,6 @@ namespace MWWorld ++it; } } -#endif } bool World::toggleCollisionMode() From 95465a1489e63bd7c25046f417c898dfdf848dc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:00:35 +0200 Subject: [PATCH 0303/1812] Player raycast fix --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c49a444939..e60b35524f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -27,8 +27,6 @@ #include -#include "../mwbase/world.hpp" - #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" @@ -417,9 +415,10 @@ namespace MWRender mLightRoot->addChild(mPlayerNode); } - player.getRefData().setBaseNode(mPlayerNode); + mPlayerNode->setUserDataContainer(new osg::DefaultUserDataContainer); + mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); - //attachCameraTo(player); + player.getRefData().setBaseNode(mPlayerNode); } void RenderingManager::renderPlayer(const MWWorld::Ptr &player) From 1fd9fba7a3b68df838436bd2e5703ce9686bfdc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:28:34 +0200 Subject: [PATCH 0304/1812] Fix debug drawer crash --- apps/openmw/mwrender/bulletdebugdraw.cpp | 50 ++++++++++++++++-------- apps/openmw/mwrender/bulletdebugdraw.hpp | 3 ++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 9e683232b1..36fc242266 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -28,21 +28,41 @@ DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *w mParentNode->addChild(mGeode); mGeode->setNodeMask(Mask_Debug); - mGeometry = new osg::Geometry; + createGeometry(); - mVertices = new osg::Vec3Array; - - mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); - - mGeometry->setUseDisplayList(false); - mGeometry->setVertexArray(mVertices); - mGeometry->setDataVariance(osg::Object::DYNAMIC); - mGeometry->addPrimitiveSet(mDrawArrays); - - mGeode->addDrawable(mGeometry); mParentNode->addChild(mGeode); } +void DebugDrawer::createGeometry() +{ + if (!mGeometry) + { + mGeometry = new osg::Geometry; + + mVertices = new osg::Vec3Array; + + mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + + mGeometry->setUseDisplayList(false); + mGeometry->setVertexArray(mVertices); + mGeometry->setDataVariance(osg::Object::DYNAMIC); + mGeometry->addPrimitiveSet(mDrawArrays); + + mGeode->addDrawable(mGeometry); + } +} + +void DebugDrawer::destroyGeometry() +{ + if (mGeometry) + { + mGeode->removeDrawable(mGeometry); + mGeometry = NULL; + mVertices = NULL; + mDrawArrays = NULL; + } +} + DebugDrawer::~DebugDrawer() { mParentNode->removeChild(mGeode); @@ -81,11 +101,9 @@ void DebugDrawer::setDebugMode(int isOn) mDebugOn = (isOn == 0) ? false : true; if (!mDebugOn) - { - mVertices->clear(); - mVertices->releaseGLObjects(0); - mGeometry->releaseGLObjects(0); - } + destroyGeometry(); + else + createGeometry(); } int DebugDrawer::getDebugMode() const diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index 288091e7ce..d2a4163cf8 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -29,6 +29,9 @@ protected: bool mDebugOn; + void createGeometry(); + void destroyGeometry(); + public: DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); From 76dd3e40345653aac40647783d45e98e0ce5fb07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 May 2015 04:40:09 +0200 Subject: [PATCH 0305/1812] Fix lip animation regression --- apps/openmw/mwsound/loudness.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 1e6872a766..12fe8ae4d0 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -31,8 +31,8 @@ namespace MWSound value = ((char)(data[sample*advance]^0x80))/128.f; else if (type == SampleType_Int16) { - value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); + value = *reinterpret_cast(&data[sample*advance]); + value /= float(std::numeric_limits::max()); } else if (type == SampleType_Float32) { From 3dcb167066831c47a6a5a1063faefe8ac3da473b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 16:40:44 +0200 Subject: [PATCH 0306/1812] Map rendering --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 9 +- apps/openmw/mwbase/world.hpp | 11 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 1 - apps/openmw/mwgui/loadingscreen.hpp | 2 - apps/openmw/mwgui/mapwindow.cpp | 61 ++- apps/openmw/mwgui/mapwindow.hpp | 19 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 68 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 13 +- apps/openmw/mwphysics/actor.cpp | 1 - apps/openmw/mwrender/animation.cpp | 1 - apps/openmw/mwrender/characterpreview.cpp | 3 + apps/openmw/mwrender/localmap.cpp | 534 +++++++++++----------- apps/openmw/mwrender/localmap.hpp | 119 ++--- apps/openmw/mwrender/objects.cpp | 7 +- apps/openmw/mwrender/renderingmanager.cpp | 17 +- apps/openmw/mwrender/sky.cpp | 9 +- apps/openmw/mwrender/vismask.hpp | 10 +- apps/openmw/mwworld/scene.cpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 58 ++- apps/openmw/mwworld/worldimp.hpp | 12 +- components/myguiplatform/myguitexture.cpp | 2 +- components/nifosg/controller.cpp | 1 - components/nifosg/nifloader.cpp | 2 - components/nifosg/particle.cpp | 2 - components/sceneutil/lightmanager.cpp | 7 + components/sceneutil/lightmanager.hpp | 3 + components/sceneutil/riggeometry.cpp | 1 - 31 files changed, 535 insertions(+), 458 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08dba334fa..9bfd867091 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -596,7 +596,7 @@ void OMW::Engine::go() { double dt = frameTimer.time_s(); frameTimer.setStartTick(); - //dt = std::min(dt, 0.2); + dt = std::min(dt, 0.2); double simulationTime = frame(dt); mViewer->frame(simulationTime); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d1f1ad3a33..37112477eb 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -178,12 +178,6 @@ namespace MWBase virtual void changeCell(MWWorld::CellStore* cell) = 0; ///< change the active cell - virtual void setPlayerPos(int cellX, int cellY, 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; @@ -358,6 +352,9 @@ namespace MWBase virtual std::string correctIconPath(const std::string& path) = 0; virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; + + virtual void requestMap(std::set cells) = 0; + virtual void removeCell(MWWorld::CellStore* cell) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6d1bc34bc4..c0e2ade0f5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -142,21 +142,12 @@ namespace MWBase virtual bool isCellQuasiExterior() const = 0; - virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; + virtual osg::Vec2f getNorthVector (MWWorld::CellStore* cell) = 0; ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) = 0; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y) = 0; - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0; - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value) = 0; ///< Set value independently from real type. diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a1e027f890..43df37b6de 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,9 +70,9 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop) + HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 9eed9811a4..72fc06f6a5 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,7 +19,7 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop); + HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index cdb2d6bdff..1f084402b0 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -35,7 +35,6 @@ namespace MWGui , mLastRenderTime(0.0) , mLoadingOnTime(0.0) , mProgress(0) - , mVSyncWasEnabled(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index a1e6e4d213..baacc7133d 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -67,8 +67,6 @@ namespace MWGui std::vector mSplashScreens; - bool mVSyncWasEnabled; - void changeWallpaper(); void draw(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 28fd13335e..95de175a3e 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -26,6 +26,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwrender/globalmap.hpp" +#include "../mwrender/localmap.hpp" #include "widgets.hpp" #include "confirmationdialog.hpp" @@ -142,8 +143,9 @@ namespace MWGui // ------------------------------------------------------ - LocalMapBase::LocalMapBase(CustomMarkerCollection &markers) - : mCurX(0) + LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender) + : mLocalMapRender(localMapRender) + , mCurX(0) , mCurY(0) , mInterior(false) , mLocalMap(NULL) @@ -260,8 +262,8 @@ namespace MWGui else { int cellX, cellY; - Ogre::Vector2 worldPos (worldX, worldY); - MWBase::Environment::get().getWorld ()->worldToInteriorMapPosition (worldPos, nX, nY, cellX, cellY); + osg::Vec2f worldPos (worldX, worldY); + mLocalMapRender->worldToInteriorMapPosition(worldPos, nX, nY, cellX, cellY); markerPos.cellX = cellX; markerPos.cellY = cellY; @@ -301,7 +303,7 @@ namespace MWGui continue; } - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 8, @@ -342,24 +344,30 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures -#if 0 + std::vector > textures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { - // map - std::string image = mPrefix+"_"+ MyGUI::utility::toString(x + (mx-1)) + "_" - + MyGUI::utility::toString(y + (-1*(my-1))); + int mapX = x + (mx-1); + int mapY = y + (-1*(my-1)); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); + osg::ref_ptr texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY); + if (texture) + { + boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); + textures.push_back(guiTex); + box->setRenderItemTexture(guiTex.get()); + box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + } else - box->setImageTexture("black"); + box->setRenderItemTexture(NULL); } } -#endif + mMapTextures.swap(textures); + MWBase::World* world = MWBase::Environment::get().getWorld(); // Retrieve the door markers we want to show @@ -394,7 +402,7 @@ namespace MWGui destNotes.push_back(it->mNote); } - MarkerUserData data; + MarkerUserData data (mLocalMapRender); data.notes = destNotes; data.caption = marker.name; MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data); @@ -490,7 +498,7 @@ namespace MWGui for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) { const ESM::Position& worldPos = it->getRefData().getPosition(); - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -535,7 +543,7 @@ namespace MWGui if (markedCell && markedCell->isExterior() == !mInterior && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) { - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -553,9 +561,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------ - MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, const std::string& cacheDir) + MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender) : WindowPinnableBase("openmw_map_window.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) , mGlobalMapTexture(NULL) @@ -662,19 +670,19 @@ namespace MWGui x += mCurX; y += mCurY; - Ogre::Vector2 worldPos; + osg::Vec2f worldPos; if (mInterior) { - worldPos = MWBase::Environment::get().getWorld()->interiorMapToWorldPosition(nX, nY, x, y); + worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y); } else { - worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0f-nY)) * cellSize; + worldPos.x() = (x + nX) * cellSize; + worldPos.y() = (y + (1.0f-nY)) * cellSize; } - mEditingMarker.mWorldX = worldPos.x; - mEditingMarker.mWorldY = worldPos.y; + mEditingMarker.mWorldX = worldPos.x(); + mEditingMarker.mWorldY = worldPos.y(); mEditingMarker.mCell.mPaged = !mInterior; if (mInterior) @@ -993,4 +1001,9 @@ namespace MWGui eventDeleteClicked(); } + bool LocalMapBase::MarkerUserData::isPositionExplored() const + { + return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); + } + } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 1e1e2c97e3..92cd880f4e 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -3,6 +3,8 @@ #include +#include + #include "windowpinnablebase.hpp" #include @@ -12,6 +14,7 @@ namespace MWRender { class GlobalMap; + class LocalMap; } namespace ESM @@ -52,7 +55,7 @@ namespace MWGui class LocalMapBase { public: - LocalMapBase(CustomMarkerCollection& markers); + LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); @@ -67,6 +70,14 @@ namespace MWGui struct MarkerUserData { + MarkerUserData(MWRender::LocalMap* map) + : mLocalMapRender(map) + { + } + + bool isPositionExplored() const; + + MWRender::LocalMap* mLocalMapRender; bool interior; int cellX; int cellY; @@ -77,6 +88,8 @@ namespace MWGui }; protected: + MWRender::LocalMap* mLocalMapRender; + int mCurX, mCurY; bool mInterior; MyGUI::ScrollView* mLocalMap; @@ -93,6 +106,8 @@ namespace MWGui std::vector mMapWidgets; std::vector mFogWidgets; + std::vector > mMapTextures; + // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; std::vector mMagicMarkerWidgets; @@ -153,7 +168,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop { public: - MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, const std::string& cacheDir); + MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 43acbeaab4..5dd201068b 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -169,7 +169,7 @@ namespace MWGui { LocalMapBase::MarkerUserData data = *focus->getUserData(); - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (data.nX, data.nY, data.cellX, data.cellY, data.interior)) + if (!data.isPositionExplored()) return; ToolTipInfo info; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5649908fcd..e4ecdad531 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,8 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwrender/localmap.hpp" + #include "../mwsound/soundmanagerimp.hpp" #include "console.hpp" @@ -115,6 +117,7 @@ namespace MWGui , mCurrentModals() , mHud(NULL) , mMap(NULL) + , mLocalMapRender(NULL) , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) @@ -266,7 +269,8 @@ namespace MWGui mRecharge = new Recharge(); mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); - mMap = new MapWindow(mCustomMarkers, mDragAndDrop, ""); + mLocalMapRender = new MWRender::LocalMap(mViewer); + mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); @@ -284,7 +288,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -383,6 +387,7 @@ namespace MWGui delete mMessageBoxManager; delete mHud; delete mMap; + delete mLocalMapRender; delete mMenu; delete mStatsWindow; delete mJournal; @@ -886,6 +891,31 @@ namespace MWGui return default_; } + void WindowManager::updateMap() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); + osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); + + osg::Vec3f playerdirection; + int x,y; + float u,v; + mLocalMapRender->updatePlayer(playerPosition, playerOrientation, u, v, x, y, playerdirection); + + if (!player.getCell()->isExterior()) + { + mMap->setActiveCell(x, y, true); + mHud->setActiveCell(x, y, true); + } + // else: need to know the current grid center, call setActiveCell from MWWorld::Scene + + mMap->setPlayerDir(playerdirection.x(), playerdirection.y()); + mMap->setPlayerPos(x, y, u, v); + mHud->setPlayerDir(playerdirection.x(), playerdirection.y()); + mHud->setPlayerPos(x, y, u, v); + } + void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); @@ -894,6 +924,9 @@ namespace MWGui mMenu->update(frameDuration); + if (mLocalMapRender) + mLocalMapRender->cleanupCameras(); + if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; @@ -908,6 +941,8 @@ namespace MWGui mInventoryWindow->onFrame(); + updateMap(); + mStatsWindow->onFrame(frameDuration); mMap->onFrame(frameDuration); mSpellWindow->onFrame(frameDuration); @@ -968,29 +1003,10 @@ namespace MWGui void WindowManager::setActiveMap(int x, int y, bool interior) { - if (!interior) - { - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - } - mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); } - void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) - { - mMap->setPlayerPos(cellX, cellY, x, y); - mHud->setPlayerPos(cellX, cellY, x, y); - } - - void WindowManager::setPlayerDir(const float x, const float y) - { - mMap->setPlayerDir(x,y); - mMap->setGlobalMapPlayerDir(x, y); - mHud->setPlayerDir(x,y); - } - void WindowManager::setDrowningBarVisibility(bool visible) { mHud->setDrowningBarVisible(visible); @@ -1990,4 +2006,14 @@ namespace MWGui tex->unlock(); } + void WindowManager::requestMap(std::set cells) + { + mLocalMapRender->requestMap(cells); + } + + void WindowManager::removeCell(MWWorld::CellStore *cell) + { + mLocalMapRender->removeCell(cell); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d07f2fb98d..c0184d4b6d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -67,6 +67,11 @@ namespace Gui class FontLoader; } +namespace MWRender +{ + class LocalMap; +} + namespace MWGui { class WindowBase; @@ -191,8 +196,6 @@ namespace MWGui 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(int cellX, int cellY, 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); @@ -363,6 +366,9 @@ namespace MWGui virtual std::string correctBookartPath(const std::string& path, int width, int height); virtual std::string correctTexturePath(const std::string& path); + void requestMap(std::set cells); + void removeCell(MWWorld::CellStore* cell); + private: Resource::ResourceSystem* mResourceSystem; @@ -386,6 +392,7 @@ namespace MWGui HUD *mHud; MapWindow *mMap; + MWRender::LocalMap* mLocalMapRender; MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; @@ -473,6 +480,8 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings + void updateMap(); + float mFPS; std::map mFallbackMap; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 1a712461ef..7084af8624 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -1,5 +1,4 @@ #include "actor.hpp" -#include #include diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1c436d4403..1f78f0dd8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cc6b4a9bbc..62c732051e 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "npcanimation.hpp" +#include "vismask.hpp" namespace MWRender { @@ -81,6 +82,8 @@ namespace MWRender mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + mCamera->setNodeMask(Mask_RenderToTexture); + osg::ref_ptr lightManager = new SceneUtil::LightManager; lightManager->setStartLight(1); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index f675fe1d8e..8ab16283e5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,74 +1,82 @@ #include "localmap.hpp" -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include + +#include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "vismask.hpp" -using namespace MWRender; -using namespace Ogre; +namespace +{ -LocalMap::LocalMap() - : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) + class CameraUpdateCallback : public osg::NodeCallback + { + public: + CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + : mCamera(cam), mParent(parent) + { + } + + virtual void operator()(osg::Node*, osg::NodeVisitor*) + { + mParent->markForRemoval(mCamera); + + // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, + // so it has been updated already. + //traverse(node, nv); + } + + private: + osg::ref_ptr mCamera; + MWRender::LocalMap* mParent; + }; + +} + +namespace MWRender +{ + +LocalMap::LocalMap(osgViewer::Viewer* viewer) + : mViewer(viewer) + , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) + , mMapWorldSize(8192.f) , mAngle(0.f) , mInterior(false) { - // mCellCamera = mRendering->getScene()->createCamera("CellCamera"); - mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); + mRoot = mViewer->getSceneData()->asGroup(); - mCameraNode->attachObject(mCellCamera); - - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); - mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); - - mRenderTexture = TextureManager::getSingleton().createManual( - "localmap/rtt", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8, - TU_RENDERTARGET); - - mRenderTarget = mRenderTexture->getBuffer()->getRenderTarget(); - mRenderTarget->setAutoUpdated(false); - Viewport* vp = mRenderTarget->addViewport(mCellCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setMaterialScheme("local_map"); + SceneUtil::FindByNameVisitor find("Scene Root"); + mRoot->accept(find); + mSceneRoot = find.mFoundNode; + if (!mSceneRoot) + throw std::runtime_error("no scene root found"); } LocalMap::~LocalMap() { + for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) + mRoot->removeChild(*it); + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + mRoot->removeChild(*it); } -const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) { - return Vector2( Math::Cos(angle) * (p.x - c.x) - Math::Sin(angle) * (p.y - c.y) + c.x, - Math::Sin(angle) * (p.x - c.x) + Math::Cos(angle) * (p.y - c.y) + c.y); -} - -std::string LocalMap::coordStr(const int x, const int y) -{ - return StringConverter::toString(x) + "_" + StringConverter::toString(y); + return osg::Vec2f( std::cos(angle) * (p.x() - c.x()) - std::sin(angle) * (p.y() - c.y()) + c.x(), + std::sin(angle) * (p.x() - c.x()) + std::cos(angle) * (p.y() - c.y()) + c.y()); } void LocalMap::clear() @@ -103,8 +111,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); + const int segsX = static_cast(std::ceil(length.x / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y / mMapWorldSize)); mInteriorName = cell->getCell()->mName; @@ -148,24 +156,145 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) +osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax) +{ + osg::ref_ptr camera (new osg::Camera); + + camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10); + camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f)); + camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + camera->setRenderOrder(osg::Camera::PRE_RENDER); + + camera->setCullMask(MWRender::Mask_Scene); + camera->setNodeMask(Mask_RenderToTexture); + + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + stateset->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.3f, 0.3f, 0.3f, 1.f)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3f, -0.3f, 0.7f, 0.f)); + light->setDiffuse(osg::Vec4(0.7f, 0.7f, 0.7f, 1.f)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + camera->addChild(lightSource); + camera->setStateSet(stateset); + camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + camera->setViewport(0, 0, mMapResolution, mMapResolution); + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + + return camera; +} + +void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int y) +{ + osg::ref_ptr texture (new osg::Texture2D); + texture->setTextureSize(mMapResolution, mMapResolution); + texture->setInternalFormat(GL_RGB); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + camera->attach(osg::Camera::COLOR_BUFFER, texture); + + camera->addChild(mSceneRoot); + mRoot->addChild(camera); + mActiveCameras.push_back(camera); + mTextures[std::make_pair(x, y)] = texture; +} + +void LocalMap::requestMap(std::set cells) +{ + for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + { + MWWorld::CellStore* cell = *it; + if (cell->isExterior()) + requestExteriorMap(cell); + else + requestInteriorMap(cell); + } +} + +void LocalMap::removeCell(MWWorld::CellStore *cell) +{ + if (cell->isExterior()) + mTextures.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + else + mTextures.clear(); +} + +osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +{ + TextureMap::iterator found = mTextures.find(std::make_pair(x, y)); + if (found == mTextures.end()) + return osg::ref_ptr(); + else + return found->second; +} + +void LocalMap::markForRemoval(osg::Camera *cam) +{ + CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), cam); + if (found == mActiveCameras.end()) + { + std::cerr << "trying to remove an inactive camera" << std::endl; + return; + } + mActiveCameras.erase(found); + mCamerasPendingRemoval.push_back(cam); +} + +void LocalMap::cleanupCameras() +{ + if (mCamerasPendingRemoval.empty()) + return; + + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + { + (*it)->removeChildren(0, (*it)->getNumChildren()); + (*it)->setGraphicsContext(NULL); + mRoot->removeChild(*it); + } + + + mCamerasPendingRemoval.clear(); +} + +void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) { mInterior = false; - mCameraRotNode->setOrientation(Quaternion::IDENTITY); - mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); - int x = cell->getCell()->getGridX(); int y = cell->getCell()->getGridY(); - std::string name = "Cell_"+coordStr(x, y); + osg::BoundingSphere bound = mViewer->getSceneData()->getBound(); + float zmin = bound.center().z() - bound.radius(); + float zmax = bound.center().z() + bound.radius(); - mCameraPosNode->setPosition(Vector3(0,0,0)); - - // Note: using force=true for exterior cell maps. - // They must be updated even if they were visited before, because the set of surrounding active cells might be different - // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); + osg::ref_ptr camera = createOrthographicCamera(x*mMapWorldSize + mMapWorldSize/2.f, y*mMapWorldSize + mMapWorldSize/2.f, mMapWorldSize, mMapWorldSize, + osg::Vec3d(0,1,0), zmin, zmax); + setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); /* if (mBuffers.find(name) == mBuffers.end()) @@ -178,12 +307,17 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, - AxisAlignedBox bounds) +void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) { + osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(Mask_Scene); + mSceneRoot->accept(computeBoundsVisitor); + + osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); + // If we're in an empty cell, bail out // The operations in this function are only valid for finite bounds - if (bounds.isNull ()) + if (!bounds.valid() || bounds.radius2() == 0.0) return; mInterior = true; @@ -191,41 +325,31 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mBounds = bounds; // Get the cell's NorthMarker rotation. This is used to rotate the entire map. - const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle = Ogre::Math::ATan2 (north.x, north.y); - mAngle = angle.valueRadians(); + osg::Vec2f north = MWBase::Environment::get().getWorld()->getNorthVector(cell); + + mAngle = std::atan2(north.x(), north.y()); // Rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); - - Vector2 c1(_c1.x, _c1.y); - Vector2 c2(_c2.x, _c2.y); - Vector2 c3(_c3.x, _c3.y); - Vector2 c4(_c4.x, _c4.y); - c1 = rotatePoint(c1, _center, mAngle); - c2 = rotatePoint(c2, _center, mAngle); - c3 = rotatePoint(c3, _center, mAngle); - c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, c1.y, 0)); - mBounds.merge(Vector3(c2.x, c2.y, 0)); - mBounds.merge(Vector3(c3.x, c3.y, 0)); - mBounds.merge(Vector3(c4.x, c4.y, 0)); + osg::Vec2f _center(bounds.center().x(), bounds.center().y()); + for (int i=0; i<8; ++i) + { + osg::Vec3f corner = mBounds.corner(i); + osg::Vec2f corner2d (corner.x(), corner.y()); + corner2d = rotatePoint(corner2d, _center, mAngle); + mBounds.expandBy(osg::Vec3f(corner2d.x(), corner2d.y(), 0)); + } // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const Ogre::Real padding = 500.0f; + const float padding = 500.0f; // Apply a little padding - mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); - mBounds.setMaximum (mBounds.getMaximum() + Vector3(padding,padding,0)); + mBounds.set(mBounds._min - osg::Vec3f(padding,padding,0.f), + mBounds._max + osg::Vec3f(padding,padding,0.f)); - float zMin = mBounds.getMinimum().z; - float zMax = mBounds.getMaximum().z; + float zMin = mBounds.zMin(); + float zMax = mBounds.zMax(); // If there is fog state in the CellStore (e.g. when it came from a savegame) we need to do some checks // to see if this state is still valid. @@ -244,8 +368,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, Ogre::Vector3 minDiff = newMin - mBounds.getMinimum(); Ogre::Vector3 maxDiff = newMax - mBounds.getMaximum(); - if (std::abs(minDiff.x) > 500 || std::abs(minDiff.y) > 500 - || std::abs(maxDiff.x) > 500 || std::abs(maxDiff.y) > 500 + if (std::abs(minDiff.x) > padding || std::abs(minDiff.y) > padding + || std::abs(maxDiff.x) > padding || std::abs(maxDiff.y) > padding || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) { // Nuke it @@ -260,35 +384,35 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, } */ - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); + osg::Vec2f length = max-min; - Vector2 length = max-min; - - mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); - - mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); + osg::Vec2f center(bounds.center().x(), bounds.center().y()); // divide into segments - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); + const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); - mInteriorName = cell->getCell()->mName; - - int i=0; for (int x=0; x(sSize*x), static_cast(sSize*y)); - Vector2 newcenter = start + sSize/2; + osg::Vec2f start = min + osg::Vec2f(mMapWorldSize*x, mMapWorldSize*y); + osg::Vec2f newcenter = start + osg::Vec2f(mMapWorldSize/2.f, mMapWorldSize/2.f); - std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); + osg::Quat cameraOrient (mAngle, osg::Vec3d(0,0,-1)); + osg::Vec2f a = newcenter - center; + osg::Vec3f rotatedCenter = cameraOrient * (osg::Vec3f(a.x(), a.y(), 0)); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + center; + + osg::ref_ptr camera = createOrthographicCamera(pos.x(), pos.y(), + mMapWorldSize, mMapWorldSize, + osg::Vec3f(north.x(), north.y(), 0.f), zMin, zMax); + + setupRenderToTexture(camera, x, y); /* if (!cell->getFog()) @@ -305,14 +429,13 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, loadFogOfWar(texturePrefix, esm); } */ - ++i; } } } +/* void LocalMap::createFogOfWar(const std::string& texturePrefix) { - /* const std::string texName = texturePrefix + "_fog"; TexturePtr tex = createFogOfWarTexture(texName); @@ -328,34 +451,12 @@ void LocalMap::createFogOfWar(const std::string& texturePrefix) tex->getBuffer()->unlock(); mBuffers[texturePrefix] = buffer; - */ -} - -Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) -{ - TexturePtr tex;// = TextureManager::getSingleton().getByName(texName); - /* - * if (tex.isNull()) - { - tex = TextureManager::getSingleton().createManual( - texName, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - sFogOfWarResolution, sFogOfWarResolution, - 0, - PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY, - this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D) - ); - } - */ - - return tex; } +*/ +/* void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) { - /* std::vector& data = esm.mImageData; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; @@ -377,89 +478,35 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& memcpy(&buffer[0], image.getData(), image.getSize()); mBuffers[texturePrefix] = buffer; - */ +} +*/ + +void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) +{ + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); + + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + + x = static_cast(std::ceil((pos.x() - min.x()) / mMapWorldSize) - 1); + y = static_cast(std::ceil((pos.y() - min.y()) / mMapWorldSize) - 1); + + nX = (pos.x() - min.x() - mMapWorldSize*x)/mMapWorldSize; + nY = 1.0f-(pos.y() - min.y() - mMapWorldSize*y)/mMapWorldSize; } -void LocalMap::render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, const std::string& texture, bool force) +osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) { - mCellCamera->setFarClipDistance( (zhigh-zlow) + 2000 ); - mCellCamera->setNearClipDistance(50); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f pos (mMapWorldSize * (nX + x) + min.x(), + mMapWorldSize * (1.0f-nY + y) + min.y()); - mCellCamera->setOrthoWindow(xw, yw); - mCameraNode->setPosition(Vector3(x, y, zhigh+1000)); - - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - //mRendering->getScene()->setFog(FOG_NONE); - - // set up lighting - //Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - //mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); - //mRenderingManager->disableLights(true); - mLight->setVisible(true); - - TexturePtr tex; - // try loading from memory - tex = TextureManager::getSingleton().getByName(texture); - if (tex.isNull()) - { - // render - mRenderTarget->update(); - - // create a new texture and blit to it - Ogre::TexturePtr tex = TextureManager::getSingleton().createManual( - texture, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - else if (force) - { - mRenderTarget->update(); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - - //mRenderingManager->enableLights(true); - mLight->setVisible(false); - - // re-enable fog - //mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); - //mRendering->getScene()->setAmbientLight(oldAmbient); -} - -void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) -{ - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); - - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - - x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); - y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); - - nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; -} - -Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) -{ - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Ogre::Vector2 pos; - - pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0f-nY + y) + min.y; - - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), -mAngle); return pos; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return false; + return true; /* std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); @@ -478,33 +525,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi */ } -void LocalMap::loadResource(Ogre::Resource* resource) -{ - /* - std::string resourceName = resource->getName(); - size_t pos = resourceName.find("_fog"); - if (pos != std::string::npos) - resourceName = resourceName.substr(0, pos); - if (mBuffers.find(resourceName) == mBuffers.end()) - { - // create a buffer to use for dynamic operations - std::vector buffer; - - // initialize to (0, 0, 0, 1) - buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000); - mBuffers[resourceName] = buffer; - } - - std::vector& buffer = mBuffers[resourceName]; - - Ogre::Texture* tex = static_cast(resource); - tex->createInternalResources(); - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); - */ -} - -void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) +void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction) { /* if (sFogOfWarSkip != 0) @@ -513,42 +535,32 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (++count % sFogOfWarSkip != 0) return; } + */ // retrieve the x,y grid coordinates the player is in - int x,y; - float u,v; - - Vector2 pos(position.x, position.y); + osg::Vec2f pos(position.x(), position.y()); if (mInterior) + { worldToInteriorMapPosition(pos, u,v, x,y); - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - - if (!mInterior) - { - x = static_cast(std::ceil(pos.x / sSize) - 1); - y = static_cast(std::ceil(pos.y / sSize) - 1); - } - else - MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); - - // convert from world coordinates to texture UV coordinates - std::string texBaseName; - if (!mInterior) - { - u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); - texBaseName = "Cell_"; + osg::Quat cameraOrient (mAngle, osg::Vec3(0,0,-1)); + direction = orientation * cameraOrient.inverse() * osg::Vec3f(0,1,0); } else { - texBaseName = mInteriorName + "_"; + direction = orientation * osg::Vec3f(0,1,0); + + x = static_cast(std::ceil(pos.x() / mMapWorldSize) - 1); + y = static_cast(std::ceil(pos.y() / mMapWorldSize) - 1); + + // convert from world coordinates to texture UV coordinates + u = std::abs((pos.x() - (mMapWorldSize*x))/mMapWorldSize); + v = 1.0f-std::abs((pos.y() - (mMapWorldSize*y))/mMapWorldSize); } - MWBase::Environment::get().getWindowManager()->setPlayerPos(x, y, u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); + /* // explore radius (squared) const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = Math::Sqr(exploreRadius); @@ -614,3 +626,5 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } */ } + +} diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index d0d7d73d25..8160c325c0 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,9 +1,13 @@ #ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H -#include -#include -#include +#include +#include +#include + +#include +#include +#include namespace MWWorld { @@ -15,52 +19,57 @@ namespace ESM struct FogTexture; } +namespace osgViewer +{ + class Viewer; +} + +namespace osg +{ + class Texture2D; + class Camera; + class Group; + class Node; +} + namespace MWRender { - class RenderingManager; - /// /// \brief Local map rendering /// class LocalMap { public: - LocalMap(); + LocalMap(osgViewer::Viewer* viewer); ~LocalMap(); - virtual void loadResource(Ogre::Resource* resource); - /** * Clear all savegame-specific data (i.e. fog of war textures) */ void clear(); - /** - * Request the local map for an exterior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell exterior cell - * @param zMin min height of objects or terrain in cell - * @param zMax max height of objects or terrain in cell - */ - void requestMap (MWWorld::CellStore* cell, float zMin, float zMax); + void requestMap (std::set cells); + + void removeCell (MWWorld::CellStore* cell); + + osg::ref_ptr getMapTexture (bool interior, int x, int y); + + void markForRemoval(osg::Camera* cam); /** - * Request the local map for an interior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell interior cell - * @param bounds bounding box of the cell + * Removes cameras that have already been rendered. Should be called every frame to ensure that + * we do not render the same map more than once. Note, this cleanup is difficult to implement in an + * automated fashion, since we can't alter the scene graph structure from within an update callback. */ - void requestMap (MWWorld::CellStore* cell, - Ogre::AxisAlignedBox bounds); + void cleanupCameras(); /** - * Set the position & direction of the player. + * Set the position & direction of the player, and returns the position in map space through the reference parameters. * @remarks This is used to draw a "fog of war" effect * to hide areas on the map the player has not discovered yet. */ - void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation); + void updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction); /** * Save the fog of war for this cell to its CellStore. @@ -72,9 +81,9 @@ namespace MWRender * Get the interior map texture index and normalized position * on this texture, given a world position */ - void worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y); + void worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y); - Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); + osg::Vec2f interiorMapToWorldPosition (float nX, float nY, int x, int y); /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) @@ -82,6 +91,20 @@ namespace MWRender bool isPositionExplored (float nX, float nY, int x, int y, bool interior); private: + osg::ref_ptr mViewer; + + osg::ref_ptr mRoot; + osg::ref_ptr mSceneRoot; + + typedef std::vector< osg::ref_ptr > CameraVector; + + CameraVector mActiveCameras; + + CameraVector mCamerasPendingRemoval; + + typedef std::map, osg::ref_ptr > TextureMap; + TextureMap mTextures; + int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high @@ -91,46 +114,34 @@ namespace MWRender static const int sFogOfWarSkip = 2; // size of a map segment (for exteriors, 1 cell) - static const int sSize = 8192; - - Ogre::Camera* mCellCamera; - Ogre::SceneNode* mCameraNode; - Ogre::SceneNode* mCameraPosNode; - Ogre::SceneNode* mCameraRotNode; - - // directional light from a fixed angle - Ogre::Light* mLight; + float mMapWorldSize; float mAngle; - const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle); - /// @param force Always render, even if we already have a cached map - void render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, - const std::string& texture, bool force=false); + void requestExteriorMap(MWWorld::CellStore* cell); + void requestInteriorMap(MWWorld::CellStore* cell); + + osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); + void setupRenderToTexture(osg::ref_ptr camera, int x, int y); // Creates a fog of war texture and initializes it to full black - void createFogOfWar(const std::string& texturePrefix); + //void createFogOfWar(const std::string& texturePrefix); // Loads a fog of war texture from its ESM struct - void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it - - Ogre::TexturePtr createFogOfWarTexture(const std::string& name); - - std::string coordStr(const int x, const int y); + //void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it // A buffer for the "fog of war" textures of the current cell. // Both interior and exterior maps are possibly divided into multiple textures. - std::map > mBuffers; + //std::map > mBuffers; // The render texture we will use to create the map images - Ogre::TexturePtr mRenderTexture; - Ogre::RenderTarget* mRenderTarget; + //Ogre::TexturePtr mRenderTexture; + //Ogre::RenderTarget* mRenderTarget; bool mInterior; - Ogre::AxisAlignedBox mBounds; - std::string mInteriorName; + osg::BoundingBox mBounds; + //std::string mInteriorName; }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb53105a79..8160027538 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -206,6 +205,10 @@ void Objects::removeCell(const MWWorld::CellStore* store) void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + osg::Node* objectNode = cur.getRefData().getBaseNode(); + if (!objectNode) + return; + MWWorld::CellStore *newCell = cur.getCell(); osg::Group* cellnode; @@ -217,8 +220,6 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) cellnode = mCellSceneNodes[newCell]; } - osg::Node* objectNode = cur.getRefData().getBaseNode(); - osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); if (userDataContainer) for (unsigned int i=0; igetNumUserObjects(); ++i) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e60b35524f..b1c26812c7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -111,6 +110,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; + source->setNodeMask(SceneUtil::Mask_Lit); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -123,6 +123,7 @@ namespace MWRender lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); lightRoot->setNodeMask(Mask_Scene); + lightRoot->setName("Scene Root"); mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); @@ -342,8 +343,12 @@ namespace MWRender intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor intersectionVisitor(intersector); + int mask = intersectionVisitor.getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); if (ignorePlayer) - intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + mask &= ~(Mask_Player); + + intersectionVisitor.setTraversalMask(mask); mViewer->getCamera()->accept(intersectionVisitor); @@ -451,12 +456,8 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { - double fovy, aspect, zNear, zFar; - mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - fovy = mFieldOfView; - zNear = mNearClip; - zFar = mViewDistance; - mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); + mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43c88427ec..990f3a5d96 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,10 +8,6 @@ #include #include -#include - -#include - #include #include @@ -34,7 +30,7 @@ #include "../mwworld/fallback.hpp" -#include "renderingmanager.hpp" +#include "vismask.hpp" namespace { @@ -506,6 +502,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSecundaEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -652,7 +649,7 @@ void SkyManager::setEnabled(bool enabled) if (!enabled) clearRain(); - mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); + mRootNode->setNodeMask(enabled ? Mask_Sky : 0); mEnabled = enabled; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 7382438d17..c9ac35c67c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -14,10 +14,16 @@ namespace MWRender Mask_Debug = (1<<2), Mask_Actor = (1<<3), Mask_Player = (1<<4), + Mask_Sky = (1<<5), // top level masks - Mask_Scene = (1<<5), - Mask_GUI = (1<<6) + Mask_Scene = (1<<6), + Mask_GUI = (1<<7), + + // Set on cameras within the main scene graph + Mask_RenderToTexture = (1<<8) + + // reserved: (1<<16) for SceneUtil::Mask_Lit }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 397ebbe75e..939fbe873b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,8 +172,13 @@ namespace MWWorld { // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different // (and objects in a different cell can "bleed" into another cells map if they cross the border) - //for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - //mRendering.requestMap(*active); + std::set cellsToUpdate; + for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) + { + cellsToUpdate.insert(*active); + } + MWBase::Environment::get().getWindowManager()->requestMap(cellsToUpdate); + mNeedMapUpdate = false; if (mCurrentCell->isExterior()) @@ -213,6 +218,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->drop (*iter); mRendering.removeCell(*iter); + MWBase::Environment::get().getWindowManager()->removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57b8b67a4d..e20904d717 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -162,14 +162,11 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); #endif mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); - //mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); @@ -1591,24 +1588,38 @@ namespace MWWorld updateWindowManager (); updateSoundListener(); - /* - if (!paused && mPlayer->getPlayer().getCell()->isExterior()) + + updatePlayer(paused); + } + + void World::updatePlayer(bool paused) + { + MWWorld::Ptr player = getPlayerPtr(); + + // TODO: move to MWWorld::Player + + if (player.getCell()->isExterior()) { - ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); + ESM::Position pos = player.getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); } - */ + + if (player.getClass().getNpcStats(player).isWerewolf()) + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); // Sink the camera while sneaking - bool sneaking = getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool inair = !isOnGround(getPlayerPtr()); - bool swimming = isSwimming(getPlayerPtr()); + bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !isOnGround(player); + bool swimming = isSwimming(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); if(!paused && sneaking && !(swimming || inair)) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); + + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); + MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); } void World::updateSoundListener() @@ -1701,16 +1712,16 @@ namespace MWWorld mWeatherManager->modRegion(regionid, chances); } - Ogre::Vector2 World::getNorthVector (CellStore* cell) + osg::Vec2f World::getNorthVector (CellStore* cell) { MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) - return Ogre::Vector2(0, 1); + return osg::Vec2f(0, 1); - Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0); - Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y); + osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); + osg::Vec3f dir = orient * osg::Vec3f(0,1,0); + osg::Vec2f d (dir.x(), dir.y()); return d; } @@ -1756,24 +1767,9 @@ namespace MWWorld } } - void World::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) - { - //mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); - } - - Ogre::Vector2 World::interiorMapToWorldPosition(float nX, float nY, int x, int y) - { - return Ogre::Vector2();//mRendering->interiorMapToWorldPosition(nX, nY, x, y); - } - - bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) - { - return 0;//mRendering->isPositionExplored(nX, nY, x, y, interior); - } - void World::setWaterHeight(const float height) { - //mPhysics->setWaterHeight(height); + mPhysics->setWaterHeight(height); //mRendering->setWaterHeight(height); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e217f4bc4e..dedfebdf22 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,6 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); + void updatePlayer(bool paused); MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); @@ -218,21 +219,12 @@ namespace MWWorld virtual bool isCellQuasiExterior() const; - virtual Ogre::Vector2 getNorthVector (CellStore* cell); + virtual osg::Vec2f getNorthVector (CellStore* cell); ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value); ///< Set value independently from real type. diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 2a32dd9f31..0a846b227d 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,7 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d676bc3f8d..06d5d8792d 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index adf7e94b4c..5fdf964c4a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -9,8 +9,6 @@ #include #include -#include - // resource #include #include diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index b733987d03..ac304bdf31 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -6,8 +6,6 @@ #include -#include - #include "userdata.hpp" namespace NifOsg diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ce7a343da5..e53a55bf37 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -226,6 +226,7 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { + setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); } @@ -233,6 +234,12 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); + if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) + { + traverse(node, nv); + return; + } + if (!mLightManager) { for (unsigned int i=0;igetNodePath().size(); ++i) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 1cd73589a4..dd0c2d3e6c 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,6 +9,9 @@ namespace SceneUtil { + // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. + const int Mask_Lit = (1<<16); + /// LightSource managed by a LightManager. class LightSource : public osg::Node { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 065ee60d99..dd6b9a4999 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "skeleton.hpp" #include "util.hpp" From c4951d1e73fface33580f70474dd315404c8a404 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 18:10:31 +0200 Subject: [PATCH 0307/1812] Map rotation fix --- apps/openmw/mwrender/localmap.cpp | 16 ++++++++++------ apps/openmw/mwrender/localmap.hpp | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8ab16283e5..0da14f7024 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -73,10 +73,10 @@ LocalMap::~LocalMap() mRoot->removeChild(*it); } -const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) { - return osg::Vec2f( std::cos(angle) * (p.x() - c.x()) - std::sin(angle) * (p.y() - c.y()) + c.x(), - std::sin(angle) * (p.x() - c.x()) + std::cos(angle) * (p.y() - c.y()) + c.y()); + return osg::Vec2f( std::cos(angle) * (point.x() - center.x()) - std::sin(angle) * (point.y() - center.y()) + center.x(), + std::sin(angle) * (point.x() - center.x()) + std::cos(angle) * (point.y() - center.y()) + center.y()); } void LocalMap::clear() @@ -330,12 +330,16 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) mAngle = std::atan2(north.x(), north.y()); // Rotate the cell and merge the rotated corners to the bounding box - osg::Vec2f _center(bounds.center().x(), bounds.center().y()); + osg::Vec2f origCenter(bounds.center().x(), bounds.center().y()); + osg::Vec3f origCorners[8]; + for (int i=0; i<8; ++i) + origCorners[i] = mBounds.corner(i); + for (int i=0; i<8; ++i) { - osg::Vec3f corner = mBounds.corner(i); + osg::Vec3f corner = origCorners[i]; osg::Vec2f corner2d (corner.x(), corner.y()); - corner2d = rotatePoint(corner2d, _center, mAngle); + corner2d = rotatePoint(corner2d, origCenter, mAngle); mBounds.expandBy(osg::Vec3f(corner2d.x(), corner2d.y(), 0)); } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 8160c325c0..ba92cde246 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -117,7 +117,7 @@ namespace MWRender float mMapWorldSize; float mAngle; - const osg::Vec2f rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); void requestExteriorMap(MWWorld::CellStore* cell); void requestInteriorMap(MWWorld::CellStore* cell); From 099f93f00df5d3fd76ff707da5993e7154a881f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 18:22:21 +0200 Subject: [PATCH 0308/1812] Sky fixes --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- apps/openmw/mwrender/sky.cpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b1c26812c7..6a1ed89a26 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -50,6 +50,7 @@ namespace MWRender stateset->setAttribute(lightModel, osg::StateAttribute::ON); osg::Fog* fog = new osg::Fog; fog->setStart(1); + fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); } @@ -60,7 +61,6 @@ namespace MWRender osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); fog->setColor(mFogColor); fog->setEnd(mFogEnd); - fog->setMode(osg::Fog::LINEAR); } void setAmbientColor(const osg::Vec4f& col) @@ -115,6 +115,7 @@ namespace MWRender source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); + mSunLight->setSpecular(osg::Vec4f(0,0,0,0)); mSunLight->setConstantAttenuation(1.f); lightRoot->addChild(source); @@ -181,12 +182,14 @@ namespace MWRender void RenderingManager::setSunColour(const osg::Vec4f &colour) { + // need to wrap this in a StateUpdater? mSunLight->setDiffuse(colour); } void RenderingManager::setSunDirection(const osg::Vec3f &direction) { osg::Vec3 position = direction * -1; + // need to wrap this in a StateUpdater? mSunLight->setPosition(osg::Vec4(position.x(), position.y(), position.z(), 0)); mSky->setSunDirection(position); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 990f3a5d96..d667611954 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -41,6 +41,7 @@ namespace mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); mat->setColorMode(osg::Material::DIFFUSE); return mat; } @@ -51,6 +52,7 @@ namespace mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); mat->setColorMode(osg::Material::OFF); return mat; } @@ -550,6 +552,7 @@ void SkyManager::create() depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); mCreated = true; } From 5de24552a8aa275931e8bca71d78bc5bcf2f3a77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 19:12:29 +0200 Subject: [PATCH 0309/1812] Leak fix --- components/sceneutil/riggeometry.cpp | 4 +++- components/sceneutil/riggeometry.hpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index dd6b9a4999..2a67c6ce60 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -59,7 +59,8 @@ public: }; RigGeometry::RigGeometry() - : mFirstFrame(true) + : mSkeleton(NULL) + , mFirstFrame(true) , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); @@ -69,6 +70,7 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) + , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index ea4245aa8b..bd7c586c47 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -46,7 +46,7 @@ namespace SceneUtil private: osg::ref_ptr mSourceGeometry; - osg::ref_ptr mSkeleton; + Skeleton* mSkeleton; osg::ref_ptr mInfluenceMap; From 723beb1cac998a92320b83f9ff14aa0d80d86ff4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 May 2015 20:20:18 +0200 Subject: [PATCH 0310/1812] Move IncrementalCompileOperation to SceneManager --- apps/openmw/mwgui/loadingscreen.cpp | 3 ++- apps/openmw/mwrender/objects.cpp | 16 ---------------- apps/openmw/mwrender/objects.hpp | 4 ---- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/resource/scenemanager.cpp | 12 +++++++++++- components/resource/scenemanager.hpp | 10 ++++++++++ 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 1f084402b0..f6a9f5ccdd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -181,7 +181,8 @@ namespace MWGui void LoadingScreen::setProgress (size_t value) { - if (value - mProgress < mProgressBar->getScrollRange()/100.f) + // skip expensive update if there isn't enough visible progress + if (value - mProgress < mProgressBar->getScrollRange()/200.f) return; mProgress = value; mProgressBar->setScrollPosition(0); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 8160027538..47a54fdbfb 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include #include @@ -81,11 +79,6 @@ Objects::~Objects() mCellSceneNodes.clear(); } -void Objects::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) -{ - mIncrementalCompileOperation = ico; -} - void Objects::insertBegin(const MWWorld::Ptr& ptr) { osg::ref_ptr cellnode; @@ -118,9 +111,6 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - if (!allowLight) { RemoveParticlesVisitor visitor; @@ -144,9 +134,6 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim.reset(new CreatureAnimation(ptr, mesh, mResourceSystem)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - mObjects.insert(std::make_pair(ptr, anim.release())); } @@ -157,9 +144,6 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); - if (mIncrementalCompileOperation && anim->getObjectRoot()) - mIncrementalCompileOperation->add(anim->getObjectRoot()); - mObjects.insert(std::make_pair(ptr, anim.release())); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b3799d0efb..5c7ea32f49 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -69,14 +69,10 @@ class Objects{ Resource::ResourceSystem* mResourceSystem; - osg::ref_ptr mIncrementalCompileOperation; - public: Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr rootNode); ~Objects(); - void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); - /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6a1ed89a26..e1f1e13d19 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -101,7 +102,7 @@ namespace MWRender mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); - mObjects->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); + mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 8a0d526fa0..5c3d9f1517 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include @@ -88,7 +90,10 @@ namespace Resource // TODO: add support for non-NIF formats NifOsg::Loader loader; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + + if (mIncrementalCompileOperation) + mIncrementalCompileOperation->add(loaded); mIndex[normalized] = loaded; return loaded; @@ -147,6 +152,11 @@ namespace Resource } } + void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) + { + mIncrementalCompileOperation = ico; + } + const VFS::Manager* SceneManager::getVFS() const { return mVFS; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 9f3c5387e7..625c1cd5eb 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -24,6 +24,11 @@ namespace NifOsg class KeyframeHolder; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { @@ -56,6 +61,9 @@ namespace Resource /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); + /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. + void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + const VFS::Manager* getVFS() const; Resource::TextureManager* getTextureManager(); @@ -64,6 +72,8 @@ namespace Resource const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; + osg::ref_ptr mIncrementalCompileOperation; + // observer_ptr? typedef std::map > Index; Index mIndex; From fe439e53fffc53e951cfafa690e22e7c536e114d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 May 2015 22:32:11 +0200 Subject: [PATCH 0311/1812] Bullet include cleanup --- apps/openmw/mwphysics/actor.cpp | 8 +++++--- apps/openmw/mwphysics/physicssystem.cpp | 11 +++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 7 +++++-- apps/openmw/mwphysics/trace.cpp | 5 +++-- apps/openmw/mwrender/bulletdebugdraw.cpp | 2 ++ apps/openmw/mwrender/bulletdebugdraw.hpp | 6 ++++-- components/nifbullet/bulletnifloader.cpp | 20 ++++++++++++++++++++ components/nifbullet/bulletnifloader.hpp | 24 ++++-------------------- 8 files changed, 54 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 7084af8624..c47ecd17ca 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -2,12 +2,14 @@ #include -#include - -#include "../mwworld/class.hpp" +#include +#include +#include #include +#include "../mwworld/class.hpp" + #include "convert.hpp" #include "collisiontype.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 065be083df..b706912eda 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -6,6 +6,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -600,6 +609,8 @@ namespace MWPhysics mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); mSolver = new btSequentialImpulseConstraintSolver; mBroadphase = new btDbvtBroadphase(); + + // Note we don't use any Dynamics at the moment - a btCollisionWorld might be sufficient? mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2ebe16e3bd..75666acd75 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -5,8 +5,6 @@ #include -#include - #include #include "../mwworld/ptr.hpp" @@ -35,6 +33,11 @@ namespace Resource class btSequentialImpulseConstraintSolver; class btDiscreteDynamicsWorld; +class btBroadphaseInterface; +class btDefaultCollisionConfiguration; +class btCollisionDispatcher; +class btCollisionObject; +class btCollisionShape; namespace MWPhysics { diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index ddb984821f..79d4de1a01 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -2,8 +2,9 @@ #include -#include -#include +#include +#include +#include #include "collisiontype.hpp" #include "actor.hpp" diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 36fc242266..8ac8e3121b 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index d2a4163cf8..66af2f565d 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -1,12 +1,14 @@ #ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H #define OPENMW_MWRENDER_BULLETDEBUGDRAW_H -#include "btBulletDynamicsCommon.h" - #include #include #include +#include + +class btDynamicsWorld; + namespace osg { class Group; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 89daf898ae..33c8c449d4 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -6,6 +6,11 @@ #include #include +#include +#include +#include +#include + #include #include "../nif/niffile.hpp" @@ -36,6 +41,21 @@ btVector3 getbtVector(const osg::Vec3f &v) namespace NifBullet { +// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface +struct TriangleMeshShape : public btBvhTriangleMeshShape +{ + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } +}; + BulletNifLoader::BulletNifLoader() : mCompoundShape(NULL) , mStaticMesh(NULL) diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index ae4279f40c..0865b134a5 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -6,10 +6,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -18,6 +14,10 @@ #include +class btTriangleMesh; +class btCompoundShape; +class btCollisionShape; + namespace Nif { class Node; @@ -70,22 +70,6 @@ private: osg::ref_ptr mSource; }; -// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface -struct TriangleMeshShape : public btBvhTriangleMeshShape -{ - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } - - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } -}; - - /** *Load bulletShape from NIF files. */ From 1f00174c026901ac33f00a794d38fd9bb5da3f13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 May 2015 23:09:38 +0200 Subject: [PATCH 0312/1812] Use a btCollisionWorld instead of btDiscreteDynamicsWorld Slightly improves performance, since we no longer need to stepSimulation(). We don't use any Dynamics (yet). --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwphysics/actor.cpp | 12 +-- apps/openmw/mwphysics/actor.hpp | 6 +- apps/openmw/mwphysics/physicssystem.cpp | 95 +++++++++++------------- apps/openmw/mwphysics/physicssystem.hpp | 6 +- apps/openmw/mwphysics/trace.cpp | 6 +- apps/openmw/mwphysics/trace.h | 6 +- apps/openmw/mwrender/bulletdebugdraw.cpp | 4 +- apps/openmw/mwrender/bulletdebugdraw.hpp | 6 +- cmake/FindBullet.cmake | 6 +- 10 files changed, 70 insertions(+), 78 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d45e76f258..b4ecdd9567 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -152,7 +152,6 @@ if (ANDROID) MyGUIEngineStatic cpufeatures BulletCollision - BulletDynamics LinearMath ) endif (ANDROID) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index c47ecd17ca..94d93e7d7a 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -17,12 +17,12 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world) +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) - , mDynamicsWorld(world) + , mCollisionWorld(world) { mPtr = ptr; @@ -55,7 +55,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptrremoveCollisionObject(mCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); } void Actor::enableCollisionMode(bool collision) @@ -74,13 +74,13 @@ void Actor::enableCollisionBody(bool collision) void Actor::updateCollisionMask() { - mDynamicsWorld->removeCollisionObject(mCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) collisionMask |= CollisionType_Actor | CollisionType_Projectile; if (mCanWaterWalk) collisionMask |= CollisionType_Water; - mDynamicsWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); + mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); } void Actor::updatePosition() diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 60de421511..7a12f549d4 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -9,7 +9,7 @@ #include #include -class btDynamicsWorld; +class btCollisionWorld; class btCollisionShape; class btCollisionObject; @@ -43,7 +43,7 @@ namespace MWPhysics class Actor : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btDynamicsWorld* world); + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); ~Actor(); /** @@ -125,7 +125,7 @@ namespace MWPhysics bool mInternalCollisionMode; bool mExternalCollisionMode; - btDynamicsWorld* mDynamicsWorld; + btCollisionWorld* mCollisionWorld; Actor(const Actor&); Actor& operator=(const Actor&); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b706912eda..2bd88e6343 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -12,9 +12,9 @@ #include #include #include +#include #include -#include -#include +#include #include #include @@ -65,7 +65,7 @@ namespace MWPhysics } static bool stepMove(btCollisionObject *colobj, osg::Vec3f &position, - const osg::Vec3f &toMove, float &remainingTime, btDynamicsWorld* dynamicsWorld) + const osg::Vec3f &toMove, float &remainingTime, btCollisionWorld* collisionWorld) { /* * Slide up an incline or set of stairs. Should be called only after a @@ -113,7 +113,7 @@ namespace MWPhysics */ ActorTracer tracer, stepper; - stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), dynamicsWorld); + stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) @@ -131,7 +131,7 @@ namespace MWPhysics * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, dynamicsWorld); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -150,7 +150,7 @@ namespace MWPhysics * +--+ +--+ * ============================================== */ - stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), dynamicsWorld); + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // don't allow stepping up other actors @@ -191,12 +191,12 @@ namespace MWPhysics public: - static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btDynamicsWorld* dynamicsWorld, float maxHeight) + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) { osg::Vec3f position(ptr.getRefData().getPosition().asVec3()); ActorTracer tracer; - tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), dynamicsWorld); + tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), collisionWorld); if(tracer.mFraction >= 1.0f) { actor->setOnGround(false); @@ -214,7 +214,7 @@ namespace MWPhysics resultCallback1.m_collisionFilterGroup = 0xff; resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; - dynamicsWorld->rayTest(from, to, resultCallback1); + collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) @@ -230,7 +230,7 @@ namespace MWPhysics } static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, btDynamicsWorld* dynamicsWorld + bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld , std::map& collisionTracker , std::map& standingCollisionTracker) { @@ -323,7 +323,7 @@ namespace MWPhysics if((newPosition - nextpos).length2() > 0.0001) { // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, dynamicsWorld); + tracer.doTrace(colobj, newPosition, nextpos, collisionWorld); // check for obstructions if(tracer.mFraction >= 1.0f) @@ -358,12 +358,12 @@ namespace MWPhysics osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, dynamicsWorld); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent { osg::Vec3f normalizedVelocity = velocity; normalizedVelocity.normalize(); - result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, dynamicsWorld); + result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld); } if(result) { @@ -401,7 +401,7 @@ namespace MWPhysics osg::Vec3f from = newPosition; osg::Vec3f to = newPosition - (physicActor->getOnGround() ? osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); - tracer.doTrace(colobj, from, to, dynamicsWorld); + tracer.doTrace(colobj, from, to, collisionWorld); if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { @@ -549,7 +549,7 @@ namespace MWPhysics return mCollisionObject.get(); } - void animateCollisionShapes(btDynamicsWorld* dynamicsWorld) + void animateCollisionShapes(btCollisionWorld* collisionWorld) { if (mShapeInstance->mAnimatedShapes.empty()) return; @@ -587,7 +587,7 @@ namespace MWPhysics compound->updateChildTransform(shapeIndex, transform); } - dynamicsWorld->updateSingleAabb(mCollisionObject.get()); + collisionWorld->updateSingleAabb(mCollisionObject.get()); } private: @@ -607,33 +607,29 @@ namespace MWPhysics { mCollisionConfiguration = new btDefaultCollisionConfiguration(); mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - mSolver = new btSequentialImpulseConstraintSolver; mBroadphase = new btDbvtBroadphase(); - // Note we don't use any Dynamics at the moment - a btCollisionWorld might be sufficient? - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration); + mCollisionWorld = new btCollisionWorld(mDispatcher, mBroadphase, mCollisionConfiguration); // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. - mDynamicsWorld->setForceUpdateAllAabbs(false); - - mDynamicsWorld->setGravity(btVector3(0,0,-10)); + mCollisionWorld->setForceUpdateAllAabbs(false); } PhysicsSystem::~PhysicsSystem() { if (mWaterCollisionObject.get()) - mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); for (HeightFieldMap::iterator it = mHeightFields.begin(); it != mHeightFields.end(); ++it) { - mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(it->second->getCollisionObject()); delete it->second; } for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) { - mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(it->second->getCollisionObject()); delete it->second; } @@ -642,8 +638,7 @@ namespace MWPhysics delete it->second; } - delete mDynamicsWorld; - delete mSolver; + delete mCollisionWorld; delete mCollisionConfiguration; delete mDispatcher; delete mBroadphase; @@ -655,8 +650,8 @@ namespace MWPhysics if (mDebugDrawEnabled && !mDebugDrawer.get()) { - mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mDynamicsWorld)); - mDynamicsWorld->setDebugDrawer(mDebugDrawer.get()); + mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mCollisionWorld)); + mCollisionWorld->setDebugDrawer(mDebugDrawer.get()); mDebugDrawer->setDebugMode(mDebugDrawEnabled); } else if (mDebugDrawer.get()) @@ -727,7 +722,7 @@ namespace MWPhysics DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; - mDynamicsWorld->contactTest(&object, resultCallback); + mCollisionWorld->contactTest(&object, resultCallback); if (resultCallback.mObject) { @@ -761,7 +756,7 @@ namespace MWPhysics resultCallback.m_collisionFilterGroup = 0xff; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; - mDynamicsWorld->rayTest(btFrom, btTo, resultCallback); + mCollisionWorld->rayTest(btFrom, btTo, resultCallback); if (resultCallback.hasHit()) { return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); @@ -798,7 +793,7 @@ namespace MWPhysics ContactTestResultCallback resultCallback; resultCallback.m_collisionFilterGroup = collisionGroup; resultCallback.m_collisionFilterMask = collisionMask; - mDynamicsWorld->contactTest(me, resultCallback); + mCollisionWorld->contactTest(me, resultCallback); return resultCallback.mResult; } @@ -808,7 +803,7 @@ namespace MWPhysics if (found == mActors.end()) return ptr.getRefData().getPosition().asVec3(); else - return MovementSolver::traceDown(ptr, found->second, mDynamicsWorld, maxHeight); + return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight); } void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) @@ -816,7 +811,7 @@ namespace MWPhysics HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); mHeightFields[std::make_pair(x,y)] = heightfield; - mDynamicsWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, + mCollisionWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, CollisionType_Actor|CollisionType_Projectile); } @@ -825,7 +820,7 @@ namespace MWPhysics HeightFieldMap::iterator heightfield = mHeightFields.find(std::make_pair(x,y)); if(heightfield != mHeightFields.end()) { - mDynamicsWorld->removeCollisionObject(heightfield->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(heightfield->second->getCollisionObject()); delete heightfield->second; mHeightFields.erase(heightfield); } @@ -840,7 +835,7 @@ namespace MWPhysics Object *obj = new Object(ptr, shapeInstance); mObjects.insert(std::make_pair(ptr, obj)); - mDynamicsWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } @@ -849,7 +844,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - mDynamicsWorld->removeCollisionObject(found->second->getCollisionObject()); + mCollisionWorld->removeCollisionObject(found->second->getCollisionObject()); delete found->second; mObjects.erase(found); } @@ -898,14 +893,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setScale(scale); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updateScale(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -916,14 +911,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updateRotation(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -934,14 +929,14 @@ namespace MWPhysics if (found != mObjects.end()) { found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); - mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject()); + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } ActorMap::iterator foundActor = mActors.find(ptr); if (foundActor != mActors.end()) { foundActor->second->updatePosition(); - // no aabb update needed (DISABLE_DEACTIVATION) + mCollisionWorld->updateSingleAabb(foundActor->second->getCollisionObject()); return; } } @@ -950,7 +945,7 @@ namespace MWPhysics { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); - Actor* actor = new Actor(ptr, shapeInstance, mDynamicsWorld); + Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld); mActors.insert(std::make_pair(ptr, actor)); } @@ -1032,7 +1027,7 @@ namespace MWPhysics osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mDynamicsWorld, mCollisions, mStandingCollisions); + waterlevel, slowFall, mCollisionWorld, mCollisions, mStandingCollisions); float heightDiff = newpos.z() - oldHeight; @@ -1052,10 +1047,10 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) - it->second->animateCollisionShapes(mDynamicsWorld); + it->second->animateCollisionShapes(mCollisionWorld); - // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. - mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); + CProfileManager::Reset(); + CProfileManager::Increment_Frame_Counter(); if (mDebugDrawer.get()) mDebugDrawer->step(); @@ -1153,7 +1148,7 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) @@ -1162,7 +1157,7 @@ namespace MWPhysics mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get()); - mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, + mCollisionWorld->addCollisionObject(mWaterCollisionObject.get(), CollisionType_Water, CollisionType_Actor); } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 75666acd75..841085f479 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -31,8 +31,7 @@ namespace Resource class ResourceSystem; } -class btSequentialImpulseConstraintSolver; -class btDiscreteDynamicsWorld; +class btCollisionWorld; class btBroadphaseInterface; class btDefaultCollisionConfiguration; class btCollisionDispatcher; @@ -127,9 +126,8 @@ namespace MWPhysics btBroadphaseInterface* mBroadphase; btDefaultCollisionConfiguration* mCollisionConfiguration; - btSequentialImpulseConstraintSolver* mSolver; btCollisionDispatcher* mDispatcher; - btDiscreteDynamicsWorld* mDynamicsWorld; + btCollisionWorld* mCollisionWorld; std::auto_ptr mShapeManager; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 79d4de1a01..94434b856a 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -50,7 +50,7 @@ protected: }; -void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world) { const btVector3 btstart = toBullet(start); const btVector3 btend = toBullet(end); @@ -89,7 +89,7 @@ void ActorTracer::doTrace(btCollisionObject *actor, const osg::Vec3f& start, con } } -void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world) +void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world) { const btVector3 btstart(start.x(), start.y(), start.z()+1.0f); const btVector3 btend(end.x(), end.y(), end.z()+1.0f); diff --git a/apps/openmw/mwphysics/trace.h b/apps/openmw/mwphysics/trace.h index 02f9ebdd1c..ef1a24d44a 100644 --- a/apps/openmw/mwphysics/trace.h +++ b/apps/openmw/mwphysics/trace.h @@ -4,7 +4,7 @@ #include class btCollisionObject; -class btDynamicsWorld; +class btCollisionWorld; namespace MWPhysics @@ -19,8 +19,8 @@ namespace MWPhysics float mFraction; - void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); - void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world); + void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world); + void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btCollisionWorld* world); }; } diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 8ac8e3121b..c6d7935c54 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -21,7 +21,7 @@ namespace namespace MWRender { -DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world) +DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btCollisionWorld *world) : mParentNode(parentNode), mWorld(world), mDebugOn(true) diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index 66af2f565d..1bccc20bd0 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -7,7 +7,7 @@ #include -class btDynamicsWorld; +class btCollisionWorld; namespace osg { @@ -23,7 +23,7 @@ class DebugDrawer : public btIDebugDraw { protected: osg::ref_ptr mParentNode; - btDynamicsWorld *mWorld; + btCollisionWorld *mWorld; osg::ref_ptr mGeode; osg::ref_ptr mGeometry; osg::ref_ptr mVertices; @@ -36,7 +36,7 @@ protected: public: - DebugDrawer(osg::ref_ptr parentNode, btDynamicsWorld *world); + DebugDrawer(osg::ref_ptr parentNode, btCollisionWorld *world); ~DebugDrawer(); void step(); diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index b75f3105a6..5204c00ce8 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -54,8 +54,8 @@ find_path(BULLET_INCLUDE_DIR NAMES btBulletCollisionCommon.h # Find the libraries -_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics) -_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d) +#_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics) +#_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY BulletCollision) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_Debug BulletCollision_d) _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY BulletMath LinearMath) @@ -71,7 +71,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR}) if(BULLET_FOUND) - _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) + #_BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_COLLISION_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_MATH_LIBRARY) endif() From 025a1a7866b8333651bff57b301813c3e7ebf609 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:34:38 +0200 Subject: [PATCH 0313/1812] Restore savegame screenshot display --- apps/openmw/mwgui/savegamedialog.cpp | 60 +++++++++++++++++----------- apps/openmw/mwgui/savegamedialog.hpp | 1 + components/CMakeLists.txt | 2 +- components/files/memorystream.hpp | 31 ++++++++++++++ 4 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 components/files/memorystream.hpp diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 980afdfae4..ab8d93a876 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,18 +1,21 @@ #include "savegamedialog.hpp" -#include "widgets.hpp" - -#include -#include #include #include #include #include +#include +#include + +#include + #include #include +#include + #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -22,6 +25,7 @@ #include "../mwstate/character.hpp" #include "confirmationdialog.hpp" +#include "widgets.hpp" namespace MWGui { @@ -358,30 +362,38 @@ namespace MWGui << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); -#if 0 + + // Decode screenshot - std::vector data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - Ogre::Image image; - image.load(stream, "jpg"); + const std::vector& data = mCurrentSlot->mProfile.mScreenshot; + Files::IMemStream instream (&data[0], data.size()); - const std::string textureName = "@savegame_screenshot"; - Ogre::TexturePtr texture; - texture = Ogre::TextureManager::getSingleton().getByName(textureName); - mScreenshot->setImageTexture(""); - if (texture.isNull()) + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) { - texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY); + std::cerr << "Can't open savegame screenshot, no jpg readerwriter found" << std::endl; + return; } - texture->unload(); - texture->setWidth(image.getWidth()); - texture->setHeight(image.getHeight()); - texture->loadImage(image); - mScreenshot->setImageTexture(textureName); -#endif + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); + if (!result.success()) + { + std::cerr << "Failed to read savegame screenshot: " << result.message() << std::endl; + return; + } + + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(result.getImage()); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + texture->setUnRefImageDataAfterApply(true); + + mScreenshotTexture.reset(new osgMyGUI::OSGTexture(texture)); + + mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); + mScreenshot->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2192adbdec..6a9e59cc60 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -48,6 +48,7 @@ namespace MWGui void fillSaveList(); + std::auto_ptr mScreenshotTexture; MyGUI::ImageBox* mScreenshot; bool mSaving; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b800da701d..6a5b7f59a9 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -85,7 +85,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - lowlevelfile constrainedfilestream + lowlevelfile constrainedfilestream memorystream ) add_component_dir (compiler diff --git a/components/files/memorystream.hpp b/components/files/memorystream.hpp new file mode 100644 index 0000000000..9a35100440 --- /dev/null +++ b/components/files/memorystream.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_FILES_MEMORYSTREAM_H +#define OPENMW_COMPONENTS_FILES_MEMORYSTREAM_H + +#include + +namespace Files +{ + + struct MemBuf : std::streambuf + { + MemBuf(char const* buffer, size_t size) + { + // a streambuf isn't specific to istreams, so we need a non-const pointer :/ + char* nonconstBuffer = (const_cast(buffer)); + this->setg(nonconstBuffer, nonconstBuffer, nonconstBuffer + size); + } + }; + + /// @brief A variant of std::istream that reads from a constant in-memory buffer. + struct IMemStream: virtual MemBuf, std::istream + { + IMemStream(char const* buffer, size_t size) + : MemBuf(buffer, size) + , std::istream(static_cast(this)) + { + } + }; + +} + +#endif From 6555ee8d80bf647e5982318a475ced750bf8e58f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:37:35 +0200 Subject: [PATCH 0314/1812] Minor include cleanup --- apps/openmw/mwgui/quickkeysmenu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 0c462c67d0..cd6e2405c8 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwgui/inventorywindow.hpp" -#include "../mwgui/bookwindow.hpp" -#include "../mwgui/scrollwindow.hpp" #include "windowmanagerimp.hpp" #include "itemselection.hpp" From 8b3054aa8be0e62a4daff170922a97644c055eca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 02:45:38 +0200 Subject: [PATCH 0315/1812] Fix for player collision cleanup issue --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e20904d717..38353fa685 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2107,6 +2107,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); + mPhysics->remove(getPlayerPtr()); mPlayer->set(player); } @@ -2128,6 +2129,7 @@ namespace MWWorld std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); + mPhysics->remove(getPlayerPtr()); mPhysics->addActor(getPlayerPtr(), model); } From 5628a2b823dfdc2bc812fff22b7d3b52e62e9451 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 03:47:53 +0200 Subject: [PATCH 0316/1812] Camera zoom fix --- apps/openmw/mwrender/camera.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 3982e5ad40..a945a171ef 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -319,9 +319,9 @@ namespace MWRender if (dist >= mFurthest) { dist = mFurthest; } else if (!override && dist < 10.f) { - dist = -10.f; + dist = 10.f; } else if (override && dist <= mNearest) { - dist = -mNearest; + dist = mNearest; mIsNearest = true; } mCameraDistance = dist; From c811ac6afe0bf4497812a8471be38990f5a0fcd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 03:50:44 +0200 Subject: [PATCH 0317/1812] Port fog of war Not optimized yet, need to work on fog texture's DataVariance. --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/mapwindow.cpp | 36 ++- apps/openmw/mwgui/mapwindow.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwrender/localmap.cpp | 365 +++++++++++++----------- apps/openmw/mwrender/localmap.hpp | 56 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 4 +- 9 files changed, 268 insertions(+), 206 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37112477eb..f8bf157c2d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -355,6 +355,7 @@ namespace MWBase virtual void requestMap(std::set cells) = 0; virtual void removeCell(MWWorld::CellStore* cell) = 0; + virtual void writeFog(MWWorld::CellStore* cell) = 0; }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 95de175a3e..8d2aaf04a8 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -216,21 +216,37 @@ namespace MWGui void LocalMapBase::applyFogOfWar() { -#if 0 + TextureVector fogTextures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { - std::string image = mPrefix+"_"+ MyGUI::utility::toString(mCurX + (mx-1)) + "_" - + MyGUI::utility::toString(mCurY + (-1*(my-1))); + int x = mCurX + (mx-1); + int y = mCurY + (-1*(my-1)); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black" ) - : ""); + + if (!mFogOfWar) + { + fog->setImageTexture(""); + continue; + } + + osg::ref_ptr tex = mLocalMapRender->getFogOfWarTexture(x, y); + if (tex) + { + boost::shared_ptr myguitex (new osgMyGUI::OSGTexture(tex)); + fog->setRenderItemTexture(myguitex.get()); + fog->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + fogTextures.push_back(myguitex); + } + else + fog->setImageTexture("black"); } } -#endif + // Move the textures we just set into mFogTextures, and move the previous textures into fogTextures, for deletion when this function ends. + // Note, above we need to ensure that all widgets are getting a new texture set, lest we delete textures that are still in use. + mFogTextures.swap(fogTextures); + redraw(); } @@ -344,7 +360,7 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures - std::vector > textures; + TextureVector textures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -354,7 +370,7 @@ namespace MWGui MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - osg::ref_ptr texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY); + osg::ref_ptr texture = mLocalMapRender->getMapTexture(mapX, mapY); if (texture) { boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 92cd880f4e..b44b545d20 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -106,7 +106,9 @@ namespace MWGui std::vector mMapWidgets; std::vector mFogWidgets; - std::vector > mMapTextures; + typedef std::vector > TextureVector; + TextureVector mMapTextures; + TextureVector mFogTextures; // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e4ecdad531..88b0bd3211 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2016,4 +2016,9 @@ namespace MWGui mLocalMapRender->removeCell(cell); } + void WindowManager::writeFog(MWWorld::CellStore *cell) + { + mLocalMapRender->saveFogOfWar(cell); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c0184d4b6d..c275a9f626 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -368,6 +368,7 @@ namespace MWGui void requestMap(std::set cells); void removeCell(MWWorld::CellStore* cell); + void writeFog(MWWorld::CellStore* cell); private: Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0da14f7024..0e7256345d 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,16 +1,20 @@ #include "localmap.hpp" #include +#include #include #include #include +#include + #include #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -44,6 +48,11 @@ namespace MWRender::LocalMap* mParent; }; + float square(float val) + { + return val*val; + } + } namespace MWRender @@ -81,47 +90,37 @@ const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f void LocalMap::clear() { + mSegments.clear(); } void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { - /* if (!mInterior) { - std::string textureName = "Cell_"+coordStr(cell->getCell()->getGridX(), cell->getCell()->getGridY())+"_fog"; + const MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; + std::auto_ptr fog (new ESM::FogState()); fog->mFogTextures.push_back(ESM::FogTexture()); - TexturePtr tex = TextureManager::getSingleton().getByName(textureName); - if (tex.isNull()) - return; - - Ogre::Image image; - tex->load(); - tex->convertToImage(image); - - Ogre::DataStreamPtr encoded = image.encode("tga"); - fog->mFogTextures.back().mImageData.resize(encoded->size()); - encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + segment.saveFogOfWar(fog->mFogTextures.back()); cell->setFog(fog.release()); } else { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); - Vector2 length = max-min; - const int segsX = static_cast(std::ceil(length.x / mMapWorldSize)); - const int segsY = static_cast(std::ceil(length.y / mMapWorldSize)); - - mInteriorName = cell->getCell()->mName; + // FIXME: segmenting code duplicated from requestMap + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); + osg::Vec2f length = max-min; + const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); std::auto_ptr fog (new ESM::FogState()); - fog->mBounds.mMinX = mBounds.getMinimum().x; - fog->mBounds.mMaxX = mBounds.getMaximum().x; - fog->mBounds.mMinY = mBounds.getMinimum().y; - fog->mBounds.mMaxY = mBounds.getMaximum().y; + fog->mBounds.mMinX = mBounds.xMin(); + fog->mBounds.mMaxX = mBounds.xMax(); + fog->mBounds.mMinY = mBounds.yMin(); + fog->mBounds.mMaxY = mBounds.yMax(); fog->mNorthMarkerAngle = mAngle; fog->mFogTextures.reserve(segsX*segsY); @@ -130,21 +129,11 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { for (int y=0; ygetCell()->mName + "_" + coordStr(x,y) + "_fog"; - - TexturePtr tex = TextureManager::getSingleton().getByName(textureName); - if (tex.isNull()) - return; - - Ogre::Image image; - tex->load(); - tex->convertToImage(image); + const MapSegment& segment = mSegments[std::make_pair(x,y)]; fog->mFogTextures.push_back(ESM::FogTexture()); - Ogre::DataStreamPtr encoded = image.encode("tga"); - fog->mFogTextures.back().mImageData.resize(encoded->size()); - encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + segment.saveFogOfWar(fog->mFogTextures.back()); fog->mFogTextures.back().mX = x; fog->mFogTextures.back().mY = y; @@ -153,7 +142,6 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) cell->setFog(fog.release()); } - */ } osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax) @@ -221,7 +209,9 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int camera->addChild(mSceneRoot); mRoot->addChild(camera); mActiveCameras.push_back(camera); - mTextures[std::make_pair(x, y)] = texture; + + MapSegment& segment = mSegments[std::make_pair(x, y)]; + segment.mMapTexture = texture; } void LocalMap::requestMap(std::set cells) @@ -238,19 +228,30 @@ void LocalMap::requestMap(std::set cells) void LocalMap::removeCell(MWWorld::CellStore *cell) { + saveFogOfWar(cell); + if (cell->isExterior()) - mTextures.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + mSegments.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); else - mTextures.clear(); + mSegments.clear(); } -osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +osg::ref_ptr LocalMap::getMapTexture(int x, int y) { - TextureMap::iterator found = mTextures.find(std::make_pair(x, y)); - if (found == mTextures.end()) + SegmentMap::iterator found = mSegments.find(std::make_pair(x, y)); + if (found == mSegments.end()) return osg::ref_ptr(); else - return found->second; + return found->second.mMapTexture; +} + +osg::ref_ptr LocalMap::getFogOfWarTexture(int x, int y) +{ + SegmentMap::iterator found = mSegments.find(std::make_pair(x, y)); + if (found == mSegments.end()) + return osg::ref_ptr(); + else + return found->second.mFogOfWarTexture; } void LocalMap::markForRemoval(osg::Camera *cam) @@ -277,7 +278,6 @@ void LocalMap::cleanupCameras() mRoot->removeChild(*it); } - mCamerasPendingRemoval.clear(); } @@ -296,15 +296,11 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) osg::Vec3d(0,1,0), zmin, zmax); setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); - /* - if (mBuffers.find(name) == mBuffers.end()) - { - if (cell->getFog()) - loadFogOfWar(name, cell->getFog()->mFogTextures.back()); - else - createFogOfWar(name); - } - */ + MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; + if (cell->getFog()) + segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); + else + segment.initFogOfWar(); } void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) @@ -361,20 +357,19 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not // be covered by the map anymore. // The following code detects this, and discards the CellStore's fog state if it needs to. - /* if (cell->getFog()) { ESM::FogState* fog = cell->getFog(); - Ogre::Vector3 newMin (fog->mBounds.mMinX, fog->mBounds.mMinY, zMin); - Ogre::Vector3 newMax (fog->mBounds.mMaxX, fog->mBounds.mMaxY, zMax); + osg::Vec3f newMin (fog->mBounds.mMinX, fog->mBounds.mMinY, zMin); + osg::Vec3f newMax (fog->mBounds.mMaxX, fog->mBounds.mMaxY, zMax); - Ogre::Vector3 minDiff = newMin - mBounds.getMinimum(); - Ogre::Vector3 maxDiff = newMax - mBounds.getMaximum(); + osg::Vec3f minDiff = newMin - mBounds._min; + osg::Vec3f maxDiff = newMax - mBounds._max; - if (std::abs(minDiff.x) > padding || std::abs(minDiff.y) > padding - || std::abs(maxDiff.x) > padding || std::abs(maxDiff.y) > padding - || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) + if (std::abs(minDiff.x()) > padding || std::abs(minDiff.y()) > padding + || std::abs(maxDiff.x()) > padding || std::abs(maxDiff.y()) > padding + || std::abs(mAngle - fog->mNorthMarkerAngle) > osg::DegreesToRadians(5.f)) { // Nuke it cell->setFog(NULL); @@ -382,11 +377,10 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) else { // Looks sane, use it - mBounds = Ogre::AxisAlignedBox(newMin, newMax); + mBounds = osg::BoundingBox(newMin, newMax); mAngle = fog->mNorthMarkerAngle; } } - */ osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); @@ -399,6 +393,7 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); + int i = 0; for (int x=0; xgetFog()) - createFogOfWar(texturePrefix); + segment.initFogOfWar(); else { ESM::FogState* fog = cell->getFog(); // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. if (i >= int(fog->mFogTextures.size())) - throw std::runtime_error("fog texture count mismatch"); + { + std::cout << "Warning: fog texture count mismatch" << std::endl; + break; + } - ESM::FogTexture& esm = fog->mFogTextures[i]; - loadFogOfWar(texturePrefix, esm); + segment.loadFogOfWar(fog->mFogTextures[i]); } - */ + ++i; } } } -/* -void LocalMap::createFogOfWar(const std::string& texturePrefix) -{ - const std::string texName = texturePrefix + "_fog"; - TexturePtr tex = createFogOfWarTexture(texName); - - // create a buffer to use for dynamic operations - std::vector buffer; - - // initialize to (0, 0, 0, 1) - buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000); - - // upload to the texture - tex->load(); - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); - - mBuffers[texturePrefix] = buffer; -} -*/ - -/* -void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) -{ - std::vector& data = esm.mImageData; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - Ogre::Image image; - image.load(stream, "tga"); - - if (int(image.getWidth()) != sFogOfWarResolution || int(image.getHeight()) != sFogOfWarResolution) - throw std::runtime_error("fog texture size mismatch"); - - std::string texName = texturePrefix + "_fog"; - - Ogre::TexturePtr tex = createFogOfWarTexture(texName); - - tex->unload(); - tex->loadImage(image); - - // create a buffer to use for dynamic operations - std::vector buffer; - buffer.resize(sFogOfWarResolution*sFogOfWarResolution); - memcpy(&buffer[0], image.getData(), image.getSize()); - - mBuffers[texturePrefix] = buffer; -} -*/ - void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) { pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); @@ -510,11 +459,8 @@ osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return true; - /* - std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); - - if (mBuffers.find(texName) == mBuffers.end()) + const MapSegment& segment = mSegments[std::make_pair(x, y)]; + if (!segment.mFogOfWarImage) return false; nX = std::max(0.f, std::min(1.f, nX)); @@ -523,24 +469,14 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi int texU = static_cast((sFogOfWarResolution - 1) * nX); int texV = static_cast((sFogOfWarResolution - 1) * nY); - Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; - uint8 alpha = (clr >> 24); + uint32_t clr = ((const uint32_t*)segment.mFogOfWarImage->data())[texV * sFogOfWarResolution + texU]; + uint8_t alpha = (clr >> 24); return alpha < 200; - */ } void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, float& u, float& v, int& x, int& y, osg::Vec3f& direction) { - /* - if (sFogOfWarSkip != 0) - { - static int count=0; - if (++count % sFogOfWarSkip != 0) - return; - } - */ - // retrieve the x,y grid coordinates the player is in osg::Vec2f pos(position.x(), position.y()); @@ -563,11 +499,9 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient v = 1.0f-std::abs((pos.y() - (mMapWorldSize*y))/mMapWorldSize); } - - /* // explore radius (squared) const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 - const float sqrExploreRadius = Math::Sqr(exploreRadius); + const float sqrExploreRadius = square(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) // change the affected fog of war textures (in a 3x3 grid around the player) @@ -575,7 +509,6 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient { for (int my = -1; my<2; ++my) { - // is this texture affected at all? bool affected = false; if (mx == 0 && my == 0) // the player is always in the center of the 3x3 grid @@ -590,45 +523,137 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient if (!affected) continue; - std::string texName = texBaseName + coordStr(x+mx,y+my*-1); + int texX = x + mx; + int texY = y + my*-1; - TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); - if (!tex.isNull()) + MapSegment& segment = mSegments[std::make_pair(texX, texY)]; + + if (!segment.mFogOfWarImage || !segment.mMapTexture) + continue; + + unsigned char* data = segment.mFogOfWarImage->data(); + for (int texV = 0; texV >::iterator anIter; - - // get its buffer - anIter = mBuffers.find(texName); - if (anIter == mBuffers.end()) return; - - std::vector& aBuffer = (*anIter).second; - int i=0; - for (int texV = 0; texV> 24); - alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); - aBuffer[i] = (uint32) (alpha << 24); + float sqrDist = square((texU + mx*(sFogOfWarResolution-1)) - u*(sFogOfWarResolution-1)) + + square((texV + my*(sFogOfWarResolution-1)) - v*(sFogOfWarResolution-1)); - ++i; - } + uint32_t clr = *(uint32_t*)data; + uint8_t alpha = (clr >> 24); + + alpha = std::min( alpha, (uint8_t) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); + *(uint32_t*)data = (uint32_t) (alpha << 24); + + data += 4; } - - tex->load(); - - // copy to the texture - // NOTE: Could be optimized later. We actually only need to update the region that changed. - // Not a big deal at the moment, the FoW is only 32x32 anyway. - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &aBuffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); } + + segment.mHasFogState = true; + segment.mFogOfWarImage->dirty(); } } - */ +} + +LocalMap::MapSegment::MapSegment() + : mHasFogState(false) +{ +} + +LocalMap::MapSegment::~MapSegment() +{ + +} + +void LocalMap::MapSegment::createFogOfWarTexture() +{ + if (mFogOfWarTexture) + return; + mFogOfWarTexture = new osg::Texture2D; + mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); + mFogOfWarTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mFogOfWarTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mFogOfWarTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mFogOfWarTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mFogOfWarTexture->setUnRefImageDataAfterApply(false); +} + +void LocalMap::MapSegment::initFogOfWar() +{ + mFogOfWarImage = new osg::Image; + mFogOfWarImage->allocateImage(sFogOfWarResolution, sFogOfWarResolution, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert(mFogOfWarImage->isDataContiguous()); + std::vector data; + data.resize(sFogOfWarResolution*sFogOfWarResolution, 0xff000000); + + memcpy(mFogOfWarImage->data(), &data[0], data.size()*4); + + createFogOfWarTexture(); + mFogOfWarTexture->setImage(mFogOfWarImage); +} + +void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) +{ + const std::vector& data = esm.mImageData; + if (!data.size()) + { + initFogOfWar(); + return; + } + + // TODO: deprecate tga and use raw data instead + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga"); + if (!readerwriter) + { + std::cerr << "Unable to load fog, can't find a tga ReaderWriter" << std::endl; + return; + } + + Files::IMemStream in(&data[0], data.size()); + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in); + if (!result.success()) + { + std::cerr << "Failed to read fog: " << result.message() << std::endl; + return; + } + + mFogOfWarImage = result.getImage(); + mFogOfWarImage->flipVertical(); + mFogOfWarImage->dirty(); + + createFogOfWarTexture(); + mFogOfWarTexture->setImage(mFogOfWarImage); + mHasFogState = true; +} + +void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const +{ + if (!mFogOfWarImage || !mHasFogState) + return; + + std::ostringstream ostream; + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga"); + if (!readerwriter) + { + std::cerr << "Unable to write fog, can't find a tga ReaderWriter" << std::endl; + return; + } + + // extra flips are unfortunate, but required for compatibility with older versions + mFogOfWarImage->flipVertical(); + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream); + if (!result.success()) + { + std::cerr << "Unable to write fog: " << result.message() << std::endl; + return; + } + mFogOfWarImage->flipVertical(); + + std::string data = ostream.str(); + fog.mImageData = std::vector(data.begin(), data.end()); } } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index ba92cde246..c319b7ce7f 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -27,6 +27,7 @@ namespace osgViewer namespace osg { class Texture2D; + class Image; class Camera; class Group; class Node; @@ -48,12 +49,23 @@ namespace MWRender */ void clear(); + /** + * Request a map render for the given cells. Render textures will be immediately created and can be retrieved with the getMapTexture function. + */ void requestMap (std::set cells); + /** + * Remove map and fog textures for the given cell. + */ void removeCell (MWWorld::CellStore* cell); - osg::ref_ptr getMapTexture (bool interior, int x, int y); + osg::ref_ptr getMapTexture (int x, int y); + osg::ref_ptr getFogOfWarTexture (int x, int y); + + /** + * Indicates a camera has been queued for rendering and can be cleaned up in the next frame. For internal use only. + */ void markForRemoval(osg::Camera* cam); /** @@ -78,8 +90,7 @@ namespace MWRender void saveFogOfWar(MWWorld::CellStore* cell); /** - * Get the interior map texture index and normalized position - * on this texture, given a world position + * Get the interior map texture index and normalized position on this texture, given a world position */ void worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y); @@ -102,17 +113,31 @@ namespace MWRender CameraVector mCamerasPendingRemoval; - typedef std::map, osg::ref_ptr > TextureMap; - TextureMap mTextures; + struct MapSegment + { + MapSegment(); + ~MapSegment(); + + void initFogOfWar(); + void loadFogOfWar(const ESM::FogTexture& fog); + void saveFogOfWar(ESM::FogTexture& fog) const; + void createFogOfWarTexture(); + + osg::ref_ptr mMapTexture; + osg::ref_ptr mFogOfWarTexture; + osg::ref_ptr mFogOfWarImage; + + bool mHasFogState; + }; + + typedef std::map, MapSegment> SegmentMap; + SegmentMap mSegments; int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high static const int sFogOfWarResolution = 32; - // frames to skip before rendering fog of war - static const int sFogOfWarSkip = 2; - // size of a map segment (for exteriors, 1 cell) float mMapWorldSize; @@ -125,23 +150,8 @@ namespace MWRender osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); void setupRenderToTexture(osg::ref_ptr camera, int x, int y); - // Creates a fog of war texture and initializes it to full black - //void createFogOfWar(const std::string& texturePrefix); - - // Loads a fog of war texture from its ESM struct - //void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it - - // A buffer for the "fog of war" textures of the current cell. - // Both interior and exterior maps are possibly divided into multiple textures. - //std::map > mBuffers; - - // The render texture we will use to create the map images - //Ogre::TexturePtr mRenderTexture; - //Ogre::RenderTarget* mRenderTarget; - bool mInterior; osg::BoundingBox mBounds; - //std::string mInteriorName; }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 0883bc63b3..d403590dd1 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -179,12 +179,14 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mTimePlayed = mTimePlayed; profile.mDescription = description; + /* int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing Ogre::Image screenshot; world.screenshot(screenshot, screenshotW, screenshotH); Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); profile.mScreenshot.resize(encoded->size()); encoded->read(&profile.mScreenshot[0], encoded->size()); + */ if (!slot) slot = getCurrentCharacter()->createSlot (profile); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 38353fa685..427a41d643 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -337,8 +337,8 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - //CellStore* cellstore = *iter; - //mRendering->writeFog(cellstore); + CellStore* cellstore = *iter; + MWBase::Environment::get().getWindowManager()->writeFog(cellstore); } MWMechanics::CreatureStats::writeActorIdCounter(writer); From f4ee805e3be333177a3c5f518f0b172c9f9b6634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 15:44:58 +0200 Subject: [PATCH 0318/1812] Object animation fix --- apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 ++- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 4 +++- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 2 -- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwworld/player.cpp | 1 - 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index fccace55c2..9ec5bc19a0 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -2,11 +2,12 @@ #include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "movement.hpp" -#include "mechanicsmanagerimp.hpp" + #include diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9f3a23dd08..7588a3287b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1875,7 +1875,7 @@ void CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - std::cerr<< "Animation "<(ptr.getRefData().getBaseNode()), resourceSystem) { if (!model.empty()) { setObjectRoot(model, false, false); + if (animated) + addAnimSource(model); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 20fbbed5ce..d298fdff05 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -395,7 +395,7 @@ private: class ObjectAnimation : public Animation { public: - ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool allowLight); + ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool animated, bool allowLight); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 810fc8b196..b653f4d300 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -24,7 +24,6 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { setObjectRoot(model, false, false); - //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); @@ -43,7 +42,6 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { setObjectRoot(model, true, false); - //setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 47a54fdbfb..2eb72dfd2a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -109,7 +109,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool { insertBegin(ptr); - std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, allowLight)); + std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight)); if (!allowLight) { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b81532e18..09f6de072d 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -20,7 +20,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actors.hpp" -#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "class.hpp" #include "ptr.hpp" From 5f7a82e0dad7a1809c59ca31b599c024f9b093ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 16:20:29 +0200 Subject: [PATCH 0319/1812] Fog of war fix --- apps/openmw/mwrender/localmap.cpp | 41 +++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0e7256345d..495ea2d1d4 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -297,10 +297,13 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; - if (cell->getFog()) - segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); - else - segment.initFogOfWar(); + if (!segment.mFogOfWarImage) + { + if (cell->getFog()) + segment.loadFogOfWar(cell->getFog()->mFogTextures.back()); + else + segment.initFogOfWar(); + } } void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) @@ -414,20 +417,23 @@ void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) setupRenderToTexture(camera, x, y); MapSegment& segment = mSegments[std::make_pair(x,y)]; - if (!cell->getFog()) - segment.initFogOfWar(); - else + if (!segment.mFogOfWarImage) { - ESM::FogState* fog = cell->getFog(); - - // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. - if (i >= int(fog->mFogTextures.size())) + if (!cell->getFog()) + segment.initFogOfWar(); + else { - std::cout << "Warning: fog texture count mismatch" << std::endl; - break; - } + ESM::FogState* fog = cell->getFog(); - segment.loadFogOfWar(fog->mFogTextures[i]); + // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. + if (i >= int(fog->mFogTextures.size())) + { + std::cout << "Warning: fog texture count mismatch" << std::endl; + break; + } + + segment.loadFogOfWar(fog->mFogTextures[i]); + } } ++i; } @@ -570,7 +576,8 @@ void LocalMap::MapSegment::createFogOfWarTexture() if (mFogOfWarTexture) return; mFogOfWarTexture = new osg::Texture2D; - mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); + // TODO: synchronize access? for now, the worst that could happen is the draw thread jumping a frame ahead. + //mFogOfWarTexture->setDataVariance(osg::Object::DYNAMIC); mFogOfWarTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mFogOfWarTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mFogOfWarTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); @@ -581,6 +588,8 @@ void LocalMap::MapSegment::createFogOfWarTexture() void LocalMap::MapSegment::initFogOfWar() { mFogOfWarImage = new osg::Image; + // Assign a PixelBufferObject for asynchronous transfer of data to the GPU + mFogOfWarImage->setPixelBufferObject(new osg::PixelBufferObject); mFogOfWarImage->allocateImage(sFogOfWarResolution, sFogOfWarResolution, 1, GL_RGBA, GL_UNSIGNED_BYTE); assert(mFogOfWarImage->isDataContiguous()); std::vector data; From 9ee63dc3f406cb14846b09c9c2b22c9c3e2083f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 16:28:48 +0200 Subject: [PATCH 0320/1812] Change stats viewer key to f3 --- apps/openmw/engine.cpp | 2 +- components/sdlutil/sdlinputwrapper.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9bfd867091..fed1f134b8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -541,7 +541,7 @@ void OMW::Engine::go() mViewer = new osgViewer::Viewer; osg::ref_ptr statshandler = new osgViewer::StatsHandler; - statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F9); + statshandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F3); statshandler->addUserStatsLine("Script", osg::Vec4f(1.f, 1.f, 1.f, 1.f), osg::Vec4f(1.f, 1.f, 1.f, 1.f), "script_time_taken", 1000.0, true, false, "script_time_begin", "script_time_end", 10000); diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index c321c342c0..a9209bf58b 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -84,8 +84,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyPressed(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_F9) - mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F9); + if (evt.key.keysym.sym == SDLK_F3) + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F3); break; case SDL_KEYUP: @@ -93,8 +93,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyboardListener->keyReleased(evt.key); // temporary for the stats viewer - if (evt.key.keysym.sym == SDLK_F9) - mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F9); + if (evt.key.keysym.sym == SDLK_F3) + mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F3); break; case SDL_TEXTINPUT: From 1cdb440b77f262685e8fb1789652eda77abe7424 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 17:23:06 +0200 Subject: [PATCH 0321/1812] glReadPixels *is* available on OpenGL ES --- components/sdlutil/sdlcursormanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 2befc7bd05..1c5008f7af 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -119,7 +119,6 @@ namespace osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); - // TODO: implement for GL ES glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); geom->releaseGLObjects(); From 72d0a69132864c5d84fcf9b3a021acdfe452d412 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 18:44:34 +0200 Subject: [PATCH 0322/1812] Fix global map markers not being cleared on a new game --- apps/openmw/mwgui/mapwindow.cpp | 6 ++++-- apps/openmw/mwgui/mapwindow.hpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8d2aaf04a8..3a56d3dfd1 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -782,6 +782,7 @@ namespace MWGui markerWidget->setDepth(Global_MarkerLayer); markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + mGlobalMapMarkers.push_back(markerWidget); } } @@ -899,8 +900,9 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - while (mEventBoxGlobal->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mEventBoxGlobal->getChildAt(0)); + for (std::vector::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(*it); + mGlobalMapMarkers.clear(); } void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index b44b545d20..40ccbda5f1 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -236,6 +236,8 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; + std::vector mGlobalMapMarkers; + EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; From 7a1408cfed960ded9d10baedb5b8ba126a73fb9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 18:49:24 +0200 Subject: [PATCH 0323/1812] Restore display of global map overlay, no exploration yet --- apps/openmw/mwgui/mapwindow.cpp | 11 +-- apps/openmw/mwgui/mapwindow.hpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 144 ++++++++++++++++++++--------- apps/openmw/mwrender/globalmap.hpp | 6 +- 4 files changed, 114 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3a56d3dfd1..46e2f29e03 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -582,7 +582,6 @@ namespace MWGui , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) - , mGlobalMapTexture(NULL) , mGlobalMapImage(NULL) , mGlobalMapOverlay(NULL) , mGlobal(false) @@ -736,17 +735,17 @@ namespace MWGui mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapTexture = new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture()); - mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture); + mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); + mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); - //mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); + mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); + mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } MapWindow::~MapWindow() { - delete mGlobalMapTexture; - delete mGlobalMapRender; } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 40ccbda5f1..bea3d33b9f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -212,7 +212,8 @@ namespace MWGui void globalMapUpdatePlayer(); MyGUI::ScrollView* mGlobalMap; - MyGUI::ITexture* mGlobalMapTexture; + std::auto_ptr mGlobalMapTexture; + std::auto_ptr mGlobalMapOverlayTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index da1be00287..8ca21cbfb1 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -5,8 +5,11 @@ #include #include +#include + #include #include +#include #include @@ -134,7 +137,12 @@ namespace MWRender } mBaseTexture = new osg::Texture2D; + mBaseTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mBaseTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mBaseTexture->setImage(image); + mBaseTexture->setResizeNonPowerOfTwoHint(false); clear(); @@ -200,14 +208,25 @@ namespace MWRender void GlobalMap::clear() { - /* - Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); - memset(buffer, 0, mWidth * mHeight * 4); + if (!mOverlayImage) + { + mOverlayImage = new osg::Image; + mOverlayImage->allocateImage(mWidth, mHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert(mOverlayImage->isDataContiguous()); + } + memset(mOverlayImage->data(), 0, mOverlayImage->getTotalSizeInBytes()); + mOverlayImage->dirty(); - mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image - - mOverlayTexture->load(); - */ + if (!mOverlayTexture) + { + mOverlayTexture = new osg::Texture2D; + mOverlayTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setImage(mOverlayImage); + mOverlayTexture->setResizeNonPowerOfTwoHint(false); + } } void GlobalMap::write(ESM::GlobalMap& map) @@ -217,13 +236,35 @@ namespace MWRender map.mBounds.mMinY = mMinY; map.mBounds.mMaxY = mMaxY; - /* - Ogre::DataStreamPtr encoded = mOverlayImage.encode("png"); - map.mImageData.resize(encoded->size()); - encoded->read(&map.mImageData[0], encoded->size()); - */ + std::ostringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't write map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); + if (!result.success()) + { + std::cerr << "Can't write map overlay: " << result.message() << std::endl; + return; + } + + std::string data = ostream.str(); + map.mImageData = std::vector(data.begin(), data.end()); } + struct Box + { + int mLeft, mRight, mTop, mBottom; + + Box(int left, int right, int top, int bottom) + : mLeft(left), mRight(right), mTop(top), mBottom(bottom) + { + } + }; + void GlobalMap::read(ESM::GlobalMap& map) { const ESM::GlobalMap::Bounds& bounds = map.mBounds; @@ -237,17 +278,35 @@ namespace MWRender || bounds.mMinY > bounds.mMaxY) throw std::runtime_error("invalid map bounds"); - /* - Ogre::Image image; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); - image.load(stream, "png"); + if (!map.mImageData.size()) + return; + + Files::IMemStream istream(&map.mImageData[0], map.mImageData.size()); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't read map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); + if (!result.success()) + { + std::cerr << "Can't read map overlay: " << result.message() << std::endl; + return; + } + + osg::ref_ptr image = result.getImage(); + int imageWidth = image->s(); + int imageHeight = image->t(); int xLength = (bounds.mMaxX-bounds.mMinX+1); int yLength = (bounds.mMaxY-bounds.mMinY+1); // Size of one cell in image space - int cellImageSizeSrc = image.getWidth() / xLength; - if (int(image.getHeight() / yLength) != cellImageSizeSrc) + int cellImageSizeSrc = imageWidth / xLength; + if (int(imageHeight / yLength) != cellImageSizeSrc) throw std::runtime_error("cell size must be quadratic"); // If cell bounds of the currently loaded content and the loaded savegame do not match, @@ -266,39 +325,40 @@ namespace MWRender int topDiff = (bounds.mMaxY - mMaxY); int rightDiff = (bounds.mMaxX - mMaxX); int bottomDiff = (mMinY - bounds.mMinY); - Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), + + Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), std::max(0, topDiff * cellImageSizeSrc), - std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc), - std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc)); + std::min(imageWidth, imageWidth - rightDiff * cellImageSizeSrc), + std::min(imageHeight, imageHeight - bottomDiff * cellImageSizeSrc)); - Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), + Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), std::max(0, -topDiff * cellImageSizeDst), - std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst), - std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst)); + std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), + std::min(mHeight, mHeight + bottomDiff * cellImageSizeDst)); - // Looks like there is no interface for blitting from memory with src/dst boxes. - // So we create a temporary texture for blitting. - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(), - image.getHeight(), 0, Ogre::PF_A8B8G8R8); - tex->loadImage(image); - - mOverlayTexture->load(); - mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox); - - if (srcBox.left == destBox.left && srcBox.right == destBox.right - && srcBox.top == destBox.top && srcBox.bottom == destBox.bottom - && int(image.getWidth()) == mWidth && int(image.getHeight()) == mHeight) - mOverlayImage = image; + if (srcBox.mLeft == destBox.mLeft && srcBox.mRight == destBox.mRight + && srcBox.mTop == destBox.mTop && srcBox.mBottom == destBox.mBottom + && imageWidth == mWidth && imageHeight == mHeight) + { + mOverlayImage->copySubImage(0, 0, 0, image); + } else - mOverlayTexture->convertToImage(mOverlayImage); - - Ogre::TextureManager::getSingleton().remove("@temp"); - */ + { + // TODO: + // Dimensions don't match. This could mean a changed map region, or a changed map resolution. + // In the latter case, we'll want to use filtering. + // Create a RTT Camera and draw the image onto mOverlayImage in the next frame? + } + mOverlayImage->dirty(); } osg::ref_ptr GlobalMap::getBaseTexture() { return mBaseTexture; } + + osg::ref_ptr GlobalMap::getOverlayTexture() + { + return mOverlayTexture; + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index d7e20a3a77..9ca7ed5b4a 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -9,6 +9,7 @@ namespace osg { class Texture2D; + class Image; } namespace Loading @@ -50,7 +51,7 @@ namespace MWRender void read (ESM::GlobalMap& map); osg::ref_ptr getBaseTexture(); - //osg::ref_ptr getOverlayTexture(); + osg::ref_ptr getOverlayTexture(); private: int mCellSize; @@ -58,6 +59,9 @@ namespace MWRender std::vector< std::pair > mExploredCells; osg::ref_ptr mBaseTexture; + osg::ref_ptr mOverlayTexture; + + osg::ref_ptr mOverlayImage; int mWidth; int mHeight; From 6d3528af7099e300e819f6311a0b299130d7e834 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 01:49:52 +0200 Subject: [PATCH 0324/1812] Port global map exploration --- apps/openmw/mwgui/mapwindow.cpp | 9 +- apps/openmw/mwrender/globalmap.cpp | 241 +++++++++++++++++++++++------ apps/openmw/mwrender/globalmap.hpp | 53 ++++++- apps/openmw/mwrender/localmap.cpp | 5 + apps/openmw/mwrender/localmap.hpp | 2 + 5 files changed, 256 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 46e2f29e03..d748bef6c2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -587,7 +587,7 @@ namespace MWGui , mGlobal(false) , mEventBoxGlobal(NULL) , mEventBoxLocal(NULL) - , mGlobalMapRender(0) + , mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot())) , mEditNoteDialog() { static bool registered = false; @@ -730,7 +730,6 @@ namespace MWGui void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { - mGlobalMapRender = new MWRender::GlobalMap(); mGlobalMapRender->render(loadingListener); mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); @@ -794,9 +793,11 @@ namespace MWGui { LocalMapBase::onFrame(dt); + mGlobalMapRender->cleanupCameras(); + for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) { - mGlobalMapRender->exploreCell(it->first, it->second); + mGlobalMapRender->exploreCell(it->first, it->second, mLocalMapRender->getMapTexture(it->first, it->second)); } mQueuedToExplore.clear(); @@ -866,6 +867,8 @@ namespace MWGui void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); + + setGlobalMapPlayerDir(mLastDirectionX, mLastDirectionY); } void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 8ca21cbfb1..1e30eb0fcb 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -4,6 +4,10 @@ #include #include +#include +#include +#include +#include #include @@ -18,11 +22,66 @@ #include "../mwworld/esmstore.hpp" +#include "vismask.hpp" + +namespace +{ + + // Create a screen-aligned quad with given texture coordinates. + // Assumes a top-left origin of the sampled image. + osg::ref_ptr createTexturedQuad(float leftTexCoord, float topTexCoord, float rightTexCoord, float bottomTexCoord) + { + osg::ref_ptr geom = new osg::Geometry; + + osg::ref_ptr verts = new osg::Vec3Array; + verts->push_back(osg::Vec3f(-1, -1, 0)); + verts->push_back(osg::Vec3f(-1, 1, 0)); + verts->push_back(osg::Vec3f(1, 1, 0)); + verts->push_back(osg::Vec3f(1, -1, 0)); + + geom->setVertexArray(verts); + + osg::ref_ptr texcoords = new osg::Vec2Array; + texcoords->push_back(osg::Vec2f(leftTexCoord, 1.f-bottomTexCoord)); + texcoords->push_back(osg::Vec2f(leftTexCoord, 1.f-topTexCoord)); + texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-topTexCoord)); + texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-bottomTexCoord)); + + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); + + return geom; + } + + + class CameraUpdateCallback : public osg::NodeCallback + { + public: + CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + : mCamera(cam), mParent(parent) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + mParent->markForRemoval(mCamera); + traverse(node, nv); + } + + private: + osg::ref_ptr mCamera; + MWRender::GlobalMap* mParent; + }; + +} + namespace MWRender { - GlobalMap::GlobalMap() - : mWidth(0) + GlobalMap::GlobalMap(osg::Group* root) + : mRoot(root) + , mWidth(0) , mHeight(0) , mMinX(0), mMaxX(0) , mMinY(0), mMaxY(0) @@ -164,46 +223,78 @@ namespace MWRender imageY = 1.f-float(y - mMinY + 1) / (mMaxY - mMinY + 1); } - void GlobalMap::exploreCell(int cellX, int cellY) + void GlobalMap::requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, + float srcLeft, float srcTop, float srcRight, float srcBottom) { - //float originX = static_cast((cellX - mMinX) * mCellSize); - // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - //float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); + osg::ref_ptr camera (new osg::Camera); + camera->setNodeMask(Mask_RenderToTexture); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setProjectionResizePolicy(osg::Camera::FIXED); + camera->setRenderOrder(osg::Camera::PRE_RENDER); + camera->setViewport(x, y, width, height); + + if (clear) + { + camera->setClearMask(GL_COLOR_BUFFER_BIT); + camera->setClearColor(osg::Vec4(0,0,0,0)); + } + else + camera->setClearMask(GL_NONE); + + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); + + if (cpuCopy) + { + // Attach an image to copy the render back to the CPU when finished + osg::ref_ptr image (new osg::Image); + image->setPixelFormat(mOverlayImage->getPixelFormat()); + image->setDataType(mOverlayImage->getDataType()); + camera->attach(osg::Camera::COLOR_BUFFER, image); + + // FIXME: why does the image get slightly darker by the read back? + ImageDest imageDest; + imageDest.mImage = image; + imageDest.mX = x; + imageDest.mY = y; + mPendingImageDest.push_back(imageDest); + } + + // Create a quad rendering the updated texture + if (texture) + { + osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); + osg::ref_ptr depth = new osg::Depth; + depth->setFunction(osg::Depth::ALWAYS); + geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + osg::ref_ptr geode = new osg::Geode; + geode->addDrawable(geom); + camera->addChild(geode); + } + + mRoot->addChild(camera); + + mActiveCameras.push_back(camera); + } + + void GlobalMap::exploreCell(int cellX, int cellY, osg::ref_ptr localMapTexture) + { + if (!localMapTexture) + return; + + int originX = (cellX - mMinX) * mCellSize; + int originY = (cellY - mMinY) * mCellSize; if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; - /* - Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" - + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); - - if (!localMapTexture.isNull()) - { - int mapWidth = localMapTexture->getWidth(); - int mapHeight = localMapTexture->getHeight(); - mOverlayTexture->load(); - mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), - Ogre::Image::Box(static_cast(originX), static_cast(originY), - static_cast(originX + mCellSize), static_cast(originY + mCellSize))); - - Ogre::Image backup; - std::vector data; - data.resize(mCellSize*mCellSize*4, 0); - backup.loadDynamicImage(&data[0], mCellSize, mCellSize, Ogre::PF_A8B8G8R8); - - localMapTexture->getBuffer()->blitToMemory(Ogre::Image::Box(0,0,mapWidth,mapHeight), backup.getPixelBox()); - - for (int x=0; x(originX + x), static_cast(originY + y), 0); - } - } - */ + requestOverlayTextureUpdate(originX, originY, mCellSize, mCellSize, localMapTexture, false, true); } void GlobalMap::clear() @@ -215,7 +306,6 @@ namespace MWRender assert(mOverlayImage->isDataContiguous()); } memset(mOverlayImage->data(), 0, mOverlayImage->getTotalSizeInBytes()); - mOverlayImage->dirty(); if (!mOverlayTexture) { @@ -224,9 +314,16 @@ namespace MWRender mOverlayTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mOverlayTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mOverlayTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - mOverlayTexture->setImage(mOverlayImage); mOverlayTexture->setResizeNonPowerOfTwoHint(false); + mOverlayTexture->setInternalFormat(GL_RGBA); + mOverlayTexture->setTextureSize(mWidth, mHeight); } + + mPendingImageDest.clear(); + + // just push a Camera to clear the FBO, instead of setImage()/dirty() + // easier, since we don't need to worry about synchronizing access :) + requestOverlayTextureUpdate(0, 0, mWidth, mHeight, osg::ref_ptr(), true, false); } void GlobalMap::write(ESM::GlobalMap& map) @@ -257,12 +354,16 @@ namespace MWRender struct Box { - int mLeft, mRight, mTop, mBottom; + int mLeft, mTop, mRight, mBottom; - Box(int left, int right, int top, int bottom) - : mLeft(left), mRight(right), mTop(top), mBottom(bottom) + Box(int left, int top, int right, int bottom) + : mLeft(left), mTop(top), mRight(right), mBottom(bottom) { } + bool operator == (const Box& other) + { + return mLeft == other.mLeft && mTop == other.mTop && mRight == other.mRight && mBottom == other.mBottom; + } }; void GlobalMap::read(ESM::GlobalMap& map) @@ -336,20 +437,29 @@ namespace MWRender std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), std::min(mHeight, mHeight + bottomDiff * cellImageSizeDst)); - if (srcBox.mLeft == destBox.mLeft && srcBox.mRight == destBox.mRight - && srcBox.mTop == destBox.mTop && srcBox.mBottom == destBox.mBottom - && imageWidth == mWidth && imageHeight == mHeight) + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(image); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + + if (srcBox == destBox && imageWidth == mWidth && imageHeight == mHeight) { mOverlayImage->copySubImage(0, 0, 0, image); + + requestOverlayTextureUpdate(0, 0, mWidth, mHeight, texture, true, false); } else { - // TODO: // Dimensions don't match. This could mean a changed map region, or a changed map resolution. - // In the latter case, we'll want to use filtering. - // Create a RTT Camera and draw the image onto mOverlayImage in the next frame? + // In the latter case, we'll want filtering. + // Create a RTT Camera and draw the image onto mOverlayImage in the next frame. + requestOverlayTextureUpdate(destBox.mLeft, destBox.mTop, destBox.mRight-destBox.mLeft, destBox.mBottom-destBox.mTop, texture, true, true, + srcBox.mLeft/float(imageWidth), srcBox.mTop/float(imageHeight), + srcBox.mRight/float(imageWidth), srcBox.mBottom/float(imageHeight)); } - mOverlayImage->dirty(); } osg::ref_ptr GlobalMap::getBaseTexture() @@ -361,4 +471,37 @@ namespace MWRender { return mOverlayTexture; } + + void GlobalMap::markForRemoval(osg::Camera *camera) + { + CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), camera); + if (found == mActiveCameras.end()) + { + std::cerr << "GlobalMap trying to remove an inactive camera" << std::endl; + return; + } + mActiveCameras.erase(found); + mCamerasPendingRemoval.push_back(camera); + } + + void GlobalMap::cleanupCameras() + { + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + mRoot->removeChild(*it); + mCamerasPendingRemoval.clear(); + + for (ImageDestVector::iterator it = mPendingImageDest.begin(); it != mPendingImageDest.end();) + { + ImageDest& imageDest = *it; + if (--imageDest.mFramesUntilDone > 0) + { + ++it; + continue; + } + + mOverlayImage->copySubImage(imageDest.mX, imageDest.mY, 0, imageDest.mImage); + + it = mPendingImageDest.erase(it); + } + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 9ca7ed5b4a..7adb8218a7 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -10,6 +10,8 @@ namespace osg { class Texture2D; class Image; + class Group; + class Camera; } namespace Loading @@ -28,7 +30,7 @@ namespace MWRender class GlobalMap { public: - GlobalMap(); + GlobalMap(osg::Group* root); ~GlobalMap(); void render(Loading::Listener* loadingListener); @@ -42,11 +44,23 @@ namespace MWRender void cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY); - void exploreCell (int cellX, int cellY); + void exploreCell (int cellX, int cellY, osg::ref_ptr localMapTexture); /// Clears the overlay void clear(); + /** + * Removes cameras that have already been rendered. Should be called every frame to ensure that + * we do not render the same map more than once. Note, this cleanup is difficult to implement in an + * automated fashion, since we can't alter the scene graph structure from within an update callback. + */ + void cleanupCameras(); + + /** + * Mark a camera for cleanup in the next update. For internal use only. + */ + void markForRemoval(osg::Camera* camera); + void write (ESM::GlobalMap& map); void read (ESM::GlobalMap& map); @@ -54,13 +68,48 @@ namespace MWRender osg::ref_ptr getOverlayTexture(); private: + /** + * Request rendering a 2d quad onto mOverlayTexture. + * x, y, width and height are the destination coordinates. + * @param cpuCopy copy the resulting render onto mOverlayImage as well? + */ + void requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, + float srcLeft = 0.f, float srcTop = 0.f, float srcRight = 1.f, float srcBottom = 1.f); + int mCellSize; + osg::ref_ptr mRoot; + + typedef std::vector > CameraVector; + CameraVector mActiveCameras; + + CameraVector mCamerasPendingRemoval; + + struct ImageDest + { + ImageDest() + : mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. + { + } + + osg::ref_ptr mImage; + int mX, mY; + int mFramesUntilDone; + }; + + typedef std::vector ImageDestVector; + + ImageDestVector mPendingImageDest; + std::vector< std::pair > mExploredCells; osg::ref_ptr mBaseTexture; + + // GPU copy of overlay + // Note, uploads are pushed through a Camera, instead of through mOverlayImage osg::ref_ptr mOverlayTexture; + // CPU copy of overlay osg::ref_ptr mOverlayImage; int mWidth; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 495ea2d1d4..edc88ac559 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -480,6 +480,11 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi return alpha < 200; } +osg::Group* LocalMap::getRoot() +{ + return mRoot; +} + void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, float& u, float& v, int& x, int& y, osg::Vec3f& direction) { diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index c319b7ce7f..72ee0354ed 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -101,6 +101,8 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + osg::Group* getRoot(); + private: osg::ref_ptr mViewer; From 7e715decd30948beffbc60d5089337465a123c07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 02:26:58 +0200 Subject: [PATCH 0325/1812] Color fix --- apps/openmw/mwrender/globalmap.cpp | 4 ++++ apps/openmw/mwrender/sky.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 1e30eb0fcb..bcf9e74bf8 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -47,6 +47,10 @@ namespace texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-topTexCoord)); texcoords->push_back(osg::Vec2f(rightTexCoord, 1.f-bottomTexCoord)); + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d667611954..5b01edb164 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -75,6 +75,10 @@ namespace texcoords->push_back(osg::Vec2f(1, 1)); texcoords->push_back(osg::Vec2f(1, 0)); + osg::ref_ptr colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f)); + geom->setColorArray(colors, osg::Array::BIND_OVERALL); + for (int i=0; isetTexCoordArray(i, texcoords, osg::Array::BIND_PER_VERTEX); From b75d993da4635d2ee4f11b70738c75e15506cfec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 14:25:47 +0200 Subject: [PATCH 0326/1812] Fix for BULLET_DYNAMICS_LIBRARY cmake leftover --- cmake/FindBullet.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 5204c00ce8..6d5c517afd 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -66,7 +66,8 @@ _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG BulletMath_Debug BulletMath_ # all listed variables are TRUE include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG - BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY + #BULLET_DYNAMICS_LIBRARY + BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY BULLET_INCLUDE_DIR) set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR}) From 261ed1f4e5119f0d30d855393149143d32df8c45 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 20:31:26 +0200 Subject: [PATCH 0327/1812] Revert "Enable culling for particle emitters & programs" This reverts commit 8b206e0aeda6feee2470a61aa363a79dbe3ba25f. --- components/nifosg/nifloader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5fdf964c4a..219f6e194a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -682,7 +682,6 @@ namespace NifOsg attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - program->setCullingActive(true); for (; !affectors.empty(); affectors = affectors->extra) { if (affectors->recType == Nif::RC_NiParticleGrowFade) @@ -829,7 +828,6 @@ namespace NifOsg osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - emitter->setCullingActive(true); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -870,7 +868,6 @@ namespace NifOsg // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; - updater->setCullingActive(true); updater->addParticleSystem(partsys); parentNode->addChild(updater); From af2f26d04d124395903265c6a1dfb2a14fd4b89f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 20:45:27 +0200 Subject: [PATCH 0328/1812] Particle fixes --- apps/openmw/mwmechanics/character.cpp | 8 ++------ apps/openmw/mwrender/animation.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7588a3287b..9feb831c98 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1172,14 +1172,10 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->hasNode("Left Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); - else + if (mAnimation->hasNode("Bip01 L Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->hasNode("Right Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); - else + if (mAnimation->hasNode("Bip01 R Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); switch(effectentry.mRange) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 91f4f766eb..327f59df8f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1042,11 +1042,11 @@ namespace MWRender parentNode = mObjectRoot->asGroup(); else { - SceneUtil::FindByNameVisitor visitor(bonename); - mObjectRoot->accept(visitor); - if (!visitor.mFoundNode) + NodeMap::iterator found = mNodeMap.find(Misc::StringUtils::lowerCase(bonename)); + if (found == mNodeMap.end()) throw std::runtime_error("Can't find bone " + bonename); - parentNode = visitor.mFoundNode; + + parentNode = found->second; } osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); params.mObjects = PartHolderPtr(new PartHolder(node)); From 668d365ef9a5d2a3366c4cbc7a10510dd0b2b199 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 21:47:43 +0200 Subject: [PATCH 0329/1812] MorphGeometry copy fix --- components/sceneutil/clone.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 237417974e..0131adc89a 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -51,7 +51,9 @@ namespace SceneUtil if (dynamic_cast(drawable) || dynamic_cast(drawable)) { - osg::Drawable* cloned = osg::clone(drawable, *this); + osg::CopyOp copyop = *this; + copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); + osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); return cloned; From 5c7ecb9c1d93cf2290fcca025aa5c06a1637d563 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 23:38:31 +0200 Subject: [PATCH 0330/1812] string::compare exception fix --- apps/openmw/mwrender/animation.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 327f59df8f..fed96f213a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -421,10 +421,14 @@ namespace MWRender size_t off = groupname.size()+2; size_t len = evt.size() - off; - if(evt.compare(off, len, "loop start") == 0) - state.mLoopStartTime = key->first; - else if(evt.compare(off, len, "loop stop") == 0) - state.mLoopStopTime = key->first; + if(evt.compare(0, groupname.size(), groupname) == 0 && + evt.compare(groupname.size(), 2, ": ") == 0) + { + if(evt.compare(off, len, "loop start") == 0) + state.mLoopStartTime = key->first; + else if(evt.compare(off, len, "loop stop") == 0) + state.mLoopStopTime = key->first; + } if (mTextKeyListener) mTextKeyListener->handleTextKey(groupname, key, map); From a56d0e9cc3d7e82de78ffeab7b775c6a2d6efa82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 May 2015 23:39:52 +0200 Subject: [PATCH 0331/1812] ControllerVisitor fix --- components/sceneutil/controller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 6beb1bc80e..4b51485f20 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -90,6 +90,8 @@ namespace SceneUtil if (Controller* ctrl = dynamic_cast(callback)) visit(geode, *ctrl); } + + apply(static_cast(geode)); } AssignControllerSourcesVisitor::AssignControllerSourcesVisitor() From 6231cd8557079eb8951456b0baadb2e153685070 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 00:59:34 +0200 Subject: [PATCH 0332/1812] RigGeometry clone fix --- components/sceneutil/clone.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 0131adc89a..36c5c02a16 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -48,8 +48,7 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable) - || dynamic_cast(drawable)) + if (dynamic_cast(drawable)) { osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); @@ -58,6 +57,11 @@ namespace SceneUtil cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); return cloned; } + if (dynamic_cast(drawable)) + { + return osg::clone(drawable, *this); + } + return osg::CopyOp::operator()(drawable); } From fd50be0fb8787c04901c1d504d86ebe67efc5c82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:00:24 +0200 Subject: [PATCH 0333/1812] Restore various gameplay --- apps/openmw/mwmechanics/aiwander.cpp | 11 ++---- apps/openmw/mwmechanics/character.cpp | 24 +++---------- apps/openmw/mwmechanics/combat.cpp | 23 +++++++------ .../mwmechanics/mechanicsmanagerimp.cpp | 34 +++++++++---------- apps/openmw/mwmechanics/spellcasting.cpp | 17 +++++----- apps/openmw/mwmechanics/summoning.cpp | 6 ++-- apps/openmw/mwworld/refdata.cpp | 17 ++++------ apps/openmw/mwworld/refdata.hpp | 12 +------ apps/openmw/mwworld/worldimp.cpp | 2 +- components/sceneutil/controller.hpp | 1 + 10 files changed, 57 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b4476de119..6593bbf89b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -473,14 +473,9 @@ namespace MWMechanics { Ogre::Vector3 dir = playerPos - actorPos; - Ogre::Radian faceAngle = Ogre::Math::ATan2(dir.x,dir.y); - Ogre::Radian actorAngle = actor.getRefData().getBaseNodeOld()->getOrientation().getRoll(); - // an attempt at reducing the turning animation glitch - if( Ogre::Math::Abs( faceAngle - actorAngle ) >= Ogre::Degree(5) ) // TODO: is there a better way? - { - targetAngle = faceAngle; - rotate = true; - } + float faceAngleRadians = std::atan2(dir.x, dir.y); + targetAngle = faceAngleRadians; + rotate = true; } if (greetingTimer >= GREETING_SHOULD_END) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9feb831c98..a8a6f74aab 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -816,26 +816,12 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); - else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release") + else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release" + // Make sure this key is actually for the RangeType we are casting. The flame atronach has + // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. + && evt.compare(off, len, mAttackType + " release") == 0) { - // Make sure this key is actually for the RangeType we are casting. The flame atronach has - // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type. - // FIXME: compare with mCurrentWeapon instead - const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell(); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - int range = 0; - if (evt.compare(off, len, "self release") == 0) - range = 0; - else if (evt.compare(off, len, "touch release") == 0) - range = 1; - else if (evt.compare(off, len, "target release") == 0) - range = 2; - if (effectentry.mRange == range) - { - MWBase::Environment::get().getWorld()->castSpell(mPtr); - } - std::cout << "current attack: " << mCurrentWeapon << std::endl; + MWBase::Environment::get().getWorld()->castSpell(mPtr); } else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 97dea73418..ee48d124f0 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,6 +1,6 @@ #include "combat.hpp" -#include +#include #include @@ -23,12 +23,9 @@ namespace { -Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 normal) +float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg::Vec3f& normal) { - return Ogre::Math::ATan2( - normal.dotProduct( v1.crossProduct(v2) ), - v1.dotProduct(v2) - ); + return std::atan2((normal * (v1 ^ v2)), (v1 * v2)); } bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition) @@ -74,13 +71,19 @@ namespace MWMechanics if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name()) return false; - Ogre::Degree angle = signedAngle (Ogre::Vector3(attacker.getRefData().getPosition().pos) - Ogre::Vector3(blocker.getRefData().getPosition().pos), - blocker.getRefData().getBaseNodeOld()->getOrientation().yAxis(), Ogre::Vector3(0,0,1)); + if (!blocker.getRefData().getBaseNode()) + return false; // shouldn't happen + + float angleDegrees = osg::RadiansToDegrees( + signedAngleRadians ( + (attacker.getRefData().getPosition().asVec3() - blocker.getRefData().getPosition().asVec3()), + blocker.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0), + osg::Vec3f(0,0,1))); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (angle.valueDegrees() < gmst.find("fCombatBlockLeftAngle")->getFloat()) + if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->getFloat()) return false; - if (angle.valueDegrees() > gmst.find("fCombatBlockRightAngle")->getFloat()) + if (angleDegrees > gmst.find("fCombatBlockRightAngle")->getFloat()) return false; MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 72a68e96b9..0ae9395c5d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,6 +1,8 @@ - #include "mechanicsmanagerimp.hpp" -#include "npcstats.hpp" + +#include + +#include #include @@ -20,12 +22,9 @@ #include "../mwmechanics/aicombat.hpp" #include "../mwmechanics/aipursue.hpp" -#include - #include "spellcasting.hpp" #include "autocalcspell.hpp" - -#include +#include "npcstats.hpp" namespace { @@ -1332,8 +1331,6 @@ namespace MWMechanics bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { - return false; - if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; @@ -1369,9 +1366,9 @@ namespace MWMechanics static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->getFloat(); - Ogre::Vector3 pos1 (ptr.getRefData().getPosition().pos); - Ogre::Vector3 pos2 (observer.getRefData().getPosition().pos); - float distTerm = fSneakDistBase + fSneakDistMult * pos1.distance(pos2); + osg::Vec3f pos1 (ptr.getRefData().getPosition().asVec3()); + osg::Vec3f pos2 (observer.getRefData().getPosition().asVec3()); + float distTerm = fSneakDistBase + fSneakDistMult * (pos1 - pos2).length(); float chameleon = stats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude(); float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility; @@ -1388,12 +1385,15 @@ namespace MWMechanics static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); static float fSneakViewMult = store.find("fSneakViewMult")->getFloat(); float y = 0; - Ogre::Vector3 vec = pos1 - pos2; - Ogre::Radian angle = observer.getRefData().getBaseNodeOld()->getOrientation().yAxis().angleBetween(vec); - if (angle < Ogre::Degree(90)) - y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; - else - y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; + osg::Vec3f vec = pos1 - pos2; + if (observer.getRefData().getBaseNode()) + { + float angleRadians = std::acos((observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)) * vec); + if (angleRadians < osg::DegreesToRadians(90.f)) + y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; + else + y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; + } float target = x - y; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ff3d2fcebc..8965d3b0d5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,7 +19,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "magiceffects.hpp" #include "npcstats.hpp" @@ -418,9 +418,9 @@ namespace MWMechanics absorbed = (Misc::Rng::roll0to99() < absorb); if (absorbed) { - //const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - // "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); // Magicka is increased by cost of spell DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); @@ -466,9 +466,9 @@ namespace MWMechanics bool isReflected = (Misc::Rng::roll0to99() < reflect); if (isReflected) { - //const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); - //MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - // "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); + const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + reflectStatic->mModel, ESM::MagicEffect::Reflect, false, ""); reflectedEffects.mList.push_back(*effectIt); magnitudeMult = 0; } @@ -565,7 +565,7 @@ namespace MWMechanics } // Add VFX - /*const ESM::Static* castStatic; + const ESM::Static* castStatic; if (!magicEffect->mHit.empty()) castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); else @@ -577,7 +577,6 @@ namespace MWMechanics MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); - */ } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 221c672671..4140fd3c0f 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -12,7 +12,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/inventorystore.hpp" -//#include "../mwrender/animation.hpp" +#include "../mwrender/animation.hpp" #include "creaturestats.hpp" #include "aifollow.hpp" @@ -143,9 +143,8 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); int creatureActorId = summonedCreatureStats.getActorId(); - /*MWWorld::Ptr placed = */MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - /* MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) { @@ -154,7 +153,6 @@ namespace MWMechanics if (fx) anim->addEffect("meshes\\" + fx->mModel, -1, false); } - */ creatureMap.insert(std::make_pair(*it, creatureActorId)); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index b8ebf99d00..54860fc313 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -37,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mBase(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -48,7 +48,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mBase(0), mDeleted(false), mHasLocals (false), mEnabled (true), + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mBase(0), mDeleted(false), mHasLocals (false), + : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), @@ -71,7 +71,7 @@ namespace MWWorld } RefData::RefData (const RefData& refData) - : mBaseNode(0), mBase(0), mCustomData (0) + : mBaseNode(0), mCustomData (0) { try { @@ -125,19 +125,14 @@ namespace MWWorld {} } - Ogre::SceneNode* RefData::getBaseNodeOld() - { - return mBaseNode; - } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) { - mBase = base; + mBaseNode = base; } osg::PositionAttitudeTransform* RefData::getBaseNode() { - return mBase; + return mBaseNode; } int RefData::getCount() const diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index b5b1f15604..61055aa736 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,11 +7,6 @@ #include -namespace Ogre -{ - class SceneNode; -} - namespace osg { class PositionAttitudeTransform; @@ -34,8 +29,7 @@ namespace MWWorld class RefData { - Ogre::SceneNode* mBaseNode; - osg::PositionAttitudeTransform* mBase; + osg::PositionAttitudeTransform* mBaseNode; MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, @@ -81,10 +75,6 @@ namespace MWWorld RefData& operator= (const RefData& refData); - /// Return OGRE base node (can be a null pointer). - /// obsolete - Ogre::SceneNode* getBaseNodeOld(); - /// Return base node (can be a null pointer). osg::PositionAttitudeTransform* getBaseNode(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 427a41d643..08617d0d6c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2385,7 +2385,7 @@ namespace MWWorld if(result.first == "") return true; */ - return false; + return true; } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 84fe6e8967..0ef1356e77 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -36,6 +36,7 @@ namespace SceneUtil { public: Controller(); + virtual ~Controller() {} bool hasInput() const; From b2fe21dd3b2bb1ce99ac9d21742eed7484614342 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:11:00 +0200 Subject: [PATCH 0334/1812] Minor cleanup --- apps/openmw/mwworld/scene.cpp | 1 - apps/openmw/mwworld/worldimp.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 939fbe873b..db1f9714ac 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -435,7 +435,6 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); } - //We need the ogre renderer and a scene node. Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dedfebdf22..b642a1ba77 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -8,7 +8,6 @@ #include "ptr.hpp" #include "scene.hpp" #include "esmstore.hpp" -//#include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" From cc3bfe2bb216412fe7e5e672bb2e2ca6b0c6af0d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:32:00 +0200 Subject: [PATCH 0335/1812] Restore collision tracker --- apps/openmw/mwphysics/physicssystem.cpp | 83 +++++++++++-------------- apps/openmw/mwphysics/physicssystem.hpp | 13 ++-- apps/openmw/mwworld/worldimp.cpp | 38 +++++------ 3 files changed, 58 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2bd88e6343..8e63fecfbe 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -231,8 +231,8 @@ namespace MWPhysics static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld - , std::map& collisionTracker - , std::map& standingCollisionTracker) + , std::map& collisionTracker + , std::map& standingCollisionTracker) { const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); @@ -333,13 +333,10 @@ namespace MWPhysics } else { - /* const btCollisionObject* standingOn = tracer.mHitObject; - if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) - { - collisionTracker[ptr.getRefData().getHandle()] = body->mName; - } - */ + const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + if (ptrHolder) + collisionTracker[ptr] = ptrHolder->getPtr(); } } else @@ -406,12 +403,9 @@ namespace MWPhysics && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; - /* - if (const OEngine::Physic::RigidBody* body = dynamic_cast(standingOn)) - { - standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; - } - */ + const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + if (ptrHolder) + standingCollisionTracker[ptr] = ptrHolder->getPtr(); if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); @@ -857,6 +851,22 @@ namespace MWPhysics } } + void PhysicsSystem::updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + CollisionMap::iterator found = map.find(old); + if (found != map.end()) + { + map[updated] = found->second; + map.erase(found); + } + + for (CollisionMap::iterator it = map.begin(); it != map.end(); ++it) + { + if (it->second == old) + it->second = updated; + } + } + void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { ObjectMap::iterator found = mObjects.find(old); @@ -876,6 +886,9 @@ namespace MWPhysics mActors.erase(foundActor); mActors.insert(std::make_pair(updated, actor)); } + + updateCollisionMapPtr(mCollisions, old, updated); + updateCollisionMapPtr(mStandingCollisions, old, updated); } Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) @@ -1058,62 +1071,40 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - /* - const std::string& actorHandle = actor.getRefData().getHandle(); - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mStandingCollisions.begin(); - it != mStandingCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { - if (it->first == actorHandle && it->second == objectHandle) + if (it->first == actor && it->second == object) return true; } - */ return false; } - void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const { - /* - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mStandingCollisions.begin(); - it != mStandingCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { - if (it->second == objectHandle) + if (it->second == object) out.push_back(it->first); } - */ } bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - /* - const std::string& actorHandle = actor.getRefData().getHandle(); - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mCollisions.begin(); - it != mCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) { - if (it->first == actorHandle && it->second == objectHandle) + if (it->first == actor && it->second == object) return true; } - */ return false; } - void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { - /* - const std::string& objectHandle = object.getRefData().getHandle(); - - for (std::map::const_iterator it = mCollisions.begin(); - it != mCollisions.end(); ++it) + for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) { - if (it->second == objectHandle) + if (it->second == object) out.push_back(it->first); } - */ } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 841085f479..2240a51196 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -109,14 +109,14 @@ namespace MWPhysics bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; /// Get the handle of all actors standing on \a object in this frame. - void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; /// Return true if \a actor has collided with \a object in this frame. /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; /// Get the handle of all actors colliding with \a object in this frame. - void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; bool toggleDebugRendering(); @@ -142,14 +142,15 @@ namespace MWPhysics bool mDebugDrawEnabled; - std::map handleToMesh; - // Tracks all movement collisions happening during a single frame. // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, // stepping up small objects, etc. - std::map mCollisions; // FIXME: reimplement + typedef std::map CollisionMap; + CollisionMap mCollisions; + CollisionMap mStandingCollisions; - std::map mStandingCollisions; // FIXME: reimplement + // replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value + void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated); PtrVelocityList mMovementQueue; PtrVelocityList mMovementResults; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 08617d0d6c..39b26c5d22 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2200,27 +2200,27 @@ namespace MWWorld bool World::getPlayerStandingOn (const MWWorld::Ptr& object) { - //MWWorld::Ptr player = getPlayerPtr(); - return 0;//mPhysics->isActorStandingOn(player, object); + MWWorld::Ptr player = getPlayerPtr(); + return mPhysics->isActorStandingOn(player, object); } bool World::getActorStandingOn (const MWWorld::Ptr& object) { - std::vector actors; - //mPhysics->getActorsStandingOn(object, actors); + std::vector actors; + mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) { - //MWWorld::Ptr player = getPlayerPtr(); - return 0;//mPhysics->isActorCollidingWith(player, object); + MWWorld::Ptr player = getPlayerPtr(); + return mPhysics->isActorCollidingWith(player, object); } bool World::getActorCollidingWith (const MWWorld::Ptr& object) { - std::vector actors; - //mPhysics->getActorsCollidingWith(object, actors); + std::vector actors; + mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } @@ -2229,15 +2229,11 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; - /* - std::vector actors; + std::vector actors; mPhysics->getActorsStandingOn(object, actors); - for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist - if (actor.isEmpty()) - continue; - + MWWorld::Ptr actor = *it; MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; @@ -2254,7 +2250,6 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } - */ } void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) @@ -2262,15 +2257,11 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; - /* - std::vector actors; + std::vector actors; mPhysics->getActorsCollidingWith(object, actors); - for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + for (std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - MWWorld::Ptr actor = searchPtrViaHandle(*it); // Collision events are from the last frame, actor might no longer exist - if (actor.isEmpty()) - continue; - + MWWorld::Ptr actor = *it; MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; @@ -2287,7 +2278,6 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->playSound3D(actor, "Health Damage", 1.0f, 1.0f); } } - */ } float World::getWindSpeed() From 988a9cad58b41abee8453424ea5071643f7799d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 01:41:38 +0200 Subject: [PATCH 0336/1812] getHitContact Head exception fix --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 11 +++-------- apps/openmw/mwrender/animation.hpp | 6 +----- apps/openmw/mwrender/characterpreview.cpp | 9 +++++++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a8a6f74aab..379025c9e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1158,10 +1158,10 @@ bool CharacterController::updateWeaponState() effect = store.get().find(effectentry.mEffectID); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->hasNode("Bip01 L Hand")) + if (mAnimation->getNode("Bip01 L Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->hasNode("Bip01 R Hand")) + if (mAnimation->getNode("Bip01 R Hand")) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); switch(effectentry.mRange) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fed96f213a..403f270d8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1136,19 +1136,14 @@ namespace MWRender return true; } - bool Animation::hasNode(const std::string &name) const - { - std::string lowerName = Misc::StringUtils::lowerCase(name); - return (mNodeMap.find(lowerName) != mNodeMap.end()); - } - const osg::Node* Animation::getNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); NodeMap::const_iterator found = mNodeMap.find(lowerName); if (found == mNodeMap.end()) - throw std::runtime_error("Can't find node " + name); - return found->second; + return NULL; + else + return found->second; } float Animation::AnimationTime::getValue(osg::NodeVisitor*) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d298fdff05..d1a1b01c67 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -367,11 +367,7 @@ public: /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(float duration); - /// Is there a node with the specified name? - /// @note The matching is case-insensitive. - bool hasNode(const std::string& name) const; - - /// Return a node with the specified name, throws an exception if the node is not found. + /// Return a node with the specified name, or NULL if not existing. /// @note The matching is case-insensitive. const osg::Node* getNode(const std::string& name) const; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 62c732051e..cdf99f0fc9 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -363,8 +363,13 @@ namespace MWRender mCamera->removeUpdateCallback(mUpdateCameraCallback); const osg::Node* head = mAnimation->getNode("Bip01 Head"); - mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); - mCamera->addUpdateCallback(mUpdateCameraCallback); + if (head) + { + mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); + mCamera->addUpdateCallback(mUpdateCameraCallback); + } + else + std::cerr << "Error: Bip01 Head node not found" << std::endl; } } From 0f8f19958a4abfd9ccaba6ff4f58e7bbc4e6c302 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 04:26:00 +0200 Subject: [PATCH 0337/1812] NifLoader: Fix empty StateSets being created in some cases --- components/nifosg/nifloader.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 219f6e194a..1f089f0c40 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1075,8 +1075,6 @@ namespace NifOsg static void handleProperty(const Nif::Property *property, osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { - osg::StateSet* stateset = node->getOrCreateStateSet(); - switch (property->recType) { case Nif::RC_NiStencilProperty: @@ -1095,6 +1093,7 @@ namespace NifOsg break; } + osg::StateSet* stateset = node->getOrCreateStateSet(); stateset->setAttribute(frontFace, osg::StateAttribute::ON); stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); @@ -1117,7 +1116,7 @@ namespace NifOsg osg::PolygonMode* mode = new osg::PolygonMode; mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL : osg::PolygonMode::LINE); - stateset->setAttributeAndModes(mode, osg::StateAttribute::ON); + node->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); break; } case Nif::RC_NiZBufferProperty: @@ -1126,7 +1125,7 @@ namespace NifOsg // VER_MW doesn't support a DepthFunction according to NifSkope osg::Depth* depth = new osg::Depth; depth->setWriteMask((zprop->flags>>1)&1); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + node->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); break; } // OSG groups the material properties that NIFs have separate, so we have to parse them all again when one changed @@ -1141,6 +1140,7 @@ namespace NifOsg { const Nif::NiAlphaProperty* alphaprop = static_cast(property); osg::BlendFunc* blendfunc = new osg::BlendFunc; + osg::StateSet* stateset = node->getOrCreateStateSet(); if (alphaprop->flags&1) { blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), @@ -1174,6 +1174,7 @@ namespace NifOsg case Nif::RC_NiTexturingProperty: { const Nif::NiTexturingProperty* texprop = static_cast(property); + osg::StateSet* stateset = node->getOrCreateStateSet(); for (int i=0; itextures[i].inUse) From 62ce2cc123fb0a50ec3471664f235823b89979fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 20:44:19 +0200 Subject: [PATCH 0338/1812] Minor cleanup --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87c3fabd46..3c3cd9f6bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,16 +133,10 @@ endif() # Platform specific if (WIN32) set(Boost_USE_STATIC_LIBS ON) - set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) -else (WIN32) - set(PLATFORM_INCLUDE_DIR "") -endif (WIN32) -if (MSVC10) - set(PLATFORM_INCLUDE_DIR "") endif() # Dependencies From a066b2430331e156f340e50f32dd56785d945df3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 01:07:43 +0200 Subject: [PATCH 0339/1812] Restore WeaponAnimation --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 51 ++++++++-------- apps/openmw/mwrender/camera.cpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 58 +++++++++++------- apps/openmw/mwrender/creatureanimation.hpp | 16 ++--- apps/openmw/mwrender/npcanimation.cpp | 49 +++++++++++---- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/weaponanimation.cpp | 69 ++++++++++------------ apps/openmw/mwrender/weaponanimation.hpp | 26 ++++---- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/defs.hpp | 2 + 14 files changed, 170 insertions(+), 120 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b4ecdd9567..2193f4ca0e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask - creatureanimation effectmanager util renderinginterface pathgrid rendermode + creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap # occlusionquery water shadows # ripplesimulation refraction diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index c0e2ade0f5..4d01f95295 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -22,6 +22,7 @@ namespace Ogre namespace osg { class Vec3f; + class Quat; } namespace Loading @@ -486,7 +487,7 @@ namespace MWBase float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0; + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 379025c9e6..5765d8b04d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -812,7 +812,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (evt.compare(off, len, "shoot attach") == 0) mAnimation->attachArrow(); else if (evt.compare(off, len, "shoot release") == 0) - {;}//mAnimation->releaseArrow(); + mAnimation->releaseArrow(); else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d1a1b01c67..86dd21df4b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,31 @@ public: EffectAnimationTime() : mTime(0) { } }; +/// @brief Detaches the node from its parent when the object goes out of scope. +class PartHolder +{ +public: + PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + ~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + + osg::ref_ptr getNode() + { + return mNode; + } + +private: + osg::ref_ptr mNode; +}; +typedef boost::shared_ptr PartHolderPtr; + class Animation { public: @@ -174,31 +199,6 @@ protected: osg::Vec3f mAccumulate; - /// @brief Detaches the node from its parent when the object goes out of scope. - class PartHolder - { - public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } - - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } - - osg::ref_ptr getNode() - { - return mNode; - } - - private: - osg::ref_ptr mNode; - }; - typedef boost::shared_ptr PartHolderPtr; - struct EffectParams { std::string mModelName; // Just here so we don't add the same effect twice @@ -378,6 +378,7 @@ public: virtual void setAlpha(float alpha) {} virtual void setPitchFactor(float factor) {} virtual void attachArrow() {} + virtual void releaseArrow() {} virtual void enableHeadAnimation(bool enable) {} // TODO: move outside of this class /// Makes this object glow, by placing a Light in its center. diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index a945a171ef..392f8978a0 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -361,7 +361,7 @@ namespace MWRender if(isFirstPerson()) { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); - mTrackingNode = mAnimation->getNode("Head"); + mTrackingNode = mAnimation->getNode("Camera"); } else { diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b653f4d300..b98b261791 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/world.hpp" @@ -52,7 +53,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const updateParts(); } - //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + mWeaponAnimationTime = boost::shared_ptr(new WeaponAnimationTime(this)); } void CreatureWeaponAnimation::showWeapons(bool showWeapon) @@ -122,35 +123,52 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - //else - // mAmmunition.setNull(); + else + mAmmunition.reset(); } - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); - /* - std::vector >::iterator ctrl(scene->mControllers.begin()); - for(;ctrl != scene->mControllers.end();++ctrl) - { - if(ctrl->getSource().isNull()) - { - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - ctrl->setSource(mWeaponAnimationTime); - else - ctrl->setSource(Ogre::SharedPtr(new NullAnimationTime())); - } - } - */ + boost::shared_ptr source; + + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + source = mWeaponAnimationTime; + else + source.reset(new NullAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); + node->accept(assignVisitor); } void CreatureWeaponAnimation::attachArrow() { - //WeaponAnimation::attachArrow(mPtr); + WeaponAnimation::attachArrow(mPtr); } void CreatureWeaponAnimation::releaseArrow() { - //WeaponAnimation::releaseArrow(mPtr); + WeaponAnimation::releaseArrow(mPtr); +} + +osg::Group *CreatureWeaponAnimation::getArrowBone() +{ + if (!mWeapon) + return NULL; + + SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); + mWeapon->getNode()->accept(findVisitor); + + return findVisitor.mFoundNode; +} + +osg::Node *CreatureWeaponAnimation::getWeaponNode() +{ + return mWeapon ? mWeapon->getNode().get() : NULL; +} + +Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() +{ + return mResourceSystem; } osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index ccb553d990..61d077df3b 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -22,7 +22,7 @@ namespace MWRender // For creatures with weapons and shields // Animation is already virtual anyway, so might as well make a separate class. // Most creatures don't need weapons/shields, so this will save some memory. - class CreatureWeaponAnimation : public Animation/*, public WeaponAnimation*/, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); @@ -39,6 +39,12 @@ namespace MWRender virtual void attachArrow(); virtual void releaseArrow(); + // WeaponAnimation + virtual osg::Group* getArrowBone(); + virtual osg::Node* getWeaponNode(); + virtual Resource::ResourceSystem* getResourceSystem(); + virtual void showWeapon(bool show) { showWeapons(show); } + virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } virtual osg::Vec3f runAnimation(float duration); @@ -46,12 +52,6 @@ namespace MWRender /// to indicate the facing orientation of the character. //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - //virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } - - // WeaponAnimation - //virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; } - //virtual void showWeapon(bool show) { showWeapons(show); } - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); private: PartHolderPtr mWeapon; @@ -59,7 +59,7 @@ namespace MWRender bool mShowWeapons; bool mShowCarriedLeft; - //Ogre::SharedPtr mWeaponAnimationTime; + boost::shared_ptr mWeaponAnimationTime; }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index aeff1f60ae..e9e3b7aefe 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,9 @@ #include + +#include // XXX + #include #include @@ -9,6 +12,7 @@ #include #include #include +#include #include // TextKeyMapHolder @@ -203,7 +207,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mNpc = mPtr.get()->mBase; mHeadAnimationTime = boost::shared_ptr(new HeadAnimationTime(mPtr)); - //mWeaponAnimationTime = Ogre::SharedPtr(new WeaponAnimationTime(this)); + mWeaponAnimationTime = boost::shared_ptr(new WeaponAnimationTime(this)); for(size_t i = 0;i < ESM::PRT_Count;i++) { @@ -333,7 +337,7 @@ void NpcAnimation::updateNpcBase() removeIndividualPart((ESM::PartReferenceType)i); updateParts(); - //mWeaponAnimationTime->updateStartTime(); + mWeaponAnimationTime->updateStartTime(); } void NpcAnimation::updateParts() @@ -585,7 +589,7 @@ void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) mFirstPersonOffset += offset; }*/ -Animation::PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) +PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); @@ -729,8 +733,8 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } } - //else if (type == ESM::PRT_Weapon) - // src = mWeaponAnimationTime; + else if (type == ESM::PRT_Weapon) + src = mWeaponAnimationTime; else src.reset(new NullAnimationTime); @@ -809,11 +813,11 @@ void NpcAnimation::showWeapons(bool showWeapon) MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); } - //else - //mAmmunition.setNull(); + else + mAmmunition.reset(); } } else @@ -853,6 +857,31 @@ void NpcAnimation::releaseArrow() WeaponAnimation::releaseArrow(mPtr); } +osg::Group* NpcAnimation::getArrowBone() +{ + PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; + if (!part) + return NULL; + + SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); + part->getNode()->accept(findVisitor); + + return findVisitor.mFoundNode; +} + +osg::Node* NpcAnimation::getWeaponNode() +{ + PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; + if (!part) + return NULL; + return part->getNode(); +} + +Resource::ResourceSystem* NpcAnimation::getResourceSystem() +{ + return mResourceSystem; +} + void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound) { // During first auto equip, we don't play any sounds. @@ -897,7 +926,7 @@ void NpcAnimation::enableHeadAnimation(bool enable) void NpcAnimation::setWeaponGroup(const std::string &group) { - //mWeaponAnimationTime-> + mWeaponAnimationTime->setGroup(group); } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index eda59f50c5..0f90bb2d72 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -95,7 +95,7 @@ private: //Ogre::Vector3 mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; - //Ogre::SharedPtr mWeaponAnimationTime; + boost::shared_ptr mWeaponAnimationTime; float mAlpha; bool mSoundsDisabled; @@ -157,6 +157,10 @@ public: virtual void attachArrow(); virtual void releaseArrow(); + virtual osg::Group* getArrowBone(); + virtual osg::Node* getWeaponNode(); + virtual Resource::ResourceSystem* getResourceSystem(); + // WeaponAnimation //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index d16afe3ce2..23a74fb95e 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -1,9 +1,7 @@ #include "weaponanimation.hpp" -#include -#include -#include -#include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -21,10 +19,11 @@ namespace MWRender { -float WeaponAnimationTime::getValue() const +float WeaponAnimationTime::getValue(osg::NodeVisitor*) { if (mWeaponGroup.empty()) return 0; + float current = mAnimation->getCurrentTime(mWeaponGroup); if (current == -1) return 0; @@ -42,6 +41,11 @@ void WeaponAnimationTime::updateStartTime() setGroup(mWeaponGroup); } +WeaponAnimation::WeaponAnimation() + : mPitchFactor(0) +{ +} + void WeaponAnimation::attachArrow(MWWorld::Ptr actor) { MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); @@ -63,8 +67,8 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) } else if (weaponType == ESM::Weapon::MarksmanBow || weaponType == ESM::Weapon::MarksmanCrossbow) { - NifOgre::ObjectScenePtr weapon = getWeapon(); - if (!weapon.get()) + osg::Group* parent = getArrowBone(); + if (!parent) return; MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); @@ -72,12 +76,9 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) return; std::string model = ammo->getClass().getModel(*ammo); - if (!weapon->mSkelBase) - throw std::runtime_error("Need a skeleton to attach the arrow to"); + osg::ref_ptr arrow = getResourceSystem()->getSceneManager()->createInstance(model, parent); - const std::string bonename = "ArrowBone"; - mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, bonename, bonename, weapon->mSkelBase->getParentSceneNode(), model); - configureAddedObject(mAmmunition, *ammo, MWWorld::InventoryStore::Slot_Ammunition); + mAmmunition = PartHolderPtr(new PartHolder(arrow)); } } @@ -91,8 +92,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) return; // The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise. - Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -102,18 +103,13 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) { // Thrown weapons get detached now - NifOgre::ObjectScenePtr objects = getWeapon(); - - Ogre::Vector3 launchPos(0,0,0); - if (objects->mSkelBase) - { - launchPos = objects->mSkelBase->getParentNode()->_getDerivedPosition(); - } - else if (objects->mEntities.size()) - { - objects->mEntities[0]->getParentNode()->needUpdate(true); - launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition(); - } + osg::Node* weaponNode = getWeaponNode(); + if (!weaponNode) + return; + osg::MatrixList mats = weaponNode->getWorldMatrices(); + if (mats.empty()) + return; + osg::Vec3f launchPos = mats[0].getTrans(); float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); @@ -133,19 +129,14 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (ammo == inv.end()) return; - if (!mAmmunition.get()) + if (!mAmmunition) return; - Ogre::Vector3 launchPos(0,0,0); - if (mAmmunition->mSkelBase) - { - launchPos = mAmmunition->mSkelBase->getParentNode()->_getDerivedPosition(); - } - else if (mAmmunition->mEntities.size()) - { - mAmmunition->mEntities[0]->getParentNode()->needUpdate(true); - launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition(); - } + osg::ref_ptr ammoNode = mAmmunition->getNode(); + osg::MatrixList mats = ammoNode->getWorldMatrices(); + if (mats.empty()) + return; + osg::Vec3f launchPos = mats[0].getTrans(); float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); @@ -154,10 +145,11 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed); inv.remove(*ammo, 1, actor); - mAmmunition.setNull(); + mAmmunition.reset(); } } +/* void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) { if (mPitchFactor == 0) @@ -179,5 +171,6 @@ void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) node = skel->getBone("Bip01 Spine1"); node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); } +*/ } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 4009628566..f46638ac85 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -1,15 +1,15 @@ #ifndef OPENMW_MWRENDER_WEAPONANIMATION_H #define OPENMW_MWRENDER_WEAPONANIMATION_H +#include + #include "../mwworld/ptr.hpp" +#include "animation.hpp" namespace MWRender { - class Animation; - - /* - class WeaponAnimationTime : public Ogre::ControllerValue + class WeaponAnimationTime : public SceneUtil::ControllerSource { private: Animation* mAnimation; @@ -20,27 +20,29 @@ namespace MWRender void setGroup(const std::string& group); void updateStartTime(); - virtual Ogre::Real getValue() const; - virtual void setValue(Ogre::Real value) - { } + virtual float getValue(osg::NodeVisitor* nv); }; - */ /// Handles attach & release of projectiles for ranged weapons class WeaponAnimation { public: - WeaponAnimation() : mPitchFactor(0) {} + WeaponAnimation(); virtual ~WeaponAnimation() {} /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void attachArrow(MWWorld::Ptr actor) {} + void attachArrow(MWWorld::Ptr actor); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor) {} + void releaseArrow(MWWorld::Ptr actor); protected: - //NifOgre::ObjectScenePtr mAmmunition; + PartHolderPtr mAmmunition; + + virtual osg::Group* getArrowBone() = 0; + virtual osg::Node* getWeaponNode() = 0; + virtual Resource::ResourceSystem* getResourceSystem() = 0; + //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 39b26c5d22..768177b16a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2757,7 +2757,7 @@ namespace MWWorld } void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) { #if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b642a1ba77..b1718f0304 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -574,7 +574,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); virtual const std::vector& getContentFiles() const; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 8ce76a8eac..9f1a935aea 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -38,6 +38,8 @@ enum RangeType struct Position { float pos[3]; + + // In radians float rot[3]; osg::Vec3f asVec3() const From 60f55997fd0942e663b041376814f5788e0e5afa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 02:26:31 +0200 Subject: [PATCH 0340/1812] Rotate first person meshes, sneak camera offset in first person --- apps/openmw/mwrender/animation.cpp | 17 ++- apps/openmw/mwrender/animation.hpp | 12 ++- apps/openmw/mwrender/camera.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 146 ++++++++++++++++++++++---- apps/openmw/mwrender/npcanimation.hpp | 12 ++- 5 files changed, 153 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 403f270d8c..b23981f816 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -603,7 +603,7 @@ namespace MWRender void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph - for (AnimSourceControllerMap::iterator it = mAnimSourceControllers.begin(); it != mAnimSourceControllers.end(); ++it) + for (ControllerMap::iterator it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it) { osg::Node* node = it->first; node->removeUpdateCallback(it->second); @@ -611,13 +611,8 @@ namespace MWRender // Should be no longer needed with OSG 3.4 it->second->setNestedCallback(NULL); } - if (mResetAccumRootCallback && mAccumRoot) - { - mAccumRoot->removeUpdateCallback(mResetAccumRootCallback); - // Should be no longer needed with OSG 3.4 - mResetAccumRootCallback->setNestedCallback(NULL); - } - mAnimSourceControllers.clear(); + + mActiveControllers.clear(); mAccumCtrl = NULL; @@ -647,7 +642,7 @@ namespace MWRender osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); - mAnimSourceControllers[node] = it->second; + mActiveControllers.insert(std::make_pair(node, it->second)); if (grp == 0 && node == mAccumRoot) { @@ -660,10 +655,12 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } mAccumRoot->addUpdateCallback(mResetAccumRootCallback); + mActiveControllers.insert(std::make_pair(mAccumRoot, mResetAccumRootCallback)); } } } } + addControllers(); } void Animation::changeGroups(const std::string &groupname, int groups) @@ -893,7 +890,7 @@ namespace MWRender mObjectRoot = NULL; mNodeMap.clear(); - mAnimSourceControllers.clear(); + mActiveControllers.clear(); mAccumRoot = NULL; mAccumCtrl = NULL; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 86dd21df4b..e30f2b0828 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -182,10 +182,10 @@ protected: // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system osg::ref_ptr mResetAccumRootCallback; - // Keep track of keyframe controllers from external files that we added to our scene graph. + // Keep track of controllers that we added to our scene graph. // We may need to rebuild these controllers when the active animation groups / sources change. - typedef std::map, osg::ref_ptr > AnimSourceControllerMap; - AnimSourceControllerMap mAnimSourceControllers; + typedef std::multimap, osg::ref_ptr > ControllerMap; + ControllerMap mActiveControllers; boost::shared_ptr mAnimationTimePtr[sNumGroups]; @@ -256,6 +256,12 @@ protected: void clearAnimSources(); + /** + * Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers + * so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering. + */ + virtual void addControllers() {} + osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 392f8978a0..bb47245554 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -250,7 +250,7 @@ namespace MWRender void Camera::setSneakOffset(float offset) { - // TODO: implement + mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset)); } float Camera::getYaw() diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e9e3b7aefe..598e2fba9c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,9 +1,7 @@ #include "npcanimation.hpp" #include - - -#include // XXX +#include #include @@ -74,6 +72,100 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { +/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. +/// The pitch is then applied on top of that orientation. +/// @note Must be set on a MatrixTransform. +class RotateController : public osg::NodeCallback +{ +public: + RotateController(osg::Node* relativeTo, osg::Vec3f axis) + : mRotate(0.f) + , mAxis(axis) + , mRelativeTo(relativeTo) + { + + } + + void setRotate(float rotate) + { + mRotate = rotate; + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (mRotate == 0.f) + return; + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + osg::Quat worldOrient = getWorldOrientation(node); + + osg::Quat rotate (mRotate, mAxis); + osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + matrix.setRotate(orient); + + transform->setMatrix(matrix); + + traverse(node,nv); + } + + osg::Quat getWorldOrientation(osg::Node* node) + { + // this could be optimized later, we just need the world orientation, not the full matrix + osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); + osg::Quat worldOrient; + if (worldMats.size()) + { + osg::Matrixf worldMat = worldMats[0]; + worldOrient = worldMat.getRotate(); + } + return worldOrient; + } + +protected: + float mRotate; + osg::Vec3f mAxis; + osg::ref_ptr mRelativeTo; +}; + +/// Subclass RotateController to add a Z-offset for sneaking in first person mode. +/// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. +/// @note Must be set on a MatrixTransform. +class NeckController : public RotateController +{ +public: + NeckController(osg::Node* relativeTo) + : RotateController(relativeTo, osg::Vec3f(-1,0,0)) + { + } + + void setOffset(osg::Vec3f offset) + { + mOffset = offset; + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + + osg::Quat worldOrient = getWorldOrientation(node); + osg::Quat rotate (mRotate, mAxis); + osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + + matrix.setRotate(orient); + matrix.setTrans(matrix.getTrans() + worldOrient.inverse() * mOffset); + + transform->setMatrix(matrix); + + traverse(node,nv); + } + +private: + osg::Vec3f mOffset; +}; + +// -------------------------------------------------------------------------------------------------------------- + HeadAnimationTime::HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference), mTalkStart(0), mTalkStop(0), mBlinkStart(0), mBlinkStop(0), mEnabled(true), mValue(0) { @@ -150,6 +242,8 @@ void HeadAnimationTime::setBlinkStop(float value) mBlinkStop = value; } +// ---------------------------------------------------- + static NpcAnimation::PartBoneMap createPartListMap() { NpcAnimation::PartBoneMap result; @@ -196,7 +290,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), - //mFirstPersonOffset(0.f, 0.f, 0.f), mNpcType(Type_Normal), mVisibilityFlags(visibilityFlags), mAlpha(1.f), @@ -583,11 +676,6 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); } -/* -void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) -{ - mFirstPersonOffset += offset; -}*/ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { @@ -605,21 +693,17 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mHeadAnimationTime->update(timepassed); + if (mFirstPersonNeckController) + { + mFirstPersonNeckController->setRotate(mPtr.getRefData().getPosition().rot[0]); + mFirstPersonNeckController->setOffset(mFirstPersonOffset); + } + /* if (mSkelBase) { Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) - { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else + if(mViewMode != VM_FirstPerson) { // In third person mode we may still need pitch for ranged weapon targeting pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); @@ -629,7 +713,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); } } - mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. */ return ret; @@ -792,6 +875,22 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) + { + osg::Node* node = found->second; + mFirstPersonNeckController = new NeckController(mObjectRoot.get()); + node->addUpdateCallback(mFirstPersonNeckController); + mActiveControllers.insert(std::make_pair(node, mFirstPersonNeckController)); + } + } +} + void NpcAnimation::showWeapons(bool showWeapon) { mShowWeapons = showWeapon; @@ -947,6 +1046,11 @@ void NpcAnimation::setVampire(bool vampire) } } +void NpcAnimation::setFirstPersonOffset(const osg::Vec3f &offset) +{ + mFirstPersonOffset = offset; +} + void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) { Animation::updatePtr(updated); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 0f90bb2d72..28ae43144b 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -48,6 +48,8 @@ public: virtual float getValue(osg::NodeVisitor* nv); }; +class NeckController; + class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: @@ -92,7 +94,7 @@ private: int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; - //Ogre::Vector3 mFirstPersonOffset; + osg::Vec3f mFirstPersonOffset; boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; @@ -119,6 +121,11 @@ private: //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); + osg::ref_ptr mFirstPersonNeckController; + +protected: + virtual void addControllers(); + public: /** * @param ptr @@ -186,6 +193,9 @@ public: virtual void setVampire(bool vampire); + /// Set a translation offset (in object root space) to apply to meshes when in first person mode. + void setFirstPersonOffset(const osg::Vec3f& offset); + virtual void updatePtr(const MWWorld::Ptr& updated); }; From cc9b7638913ee0a5494a27af2ff7669f3ed451aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 17:20:49 +0200 Subject: [PATCH 0341/1812] Fix for StartScript regression (Fixes #2590) --- apps/openmw/mwworld/store.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d6aeeb51ed..ba8be733a0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -366,6 +366,19 @@ namespace MWWorld inserted.first->second = scpt; } + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } + template <> class Store : public StoreBase { From d05d7f51d9bc581581ce2d88ebec9ab3ca085e4e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:20:13 +0200 Subject: [PATCH 0342/1812] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c19c57eb0..95035e85e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 36) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index f62800e1fd..833d9b282a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.36.0 +* Version: 0.36.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From e8e3407062caad86c3e0c9dc3af0ae7ad7921434 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:21:21 +0200 Subject: [PATCH 0343/1812] updated changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466c2ef253..b2e7dc25c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.36.1 +------ + + Bug #2590: Start scripts not added correctly + 0.36.0 ------ From 71bafcb52bbf590f2a853ec43059ec3e787e2ea7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 18:04:14 +0200 Subject: [PATCH 0344/1812] Restore head tracking --- apps/openmw/mwmechanics/actors.cpp | 30 ++++----- apps/openmw/mwmechanics/character.cpp | 79 +++++++++++++---------- apps/openmw/mwphysics/physicssystem.cpp | 3 +- apps/openmw/mwrender/animation.hpp | 5 ++ apps/openmw/mwrender/npcanimation.cpp | 83 ++++++++++++++++++------- apps/openmw/mwrender/npcanimation.hpp | 14 +++-- 6 files changed, 135 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3333511d3f..84e97487a2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,15 +1,12 @@ - #include "actors.hpp" #include -#include -#include +#include #include #include "../mwworld/esmstore.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" @@ -20,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwrender/animation.hpp" @@ -27,14 +25,9 @@ #include "creaturestats.hpp" #include "movement.hpp" #include "character.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" - #include "aicombat.hpp" #include "aifollow.hpp" #include "aipursue.hpp" - #include "actor.hpp" #include "summoning.hpp" #include "combat.hpp" @@ -274,7 +267,6 @@ namespace MWMechanics void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance) { - /* static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get() .find("fMaxHeadTrackDistance")->getFloat(); static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get() @@ -286,7 +278,7 @@ namespace MWMechanics const ESM::Position& actor1Pos = actor.getRefData().getPosition(); const ESM::Position& actor2Pos = targetActor.getRefData().getPosition(); - float sqrDist = Ogre::Vector3(actor1Pos.pos).squaredDistance(Ogre::Vector3(actor2Pos.pos)); + float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2(); if (sqrDist > maxDistance*maxDistance) return; @@ -294,12 +286,17 @@ namespace MWMechanics if (targetActor.getClass().getCreatureStats(targetActor).isDead()) return; + if (!actor.getRefData().getBaseNode()) + return; + // stop tracking when target is behind the actor - Ogre::Vector3 actorDirection (actor.getRefData().getBaseNode()->getOrientation().yAxis()); - Ogre::Vector3 targetDirection (Ogre::Vector3(actor2Pos.pos) - Ogre::Vector3(actor1Pos.pos)); - actorDirection.z = 0; - targetDirection.z = 0; - if (actorDirection.angleBetween(targetDirection) < Ogre::Degree(90) + osg::Vec3f actorDirection = actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); + osg::Vec3f targetDirection (actor2Pos.asVec3() - actor1Pos.asVec3()); + actorDirection.z() = 0; + targetDirection.z() = 0; + actorDirection.normalize(); + targetDirection.normalize(); + if (std::acos(actorDirection * targetDirection) < osg::DegreesToRadians(90.f) && sqrDist <= sqrHeadTrackDistance && MWBase::Environment::get().getWorld()->getLOS(actor, targetActor) // check LOS and awareness last as it's the most expensive function && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(targetActor, actor)) @@ -307,7 +304,6 @@ namespace MWMechanics sqrHeadTrackDistance = sqrDist; headTrackTarget = targetActor; } - */ } void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5765d8b04d..354ca998c0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,8 @@ #include +#include + #include "movement.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -46,12 +48,12 @@ namespace { // Wraps a value to (-PI, PI] -void wrap(Ogre::Radian& rad) +void wrap(float& rad) { - if (rad.valueRadians()>0) - rad = Ogre::Radian(std::fmod(rad.valueRadians()+Ogre::Math::PI, 2.0f*Ogre::Math::PI)-Ogre::Math::PI); + if (rad>0) + rad = std::fmod(rad+osg::PI, 2.0f*osg::PI)-osg::PI; else - rad = Ogre::Radian(std::fmod(rad.valueRadians()-Ogre::Math::PI, 2.0f*Ogre::Math::PI)+Ogre::Math::PI); + rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; } std::string getBestAttack (const ESM::Weapon* weapon) @@ -2034,50 +2036,61 @@ void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) void CharacterController::updateHeadTracking(float duration) { - /* - Ogre::Node* head = mAnimation->getNode("Bip01 Head"); + const osg::Node* head = mAnimation->getNode("Bip01 Head"); if (!head) return; - Ogre::Radian zAngle (0.f); - Ogre::Radian xAngle (0.f); + + float zAngleRadians = 0.f; + float xAngleRadians = 0.f; + if (!mHeadTrackTarget.isEmpty()) { - Ogre::Vector3 headPos = mPtr.getRefData().getBaseNode()->convertLocalToWorldPosition(head->_getDerivedPosition()); - Ogre::Vector3 targetPos (mHeadTrackTarget.getRefData().getPosition().pos); + osg::MatrixList mats = head->getWorldMatrices(); + if (mats.empty()) + return; + osg::Matrixf mat = mats[0]; + osg::Vec3f headPos = mat.getTrans(); + + osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3()); if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { - Ogre::Node* targetHead = anim->getNode("Head"); - if (!targetHead) - targetHead = anim->getNode("Bip01 Head"); - if (targetHead) - targetPos = mHeadTrackTarget.getRefData().getBaseNode()->convertLocalToWorldPosition( - targetHead->_getDerivedPosition()); + const osg::Node* node = anim->getNode("Head"); + if (node == NULL) + node = anim->getNode("Bip01 Head"); + if (node != NULL) + { + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + targetPos = mats[0].getTrans(); + } } - Ogre::Vector3 direction = targetPos - headPos; - direction.normalise(); + osg::Vec3f direction = targetPos - headPos; + direction.normalize(); - const Ogre::Vector3 actorDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); + if (!mPtr.getRefData().getBaseNode()) + return; + const osg::Vec3f actorDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); - zAngle = Ogre::Math::ATan2(direction.x,direction.y) - - Ogre::Math::ATan2(actorDirection.x, actorDirection.y); - xAngle = -Ogre::Math::ASin(direction.z); - wrap(zAngle); - wrap(xAngle); - xAngle = Ogre::Degree(std::min(xAngle.valueDegrees(), 40.f)); - xAngle = Ogre::Degree(std::max(xAngle.valueDegrees(), -40.f)); - zAngle = Ogre::Degree(std::min(zAngle.valueDegrees(), 30.f)); - zAngle = Ogre::Degree(std::max(zAngle.valueDegrees(), -30.f)); + zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y()); + xAngleRadians = -std::asin(direction.z()); + wrap(zAngleRadians); + wrap(xAngleRadians); + + xAngleRadians = std::min(xAngleRadians, osg::DegreesToRadians(40.f)); + xAngleRadians = std::max(xAngleRadians, osg::DegreesToRadians(-40.f)); + zAngleRadians = std::min(zAngleRadians, osg::DegreesToRadians(30.f)); + zAngleRadians = std::max(zAngleRadians, osg::DegreesToRadians(-30.f)); } + float factor = duration*5; factor = std::min(factor, 1.f); - xAngle = (1.f-factor) * mAnimation->getHeadPitch() + factor * (-xAngle); - zAngle = (1.f-factor) * mAnimation->getHeadYaw() + factor * (-zAngle); + xAngleRadians = (1.f-factor) * mAnimation->getHeadPitch() + factor * (-xAngleRadians); + zAngleRadians = (1.f-factor) * mAnimation->getHeadYaw() + factor * (-zAngleRadians); - mAnimation->setHeadPitch(xAngle); - mAnimation->setHeadYaw(zAngle); - */ + mAnimation->setHeadPitch(xAngleRadians); + mAnimation->setHeadYaw(zAngleRadians); } } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8e63fecfbe..d36aded241 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -59,8 +59,9 @@ namespace MWPhysics class MovementSolver { private: - static float getSlope(const osg::Vec3f &normal) + static float getSlope(osg::Vec3f normal) { + normal.normalize(); return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e30f2b0828..bd864c9361 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -391,6 +391,11 @@ public: /// @param effect Controls the radius and intensity of the light. virtual void setLightEffect(float effect) {} + virtual void setHeadPitch(float pitchRadians) {} + virtual void setHeadYaw(float yawRadians) {} + virtual float getHeadPitch() const {return 0.f;} + virtual float getHeadYaw() const {return 0.f;} + private: Animation(const Animation&); void operator=(Animation&); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 598e2fba9c..92e61801e9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -73,34 +73,37 @@ namespace MWRender { /// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. -/// The pitch is then applied on top of that orientation. +/// The rotation is then applied on top of that orientation. /// @note Must be set on a MatrixTransform. class RotateController : public osg::NodeCallback { public: - RotateController(osg::Node* relativeTo, osg::Vec3f axis) - : mRotate(0.f) - , mAxis(axis) + RotateController(osg::Node* relativeTo) + : mEnabled(true) , mRelativeTo(relativeTo) { } - void setRotate(float rotate) + void setEnabled(bool enabled) + { + mEnabled = enabled; + } + + void setRotate(const osg::Quat& rotate) { mRotate = rotate; } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (mRotate == 0.f) + if (!mEnabled) return; osg::MatrixTransform* transform = static_cast(node); osg::Matrix matrix = transform->getMatrix(); osg::Quat worldOrient = getWorldOrientation(node); - osg::Quat rotate (mRotate, mAxis); - osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); matrix.setRotate(orient); transform->setMatrix(matrix); @@ -113,7 +116,7 @@ public: // this could be optimized later, we just need the world orientation, not the full matrix osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); osg::Quat worldOrient; - if (worldMats.size()) + if (!worldMats.empty()) { osg::Matrixf worldMat = worldMats[0]; worldOrient = worldMat.getRotate(); @@ -122,8 +125,8 @@ public: } protected: - float mRotate; - osg::Vec3f mAxis; + bool mEnabled; + osg::Quat mRotate; osg::ref_ptr mRelativeTo; }; @@ -134,7 +137,7 @@ class NeckController : public RotateController { public: NeckController(osg::Node* relativeTo) - : RotateController(relativeTo, osg::Vec3f(-1,0,0)) + : RotateController(relativeTo) { } @@ -149,8 +152,7 @@ public: osg::Matrix matrix = transform->getMatrix(); osg::Quat worldOrient = getWorldOrientation(node); - osg::Quat rotate (mRotate, mAxis); - osg::Quat orient = worldOrient * rotate * worldOrient.inverse() * matrix.getRotate(); + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); matrix.setRotate(orient); matrix.setTrans(matrix.getTrans() + worldOrient.inverse() * mOffset); @@ -293,9 +295,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mNpcType(Type_Normal), mVisibilityFlags(visibilityFlags), mAlpha(1.f), - mSoundsDisabled(disableSounds) - //mHeadPitch(0.f), - //mHeadYaw(0.f) + mSoundsDisabled(disableSounds), + mHeadYawRadians(0.f), + mHeadPitchRadians(0.f) { mNpc = mPtr.get()->mBase; @@ -695,10 +697,19 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) if (mFirstPersonNeckController) { - mFirstPersonNeckController->setRotate(mPtr.getRefData().getPosition().rot[0]); + mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); mFirstPersonNeckController->setOffset(mFirstPersonOffset); } + if (mHeadController) + { + const float epsilon = 0.001f; + bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); + mHeadController->setEnabled(enable); + if (enable) + mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); + } + /* if (mSkelBase) { @@ -707,10 +718,6 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) { // In third person mode we may still need pitch for ranged weapon targeting pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); } } */ @@ -718,6 +725,26 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) return ret; } +void NpcAnimation::setHeadPitch(float pitchRadians) +{ + mHeadPitchRadians = pitchRadians; +} + +void NpcAnimation::setHeadYaw(float yawRadians) +{ + mHeadYawRadians = yawRadians; +} + +float NpcAnimation::getHeadPitch() const +{ + return mHeadPitchRadians; +} + +float NpcAnimation::getHeadYaw() const +{ + return mHeadYawRadians; +} + void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; @@ -878,6 +905,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } + } } void NpcAnimation::showWeapons(bool showWeapon) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 28ae43144b..db0b4ea0ce 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -49,6 +49,7 @@ public: }; class NeckController; +class RotateController; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -102,8 +103,8 @@ private: float mAlpha; bool mSoundsDisabled; - //Ogre::Radian mHeadYaw; - //Ogre::Radian mHeadPitch; + float mHeadYawRadians; + float mHeadPitchRadians; void updateNpcBase(); @@ -122,6 +123,7 @@ private: //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); osg::ref_ptr mFirstPersonNeckController; + osg::ref_ptr mHeadController; protected: virtual void addControllers(); @@ -153,10 +155,10 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - //virtual void setHeadPitch(Ogre::Radian pitch); - //virtual void setHeadYaw(Ogre::Radian yaw); - //virtual Ogre::Radian getHeadPitch() const; - //virtual Ogre::Radian getHeadYaw() const; + virtual void setHeadPitch(float pitchRadians); + virtual void setHeadYaw(float yawRadians); + virtual float getHeadPitch() const; + virtual float getHeadYaw() const; virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); From ed4863ad7db53c6835cca1e3ecd5778933024334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 18:53:16 +0200 Subject: [PATCH 0345/1812] Restore ranged weapon aiming --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 10 +-- apps/openmw/mwrender/creatureanimation.hpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 75 ++-------------------- apps/openmw/mwrender/rotatecontroller.cpp | 57 ++++++++++++++++ apps/openmw/mwrender/rotatecontroller.hpp | 36 +++++++++++ apps/openmw/mwrender/weaponanimation.cpp | 65 +++++++++++++------ apps/openmw/mwrender/weaponanimation.hpp | 15 ++++- 8 files changed, 170 insertions(+), 94 deletions(-) create mode 100644 apps/openmw/mwrender/rotatecontroller.cpp create mode 100644 apps/openmw/mwrender/rotatecontroller.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2193f4ca0e..3cf43749de 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation sky npcanimation vismask + actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap # occlusionquery water shadows diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b98b261791..0dd647c9cf 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -171,14 +171,16 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() return mResourceSystem; } +void CreatureWeaponAnimation::addControllers() +{ + WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); +} + osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) { osg::Vec3f ret = Animation::runAnimation(duration); - /* - if (mSkelBase) - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); - */ + WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 61d077df3b..8a4ebb9309 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -46,11 +46,13 @@ namespace MWRender virtual void showWeapon(bool show) { showWeapons(show); } virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void addControllers(); + virtual osg::Vec3f runAnimation(float duration); /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character. - //virtual void setPitchFactor(float factor) { mPitchFactor = factor; } + virtual void setPitchFactor(float factor) { mPitchFactor = factor; } private: diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 92e61801e9..7283a621ab 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -26,6 +26,7 @@ #include "../mwbase/soundmanager.hpp" #include "camera.hpp" +#include "rotatecontroller.hpp" namespace { @@ -72,64 +73,6 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { -/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. -/// The rotation is then applied on top of that orientation. -/// @note Must be set on a MatrixTransform. -class RotateController : public osg::NodeCallback -{ -public: - RotateController(osg::Node* relativeTo) - : mEnabled(true) - , mRelativeTo(relativeTo) - { - - } - - void setEnabled(bool enabled) - { - mEnabled = enabled; - } - - void setRotate(const osg::Quat& rotate) - { - mRotate = rotate; - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (!mEnabled) - return; - osg::MatrixTransform* transform = static_cast(node); - osg::Matrix matrix = transform->getMatrix(); - osg::Quat worldOrient = getWorldOrientation(node); - - osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); - matrix.setRotate(orient); - - transform->setMatrix(matrix); - - traverse(node,nv); - } - - osg::Quat getWorldOrientation(osg::Node* node) - { - // this could be optimized later, we just need the world orientation, not the full matrix - osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); - osg::Quat worldOrient; - if (!worldMats.empty()) - { - osg::Matrixf worldMat = worldMats[0]; - worldOrient = worldMat.getRotate(); - } - return worldOrient; - } - -protected: - bool mEnabled; - osg::Quat mRotate; - osg::ref_ptr mRelativeTo; -}; - /// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note Must be set on a MatrixTransform. @@ -710,17 +653,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); } - /* - if (mSkelBase) - { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode != VM_FirstPerson) - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - } - } - */ + WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } @@ -906,6 +839,8 @@ void NpcAnimation::addControllers() { mFirstPersonNeckController = NULL; mHeadController = NULL; + WeaponAnimation::deleteControllers(); + if (mViewMode == VM_FirstPerson) { NodeMap::iterator found = mNodeMap.find("bip01 neck"); @@ -927,6 +862,8 @@ void NpcAnimation::addControllers() node->addUpdateCallback(mHeadController); mActiveControllers.insert(std::make_pair(node, mHeadController)); } + + WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } } diff --git a/apps/openmw/mwrender/rotatecontroller.cpp b/apps/openmw/mwrender/rotatecontroller.cpp new file mode 100644 index 0000000000..11f5b943d7 --- /dev/null +++ b/apps/openmw/mwrender/rotatecontroller.cpp @@ -0,0 +1,57 @@ +#include "rotatecontroller.hpp" + +#include + +namespace MWRender +{ + +RotateController::RotateController(osg::Node *relativeTo) + : mEnabled(true) + , mRelativeTo(relativeTo) +{ + +} + +void RotateController::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + +void RotateController::setRotate(const osg::Quat &rotate) +{ + mRotate = rotate; +} + +void RotateController::operator()(osg::Node *node, osg::NodeVisitor *nv) +{ + if (!mEnabled) + { + traverse(node, nv); + return; + } + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + osg::Quat worldOrient = getWorldOrientation(node); + + osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate(); + matrix.setRotate(orient); + + transform->setMatrix(matrix); + + traverse(node,nv); +} + +osg::Quat RotateController::getWorldOrientation(osg::Node *node) +{ + // this could be optimized later, we just need the world orientation, not the full matrix + osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo); + osg::Quat worldOrient; + if (!worldMats.empty()) + { + osg::Matrixf worldMat = worldMats[0]; + worldOrient = worldMat.getRotate(); + } + return worldOrient; +} + +} diff --git a/apps/openmw/mwrender/rotatecontroller.hpp b/apps/openmw/mwrender/rotatecontroller.hpp new file mode 100644 index 0000000000..8c3758cb00 --- /dev/null +++ b/apps/openmw/mwrender/rotatecontroller.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_MWRENDER_ROTATECONTROLLER_H +#define OPENMW_MWRENDER_ROTATECONTROLLER_H + +#include +#include + +namespace MWRender +{ + +/// Applies a rotation in \a relativeTo's space. +/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller. +/// The rotation is then applied on top of that orientation. +/// @note Must be set on a MatrixTransform. +class RotateController : public osg::NodeCallback +{ +public: + RotateController(osg::Node* relativeTo); + + void setEnabled(bool enabled); + + void setRotate(const osg::Quat& rotate); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + +protected: + osg::Quat getWorldOrientation(osg::Node* node); + + bool mEnabled; + osg::Quat mRotate; + osg::ref_ptr mRelativeTo; +}; + + +} + +#endif diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 23a74fb95e..301779c1e6 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -1,5 +1,7 @@ #include "weaponanimation.hpp" +#include + #include #include @@ -15,6 +17,7 @@ #include "../mwmechanics/combat.hpp" #include "animation.hpp" +#include "rotatecontroller.hpp" namespace MWRender { @@ -46,6 +49,11 @@ WeaponAnimation::WeaponAnimation() { } +WeaponAnimation::~WeaponAnimation() +{ + +} + void WeaponAnimation::attachArrow(MWWorld::Ptr actor) { MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); @@ -149,28 +157,49 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) } } -/* -void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) +void WeaponAnimation::addControllers(const std::map >& nodes, + std::multimap, osg::ref_ptr > &map, osg::Node* objectRoot) { - if (mPitchFactor == 0) + for (int i=0; i<2; ++i) + { + mSpineControllers[i] = NULL; + + std::map >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2"); + if (found != nodes.end()) + { + osg::Node* node = found->second; + mSpineControllers[i] = new RotateController(objectRoot); + node->addUpdateCallback(mSpineControllers[i]); + map.insert(std::make_pair(node, mSpineControllers[i])); + } + } +} + +void WeaponAnimation::deleteControllers() +{ + for (int i=0; i<2; ++i) + mSpineControllers[i] = NULL; +} + +void WeaponAnimation::configureControllers(float characterPitchRadians) +{ + if (!mSpineControllers[0]) return; - float pitch = xrot * mPitchFactor; - Ogre::Node *node; + if (mPitchFactor == 0.f || characterPitchRadians == 0.f) + { + for (int i=0; i<2; ++i) + mSpineControllers[i]->setEnabled(false); + return; + } - // In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive? - if (skel->hasBone("Bip01 spine2")) - node = skel->getBone("Bip01 spine2"); - else - node = skel->getBone("Bip01 Spine2"); - node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); - - if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif - node = skel->getBone("Bip01 spine1"); - else - node = skel->getBone("Bip01 Spine1"); - node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); + float pitch = characterPitchRadians * mPitchFactor; + osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0)); + for (int i=0; i<2; ++i) + { + mSpineControllers[i]->setRotate(rotate); + mSpineControllers[i]->setEnabled(true); + } } -*/ } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index f46638ac85..9336afd4ca 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -9,6 +9,8 @@ namespace MWRender { + class RotateController; + class WeaponAnimationTime : public SceneUtil::ControllerSource { private: @@ -28,7 +30,7 @@ namespace MWRender { public: WeaponAnimation(); - virtual ~WeaponAnimation() {} + virtual ~WeaponAnimation(); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. void attachArrow(MWWorld::Ptr actor); @@ -36,9 +38,20 @@ namespace MWRender /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. void releaseArrow(MWWorld::Ptr actor); + /// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map. + void addControllers(const std::map >& nodes, + std::multimap, osg::ref_ptr >& map, osg::Node* objectRoot); + + void deleteControllers(); + + /// Configure controllers, should be called every animation frame. + void configureControllers(float characterPitchRadians); + protected: PartHolderPtr mAmmunition; + osg::ref_ptr mSpineControllers[2]; + virtual osg::Group* getArrowBone() = 0; virtual osg::Node* getWeaponNode() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0; From 5b846ebc71ef34905809f3c78ad4591e7921da74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 May 2015 23:09:37 +0200 Subject: [PATCH 0346/1812] Camera precision fix --- apps/openmw/mwrender/camera.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index bb47245554..69998ed26e 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -92,17 +92,17 @@ namespace MWRender return; const osg::Matrix& worldMat = mats[0]; - osg::Vec3 position = worldMat.getTrans(); + osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) position.z() += mHeight; - osg::Quat orient = osg::Quat(getPitch(), osg::Vec3(1,0,0)) * osg::Quat(getYaw(), osg::Vec3(0,0,1)); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); - osg::Vec3 offset = orient * osg::Vec3(0, -mCameraDistance, 0); + osg::Vec3d offset = orient * osg::Vec3d(0, -mCameraDistance, 0); position += offset; - osg::Vec3 forward = orient * osg::Vec3(0,1,0); - osg::Vec3 up = orient * osg::Vec3(0,0,1); + osg::Vec3d forward = orient * osg::Vec3d(0,1,0); + osg::Vec3d up = orient * osg::Vec3d(0,0,1); cam->setViewMatrixAsLookAt(position, position + forward, up); } From 84fd682e4e1d0ec923bd1276fa192ac7a5952dc5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 00:40:05 +0200 Subject: [PATCH 0347/1812] Fix for unnecessary exceptions when opening sounds This would throw often during normal play, even though the throws are caught and ignored, can be annoying when the debugger is set to 'catch throw'. --- apps/openmw/mwsound/openal_output.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 6862bb889d..a984fffa97 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include "openal_output.hpp" @@ -782,17 +784,15 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) int srate; DecoderPtr decoder = mManager.getDecoder(); - try + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + std::string file = fname; + if (!decoder->mResourceMgr->exists(file)) { - decoder->open(fname); - } - catch(std::exception&) - { - std::string::size_type pos = fname.rfind('.'); - if(pos == std::string::npos) - throw; - decoder->open(fname.substr(0, pos)+".mp3"); + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; } + decoder->open(file); decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); From e30685357055f0fddfae10fc242477882cc847f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 00:50:48 +0200 Subject: [PATCH 0348/1812] Fix chargen crash --- apps/openmw/mwworld/worldimp.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 768177b16a..926e453b8b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1542,8 +1542,7 @@ namespace MWWorld } const ESM::NPC *ret = mStore.insert(record); if (update) { - mRendering->renderPlayer(getPlayerPtr()); - scaleObject(getPlayerPtr(), 1.f); // apply race height + renderPlayer(); } return ret; } @@ -2118,13 +2117,12 @@ namespace MWWorld void World::renderPlayer() { + MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); + mRendering->renderPlayer(getPlayerPtr()); scaleObject(getPlayerPtr(), 1.f); // apply race height - // At this point the Animation object is live, and the CharacterController associated with it must be created. - // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate - // so we should make sure not to use a "stale" controller for that. MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); From 8e0a9882890f264803337873bc8f40d9ffe77cd0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 01:32:02 +0200 Subject: [PATCH 0349/1812] Icon fix --- apps/openmw/mwgui/birth.cpp | 1 - apps/openmw/mwgui/formatting.cpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/itemwidget.cpp | 2 -- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellcreationdialog.cpp | 1 - apps/openmw/mwgui/spellicons.cpp | 1 - apps/openmw/mwgui/tooltips.cpp | 3 +-- apps/openmw/mwgui/widgets.cpp | 2 -- 9 files changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index dd20999e05..1122a40690 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -5,7 +5,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 461d8e32e1..6adef5eeb4 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include "../mwscript/interpretercontext.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 43df37b6de..0fab66a254 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 645a722774..75436e797d 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -4,8 +4,6 @@ #include #include -#include - // correctIconPath #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index cd6e2405c8..b673e5bd0f 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 86c502580b..08b205ec74 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c263166262..db04536231 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 5dd201068b..526cbaabe3 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/world.hpp" @@ -782,7 +781,7 @@ namespace MWGui std::string icon = effect->mIcon; int slashPos = icon.rfind('\\'); icon.insert(slashPos+1, "b_"); - //icon = Misc::ResourceHelpers::correctIconPath(icon); + icon = MWBase::Environment::get().getWindowManager()->correctIconPath(icon); widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 996cc528dd..1fa5d9cbf0 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" From ccd95419e579b0e707a67274b3efdfa93f95e661 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 01:57:15 +0200 Subject: [PATCH 0350/1812] Restore various raycasting --- apps/openmw/mwmechanics/character.cpp | 8 +- apps/openmw/mwphysics/physicssystem.cpp | 71 ++++++++--- apps/openmw/mwphysics/physicssystem.hpp | 19 ++- apps/openmw/mwrender/animation.cpp | 2 - apps/openmw/mwrender/effectmanager.cpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 15 +++ apps/openmw/mwrender/renderingmanager.hpp | 3 + apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 147 ++++++++++------------ 9 files changed, 157 insertions(+), 111 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 354ca998c0..3843df132b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -838,14 +838,12 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::updateIdleStormState() { bool inStormDirection = false; - /* if (MWBase::Environment::get().getWorld()->isInStorm()) { - Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); - inStormDirection = stormDirection.angleBetween(characterDirection) > Ogre::Degree(120); + osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + osg::Vec3f characterDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); + inStormDirection = std::acos(stormDirection * characterDirection) > osg::DegreesToRadians(120.f); } - */ if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d36aded241..c942fecb1b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -728,35 +728,74 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } - - bool PhysicsSystem::castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool ignoreHeightMap) + class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { - return false; - /* - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); + public: + ClosestNotMeRayResultCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to) + : btCollisionWorld::ClosestRayResultCallback(from, to) + , mMe(me) + { + } - std::pair result = mEngine->rayTest(_from, _to,ignoreHeightMap); - return !(result.first == ""); - */ - } + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + { + if (rayResult.m_collisionObject == mMe) + return 1.f; + return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); + } + private: + const btCollisionObject* mMe; + }; - std::pair PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to) + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask) { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); - btCollisionWorld::ClosestRayResultCallback resultCallback(btFrom, btTo); + const btCollisionObject* me = NULL; + if (!ignore.isEmpty()) + { + Actor* actor = getActor(ignore); + if (actor) + me = actor->getCollisionObject(); + } + + ClosestNotMeRayResultCallback resultCallback(me, btFrom, btTo); resultCallback.m_collisionFilterGroup = 0xff; - resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap; + resultCallback.m_collisionFilterMask = mask; mCollisionWorld->rayTest(btFrom, btTo, resultCallback); + + RayResult result; + result.mHit = resultCallback.hasHit(); if (resultCallback.hasHit()) { - return std::make_pair(true, toOsg(resultCallback.m_hitPointWorld)); + result.mHitPos = toOsg(resultCallback.m_hitPointWorld); + result.mHitNormal = toOsg(resultCallback.m_hitNormalWorld); + if (PtrHolder* ptrHolder = static_cast(resultCallback.m_collisionObject->getUserPointer())) + result.mHitObject = ptrHolder->getPtr(); } - return std::make_pair(false, osg::Vec3f()); + return result; + } + + bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) + { + Actor* physactor1 = getActor(actor1); + Actor* physactor2 = getActor(actor2); + + if (!physactor1 || !physactor2) + return false; + + osg::Vec3f halfExt1 = physactor1->getHalfExtents(); + osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); + pos1.z() += halfExt1.z()*2*0.9f; // eye level + osg::Vec3f halfExt2 = physactor2->getHalfExtents(); + osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); + pos2.z() += halfExt2.z()*2*0.9f; + + RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); + + return !result.mHit; } class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2240a51196..7920347ad5 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -11,6 +11,8 @@ #include +#include "collisiontype.hpp" + namespace osg { class Group; @@ -87,11 +89,20 @@ namespace MWPhysics const osg::Quat &orientation, float queryDistance); - // cast ray, return true if it hit something. - bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to,bool ignoreHeightMap = false); + struct RayResult + { + bool mHit; + osg::Vec3f mHitPos; + osg::Vec3f mHitNormal; + MWWorld::Ptr mHitObject; + }; - /// @return - std::pair castRay(const osg::Vec3f &from, const osg::Vec3f &to); + /// @param me Optional, a Ptr to ignore in the list of results + RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + + /// Return true if actor1 can see actor2. + bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b23981f816..2279375c23 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -20,8 +20,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 642909cda2..42a63fc68c 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e1f1e13d19..a067422d46 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -298,6 +298,21 @@ namespace MWRender mObjects->removeObject(ptr); } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) + { + osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); + osg::Matrix invViewProj = viewProj.inverse(viewProj); + + nX = nX * 2 - 1; + nY = nY * -2 + 1; + + osg::Vec3f start (nX, nY, -1.f); + osg::Vec3f end (nX, nY, 1.f); + + origin = invViewProj.preMult(start); + dest = invViewProj.preMult(end); + } + osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) { if (!ptr.getRefData().getBaseNode()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 011ceee09d..e2524b3603 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -80,6 +80,9 @@ namespace MWRender /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); + /// Get a camera to viewport ray for normalized screen coordinates nX and nY, with the top left corner being at (0,0) + void getCameraToViewportRay(float nX, float nY, osg::Vec3f& origin, osg::Vec3f& dest); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c9e69b0b40..81497aa6c2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -419,6 +419,7 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; + mStormDirection.normalize(); mRendering->getSkyManager()->setStormDirection(mStormDirection); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 926e453b8b..f4f960d97c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -7,7 +7,6 @@ #else #include #endif -#include #include #include @@ -21,8 +20,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1411,9 +1408,10 @@ namespace MWWorld bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) { - Ogre::Vector3 a(x1,y1,z1); - Ogre::Vector3 b(x2,y2,z2); - return 0;//mPhysics->castRay(a,b,false,true); + osg::Vec3f a(x1,y1,z1); + osg::Vec3f b(x2,y2,z2); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World); + return result.mHit; } void World::processDoors(float duration) @@ -1793,17 +1791,26 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - std::pair result;// = mPhysics->castRay(cursorX, cursorY); + osg::Vec3f origin, dest; + mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - if (!result.first) - return MWWorld::Ptr(); + const float maxDist = 200.f; + osg::Vec3f dir = (dest - origin); + dir.normalize(); + dest = origin + dir * maxDist; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); CellStore* cell = getPlayerPtr().getCell(); ESM::Position pos = getPlayerPtr().getRefData().getPosition(); - pos.pos[0] = result.second[0]; - pos.pos[1] = result.second[1]; - pos.pos[2] = result.second[2]; + if (result.mHit) + { + pos.pos[0] = result.mHitPos.x(); + pos.pos[1] = result.mHitPos.y(); + pos.pos[2] = result.mHitPos.z(); + } // We want only the Z part of the player's rotation pos.rot[0] = 0; pos.rot[1] = 0; @@ -1822,21 +1829,23 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - Ogre::Vector3 normal(0,0,0); - std::string handle; - std::pair result;// = mPhysics->castRay(cursorX, cursorY, &normal, &handle); + osg::Vec3f origin, dest; + mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - if (result.first) + const float maxDist = 200.f; + osg::Vec3f dir = (dest - origin); + dir.normalize(); + dest = origin + dir * maxDist; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + + if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() >= 30) + if (std::acos(result.mHitNormal * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; - /* - MWWorld::Ptr hitObject = searchPtrViaHandle(handle); - if (!hitObject.isEmpty() && hitObject.getClass().isActor()) - return false; - */ return true; } else @@ -1917,9 +1926,10 @@ namespace MWWorld float len = 100.0; - std::pair hit = mPhysics->castRay(orig, dir*len); - if (hit.first) - pos.pos[2] = hit.second.z(); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(orig, orig+dir*len, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + if (result.mHit) + pos.pos[2] = result.mHitPos.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); @@ -2346,50 +2356,30 @@ namespace MWWorld } } - bool World::getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) + bool World::getLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor) { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell - // TODO: move to PhysicsSystem - /* - OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); - OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); - - if (!actor1 || !actor2) - return false; - - Ogre::Vector3 halfExt1 = actor1->getHalfExtents(); - const float* pos1 = actor.getRefData().getPosition().pos; - Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); - const float* pos2 = targetActor.getRefData().getPosition().pos; - - btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9f); // eye level - btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9f); - - std::pair result = mPhysEngine->rayTest(from, to,false); - if(result.first == "") return true; - */ - - return true; + return mPhysics->getLineOfSight(actor, targetActor); } float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) { - return 0; - /* - btVector3 btFrom(from.x, from.y, from.z); - btVector3 btTo = btVector3(dir.x, dir.y, dir.z); - btTo.normalize(); - btTo = btFrom + btTo * maxDist; + osg::Vec3f from_ (from.x, from.y, from.z); + osg::Vec3f to_ (dir.x, dir.y, dir.z); + to_.normalize(); + to_ = from_ + (to_ * maxDist); - std::pair result = mPhysEngine->rayTest(btFrom, btTo, false); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from_, to_, MWWorld::Ptr(), + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); - if(result.second == -1) return maxDist; - else return result.second*(btTo-btFrom).length(); - */ + if (!result.mHit) + return maxDist; + else + return (result.mHitPos - from_).length(); } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) @@ -2697,37 +2687,30 @@ namespace MWWorld else { // For NPCs use facing direction from Head node - Ogre::Vector3 origin(actor.getRefData().getPosition().pos); -#if 0 - MWRender::Animation *anim = mRendering->getAnimation(actor); - if(anim != NULL) + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); + + MWRender::Animation* anim = mRendering->getAnimation(actor); + if (anim != NULL) { - Ogre::Node *node = anim->getNode("Head"); + const osg::Node* node = anim->getNode("Head"); if (node == NULL) node = anim->getNode("Bip01 Head"); - if(node != NULL) - origin += node->_getDerivedPosition(); - } -#endif - /* - - Ogre::Quaternion orient; - orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); - Ogre::Vector3 direction = orient.yAxis(); - Ogre::Vector3 dest = origin + direction * distance; - - std::vector > collisions = mPhysEngine->rayTest2(btVector3(origin.x, origin.y, origin.z), btVector3(dest.x, dest.y, dest.z)); - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end(); ++cIt) - { - MWWorld::Ptr collided = getPtrViaHandle(cIt->second); - if (collided != actor) + if (node != NULL) { - target = collided; - break; + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + origin = mats[0].getTrans(); } } - */ + + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + osg::Vec3f dest = origin + direction * distance; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); + target = result.mHitObject; } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From f88079fddd1b77e5e1b09fe9e41e9f55d3250cb3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 02:40:42 +0200 Subject: [PATCH 0351/1812] Restore the isOnGround hack --- apps/openmw/mwphysics/physicssystem.cpp | 37 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 37 +------------------------ 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c942fecb1b..7c083ca08f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -798,6 +798,43 @@ namespace MWPhysics return !result.mHit; } + // physactor->getOnGround() is not a reliable indicator of whether the actor + // is on the ground (defaults to false, which means code blocks such as + // CharacterController::update() may falsely detect "falling"). + // + // Also, collisions can move z position slightly off zero, giving a false + // indication. In order to reduce false detection of jumping, small distance + // below the actor is detected and ignored. A value of 1.5 is used here, but + // something larger may be more suitable. This change should resolve Bug#1271. + // + // TODO: There might be better places to update PhysicActor::mOnGround. + bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if(!physactor) + return false; + if(physactor->getOnGround()) + return true; + else + { + osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); + + ActorTracer tracer; + // a small distance above collision object is considered "on ground" + tracer.findGround(physactor, + pos, + pos - osg::Vec3f(0, 0, 1.5f), // trace a small amount down + mCollisionWorld); + if(tracer.mFraction < 1.0f) // collision, must be close to something below + { + physactor->setOnGround(true); + return true; + } + else + return false; + } + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7920347ad5..2defd7a507 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -104,6 +104,8 @@ namespace MWPhysics /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); + bool isOnGround (const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f4f960d97c..aa21ca7fba 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2022,44 +2022,9 @@ namespace MWWorld return pos.z < cell->getWaterLevel(); } - // physactor->getOnGround() is not a reliable indicator of whether the actor - // is on the ground (defaults to false, which means code blocks such as - // CharacterController::update() may falsely detect "falling"). - // - // Also, collisions can move z position slightly off zero, giving a false - // indication. In order to reduce false detection of jumping, small distance - // below the actor is detected and ignored. A value of 1.5 is used here, but - // something larger may be more suitable. This change should resolve Bug#1271. - // - // TODO: There might be better places to update PhysicActor::mOnGround. bool World::isOnGround(const MWWorld::Ptr &ptr) const { - MWPhysics::Actor* physactor = mPhysics->getActor(ptr); - - if(!physactor) - return false; - return physactor->getOnGround(); - /* - if(physactor->getOnGround()) - return true; - else - { - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); - OEngine::Physic::ActorTracer tracer; - // a small distance above collision object is considered "on ground" - tracer.findGround(physactor, - pos, - pos - Ogre::Vector3(0, 0, 1.5f), // trace a small amount down - mPhysEngine); - if(tracer.mFraction < 1.0f) // collision, must be close to something below - { - physactor->setOnGround(true); - return true; - } - else - return false; - } - */ + return mPhysics->isOnGround(ptr); } void World::togglePOV() From b0b55e2037d52b392c1031c81cbb8d3ecd602ae6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 02:46:09 +0200 Subject: [PATCH 0352/1812] Delete niftest as it's currently broken --- CMakeLists.txt | 9 --- components/nif/tests/.gitignore | 1 - components/nif/tests/CMakeLists.txt | 19 ------ components/nif/tests/niftest.cpp | 96 ----------------------------- components/nif/tests/test.sh | 15 ----- 5 files changed, 140 deletions(-) delete mode 100644 components/nif/tests/.gitignore delete mode 100644 components/nif/tests/CMakeLists.txt delete mode 100644 components/nif/tests/niftest.cpp delete mode 100755 components/nif/tests/test.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3cd9f6bf..43d40c2ef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,6 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment @@ -319,9 +318,6 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) - IF(BUILD_NIFTEST) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_NIFTEST) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" ) ENDIF(BUILD_WIZARD) @@ -461,11 +457,6 @@ add_subdirectory (components) # add_subdirectory(plugins/mygui_resource_plugin) #endif() -#Testing -if (BUILD_NIFTEST) - add_subdirectory(components/nif/tests/) -endif(BUILD_NIFTEST) - # Apps and tools if (BUILD_OPENMW) add_subdirectory( apps/openmw ) diff --git a/components/nif/tests/.gitignore b/components/nif/tests/.gitignore deleted file mode 100644 index 397b4a7624..0000000000 --- a/components/nif/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.log diff --git a/components/nif/tests/CMakeLists.txt b/components/nif/tests/CMakeLists.txt deleted file mode 100644 index a45298180a..0000000000 --- a/components/nif/tests/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(NIFTEST - niftest.cpp -) -source_group(components\\nif\\tests FILES ${NIFTEST}) - -# Main executable -add_executable(niftest - ${NIFTEST} -) - -target_link_libraries(niftest - ${Boost_LIBRARIES} - components -) - -if (BUILD_WITH_CODE_COVERAGE) - add_definitions (--coverage) - target_link_libraries(niftest gcov) -endif() diff --git a/components/nif/tests/niftest.cpp b/components/nif/tests/niftest.cpp deleted file mode 100644 index a06c002df1..0000000000 --- a/components/nif/tests/niftest.cpp +++ /dev/null @@ -1,96 +0,0 @@ -///Program to test .nif files both on the FileSystem and in BSA archives. - -#include "../niffile.hpp" -#include "../../bsa/bsa_file.hpp" -#include "../../bsa/bsa_archive.hpp" -#include -#include -#include -#include -#include - -///See if the file has the named extension -bool hasExtension(std::string filename, std::string extensionToFind) -{ - std::string extension = filename.substr(filename.find_last_of(".")+1); - - //Convert strings to lower case for comparison - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower); - - if(extension == extensionToFind) - return true; - else - return false; -} - -///See if the file has the "nif" extension. -bool isNIF(std::string filename) -{ - return hasExtension(filename,"nif"); -} -///See if the file has the "bsa" extension. -bool isBSA(std::string filename) -{ - return hasExtension(filename,"bsa"); -} - -///Check all the nif files in the given BSA archive -void readBSA(std::string filename) -{ - Bsa::BSAFile bsa; - bsa.open(filename.c_str()); - - const Bsa::BSAFile::FileList &files = bsa.getList(); - Bsa::addBSA(filename,"Bsa Files"); - - for(unsigned int i=0; i nifs.txt -find "$DATAFILESDIR" -iname *nif >> nifs.txt - -sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt - -xargs --arg-file=quoted_nifs.txt ../../../niftest - -rm nifs.txt -rm quoted_nifs.txt From 28694248477abad8c82a0e12b32354d20ff2313f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 04:41:03 +0200 Subject: [PATCH 0353/1812] Fix first person camera for beast races --- apps/openmw/mwrender/camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 69998ed26e..e28b6befa4 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -362,6 +362,8 @@ namespace MWRender { mAnimation->setViewMode(NpcAnimation::VM_FirstPerson); mTrackingNode = mAnimation->getNode("Camera"); + if (!mTrackingNode) + mTrackingNode = mAnimation->getNode("Head"); } else { From bed31996c910d405c09dee815cfdadf762149440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 15:34:46 +0200 Subject: [PATCH 0354/1812] Camera raycast --- apps/openmw/mwphysics/physicssystem.cpp | 25 +++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 2 ++ apps/openmw/mwrender/camera.cpp | 27 +++++++++++++++-------- apps/openmw/mwrender/camera.hpp | 5 ++++- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++ 7 files changed, 69 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7c083ca08f..c0e7a80b9d 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -778,6 +779,30 @@ namespace MWPhysics return result; } + PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) + { + btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); + callback.m_collisionFilterGroup = 0xff; + callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + + btSphereShape shape(radius); + const btQuaternion btrot = btQuaternion::getIdentity(); + + btTransform from_ (btrot, toBullet(from)); + btTransform to_ (btrot, toBullet(to)); + + mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); + + RayResult result; + result.mHit = callback.hasHit(); + if (result.mHit) + { + result.mHitPos = toOsg(callback.m_hitPointWorld); + result.mHitNormal = toOsg(callback.m_hitNormalWorld); + } + return result; + } + bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) { Actor* physactor1 = getActor(actor1); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2defd7a507..d4f7e25b10 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -101,6 +101,8 @@ namespace MWPhysics RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); + /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index e28b6befa4..9080d31644 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -80,21 +80,28 @@ namespace MWRender return mTrackingPtr; } - void Camera::updateCamera(osg::Camera *cam) + osg::Vec3d Camera::getFocalPoint() { - if (mTrackingPtr.isEmpty()) - return; const osg::Node* trackNode = mTrackingNode; if (!trackNode) - return; + return osg::Vec3d(); osg::MatrixList mats = trackNode->getWorldMatrices(); if (!mats.size()) - return; + return osg::Vec3d(); const osg::Matrix& worldMat = mats[0]; osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) position.z() += mHeight; + return position; + } + + void Camera::updateCamera(osg::Camera *cam) + { + if (mTrackingPtr.isEmpty()) + return; + + osg::Vec3d position = getFocalPoint(); osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); @@ -373,12 +380,14 @@ namespace MWRender rotateCamera(getPitch(), getYaw(), false); } - void Camera::getPosition(osg::Vec3 &focal, osg::Vec3 &camera) + void Camera::getPosition(osg::Vec3f &focal, osg::Vec3f &camera) { - //mCamera->getParentSceneNode()->needUpdate(true); + focal = getFocalPoint(); - //camera = mCamera->getRealPosition(); - //focal = mCameraNode->_getDerivedPosition(); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); + + osg::Vec3d offset = orient * osg::Vec3d(0, -mCameraDistance, 0); + camera = focal + offset; } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 68f0870d71..a655e1c1f8 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -113,8 +114,10 @@ namespace MWRender void setAnimation(NpcAnimation *anim); + osg::Vec3d getFocalPoint(); + /// Stores focal and camera world positions in passed arguments - void getPosition(osg::Vec3 &focal, osg::Vec3 &camera); + void getPosition(osg::Vec3f &focal, osg::Vec3f &camera); void togglePlayerLooking(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a067422d46..0218358394 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -514,6 +514,11 @@ namespace MWRender } } + float RenderingManager::getNearClipDistance() const + { + return mNearClip; + } + bool RenderingManager::vanityRotateCamera(const float *rot) { if(!mCamera->isVanityOrPreviewModeEnabled()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e2524b3603..57a2df60e5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -113,6 +113,8 @@ namespace MWRender void processChangedSettings(const Settings::CategorySettingVector& settings); + float getNearClipDistance() const; + // camera stuff bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust, bool override); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index aa21ca7fba..2f47c19e60 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1617,6 +1617,19 @@ namespace MWWorld int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); + + + mRendering->getCamera()->setCameraDistance(); + if(!mRendering->getCamera()->isFirstPerson()) + { + osg::Vec3f focal, camera; + mRendering->getCamera()->getPosition(focal, camera); + float radius = mRendering->getNearClipDistance()*2.5f; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal, camera, radius); + if (result.mHit) + mRendering->getCamera()->setCameraDistance((result.mHitPos - focal).length() - radius, false, false); + } + } void World::updateSoundListener() From 987918ca15faf0961c056e162044beb9baa04dba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 16:18:57 +0200 Subject: [PATCH 0355/1812] NpcAnimation::setAlpha --- apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7283a621ab..0bbec707f2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include @@ -991,7 +993,29 @@ void NpcAnimation::setAlpha(float alpha) return; mAlpha = alpha; - // TODO + if (alpha != 1.f) + { + osg::StateSet* stateset (new osg::StateSet); + + osg::BlendFunc* blendfunc (new osg::BlendFunc); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // FIXME: overriding diffuse/ambient/emissive colors + osg::Material* material (new osg::Material); + material->setColorMode(osg::Material::DIFFUSE); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + stateset->setNestRenderBins(false); + mObjectRoot->setStateSet(stateset); + } + else + { + mObjectRoot->setStateSet(NULL); + } } void NpcAnimation::enableHeadAnimation(bool enable) From 7f9f9a32d27c9f96a53dff0ae03b529661177712 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 16:25:15 +0200 Subject: [PATCH 0356/1812] InitWorldSpaceParticles fix --- apps/openmw/mwrender/creatureanimation.cpp | 9 +++++---- apps/openmw/mwrender/effectmanager.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 1 + components/resource/scenemanager.cpp | 14 +++++++++++--- components/resource/scenemanager.hpp | 3 +++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 0dd647c9cf..9d1fccdb2c 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -107,12 +107,13 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) bonename = "Shield Bone"; osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item)); - SceneUtil::attach(node, mObjectRoot, bonename, bonename); + osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename); + mResourceSystem->getSceneManager()->notifyAttached(attached); - scene.reset(new PartHolder(node)); + scene.reset(new PartHolder(attached)); if (!item.getClass().getEnchantment(item).empty()) - addGlow(node, getEnchantmentColor(item)); + addGlow(attached, getEnchantmentColor(item)); // Crossbows start out with a bolt attached // FIXME: code duplicated from NpcAnimation @@ -137,7 +138,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) source.reset(new NullAnimationTime); SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); - node->accept(assignVisitor); + attached->accept(assignVisitor); } void CreatureWeaponAnimation::attachArrow() diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 42a63fc68c..c4e457a1fd 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -49,6 +49,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu overrideTexture(textureOverride, mResourceSystem, node); mParentNode->addChild(trans); + mResourceSystem->getSceneManager()->notifyAttached(node); mEffects[trans] = effect; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0bbec707f2..da44d7f203 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -628,6 +628,7 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st { osg::ref_ptr instance = mResourceSystem->getSceneManager()->createInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + mResourceSystem->getSceneManager()->notifyAttached(attached); if (enchantedGlow) addGlow(attached, *glowColor); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 5c3d9f1517..8de08bd9d6 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -52,7 +52,10 @@ namespace void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { - osg::Matrix worldMat = node->getWorldMatrices()[0]; + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.empty()) + return; + osg::Matrix worldMat = mats[0]; worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { @@ -140,8 +143,7 @@ namespace Resource void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); - InitWorldSpaceParticlesVisitor visitor; - instance->accept(visitor); + notifyAttached(instance); } void SceneManager::releaseGLObjects(osg::State *state) @@ -157,6 +159,12 @@ namespace Resource mIncrementalCompileOperation = ico; } + void SceneManager::notifyAttached(osg::Node *node) const + { + InitWorldSpaceParticlesVisitor visitor; + node->accept(visitor); + } + const VFS::Manager* SceneManager::getVFS() const { return mVFS; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 625c1cd5eb..f4ca0dea27 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -64,6 +64,9 @@ namespace Resource /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + /// @note If you used SceneManager::attachTo, this was called automatically. + void notifyAttached(osg::Node* node) const; + const VFS::Manager* getVFS() const; Resource::TextureManager* getTextureManager(); From c85764b65451fe2409b75158f3396f204db2fbc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 17:02:44 +0200 Subject: [PATCH 0357/1812] Wireframe mode --- apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++++++- components/sceneutil/statesetupdater.cpp | 6 +++++ components/sceneutil/statesetupdater.hpp | 4 ++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 0218358394..31ff9b02b3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ namespace MWRender public: StateUpdater() : mFogEnd(0.f) + , mWireframe(false) { } @@ -53,6 +55,14 @@ namespace MWRender fog->setStart(1); fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); + if (mWireframe) + { + osg::PolygonMode* polygonmode = new osg::PolygonMode; + polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); + stateset->setAttributeAndModes(polygonmode, osg::StateAttribute::ON); + } + else + stateset->removeAttribute(osg::StateAttribute::POLYGONMODE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) @@ -79,10 +89,25 @@ namespace MWRender mFogEnd = end; } + void setWireframe(bool wireframe) + { + if (mWireframe != wireframe) + { + mWireframe = wireframe; + reset(); + } + } + + bool getWireframe() const + { + return mWireframe; + } + private: osg::Vec4f mAmbientColor; osg::Vec4f mFogColor; float mFogEnd; + bool mWireframe; }; RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) @@ -224,7 +249,9 @@ namespace MWRender return mPathgrid->toggleRenderMode(mode); else if (mode == Render_Wireframe) { - return false; + bool wireframe = !mStateUpdater->getWireframe(); + mStateUpdater->setWireframe(wireframe); + return wireframe; } /* else //if (mode == Render_BoundingBoxes) diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 8ed229aa6f..66e40f3e10 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -28,6 +28,12 @@ namespace SceneUtil traverse(node, nv); } + void StateSetUpdater::reset() + { + mStateSets[0] = NULL; + mStateSets[1] = NULL; + } + StateSetUpdater::StateSetUpdater() { } diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 56f832a086..a4fcd7866e 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -35,6 +35,10 @@ namespace SceneUtil /// @par May be used e.g. to allocate StateAttributes. virtual void setDefaults(osg::StateSet* stateset) {} + protected: + /// Reset mStateSets, forcing a setDefaults() on the next frame. Can be used to change the defaults if needed. + void reset(); + private: osg::ref_ptr mStateSets[2]; }; From de8e5f0db1ccde4510681b10cacc747c1a90ed63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Jun 2015 21:41:13 +0200 Subject: [PATCH 0358/1812] Restore projectiles --- apps/openmw/CMakeLists.txt | 7 +- apps/openmw/mwbase/mechanicsmanager.hpp | 8 +- apps/openmw/mwbase/world.hpp | 6 +- apps/openmw/mwclass/creature.cpp | 8 +- apps/openmw/mwclass/npc.cpp | 8 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwmechanics/actors.cpp | 8 +- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 6 +- apps/openmw/mwmechanics/combat.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- apps/openmw/mwmechanics/objects.cpp | 4 +- apps/openmw/mwmechanics/objects.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 8 +- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 15 +- apps/openmw/mwphysics/physicssystem.hpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 4 +- apps/openmw/mwworld/actiontrap.cpp | 6 +- apps/openmw/mwworld/projectilemanager.cpp | 195 ++++++++---------- apps/openmw/mwworld/projectilemanager.hpp | 45 ++-- apps/openmw/mwworld/worldimp.cpp | 60 ++---- apps/openmw/mwworld/worldimp.hpp | 6 +- components/esm/projectilestate.hpp | 4 +- components/esm/util.hpp | 26 +++ 27 files changed, 231 insertions(+), 226 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3cf43749de..c46a831837 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,9 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap -# occlusionquery water shadows -# ripplesimulation refraction -# terrainstorage weaponanimation +# occlusionquery water shadows ripplesimulation refraction terrainstorage ) add_openmw_dir (mwinput @@ -68,8 +66,7 @@ add_openmw_dir (mwworld cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist cellref physicssystem weather -# projectilemanager + contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager ) add_openmw_dir (mwphysics diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f7fc515f57..1d3619d3da 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,9 +6,9 @@ #include #include -namespace Ogre +namespace osg { - class Vector3; + class Vec3f; } namespace ESM @@ -174,8 +174,8 @@ namespace MWBase virtual bool toggleAI() = 0; virtual bool isAIActive() = 0; - virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects) = 0; - virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) = 0; + virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; + virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; ///return the list of actors which are following the given actor /**ie AiFollow is active and the target is the actor**/ diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4d01f95295..f258eb300a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -378,7 +378,7 @@ namespace MWBase virtual bool isWading(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; @@ -485,7 +485,7 @@ namespace MWBase virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0; + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; @@ -532,7 +532,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; - virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 64850d1279..ea67884d35 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -247,7 +247,7 @@ namespace MWClass if (!victim.getClass().isActor()) return; // Can't hit non-actors - Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); + osg::Vec3f hitPosition (result.second); float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); @@ -319,7 +319,7 @@ namespace MWClass damage = 0; if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); MWMechanics::diseaseContact(victim, ptr); @@ -726,7 +726,7 @@ namespace MWClass if(name == "left") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return 2; if(world->isOnGround(ptr)) @@ -736,7 +736,7 @@ namespace MWClass if(name == "right") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return 3; if(world->isOnGround(ptr)) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 791c2f57e2..4307fe9be0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -493,7 +493,7 @@ namespace MWClass // TODO: Use second to work out the hit angle std::pair result = world->getHitContact(ptr, dist); MWWorld::Ptr victim = result.first; - Ogre::Vector3 hitPosition (result.second.x(), result.second.y(), result.second.z()); + osg::Vec3f hitPosition (result.second); if(victim.isEmpty()) // Didn't hit anything return; @@ -583,7 +583,7 @@ namespace MWClass damage = 0; if (healthdmg && damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); MWMechanics::diseaseContact(victim, ptr); @@ -1138,7 +1138,7 @@ namespace MWClass if(name == "left" || name == "right") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isSwimming(ptr)) return (name == "left") ? "Swim Left" : "Swim Right"; if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) @@ -1175,7 +1175,7 @@ namespace MWClass if(name == "land") { MWBase::World *world = MWBase::Environment::get().getWorld(); - Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return "DefaultLandWater"; if(world->isOnGround(ptr)) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 88b0bd3211..1182de1515 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1623,6 +1623,9 @@ namespace MWGui void WindowManager::clear() { + if (mLocalMapRender) + mLocalMapRender->clear(); + mMap->clear(); mQuickKeysMenu->clear(); mMessageBoxManager->clear(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 84e97487a2..81dbca58ab 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -809,7 +809,7 @@ namespace MWMechanics NpcStats &stats = ptr.getClass().getNpcStats(ptr); MWBase::World *world = MWBase::Environment::get().getWorld(); - bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), Ogre::Vector3(ptr.getRefData().getPosition().pos))); + bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); if((world->isSubmerged(ptr) || knockedOutUnderwater) && stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0) { @@ -1385,11 +1385,11 @@ namespace MWMechanics return false; } - void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out) + void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) + if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius) out.push_back(iter->first); } } @@ -1457,7 +1457,7 @@ namespace MWMechanics std::list Actors::getActorsFighting(const MWWorld::Ptr& actor) { std::list list; std::vector neighbors; - Ogre::Vector3 position = Ogre::Vector3(actor.getRefData().getPosition().pos); + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); getObjectsInRange(position, MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(), neighbors); //only care about those within the alarm disance diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 70f1b47d91..f9e58ab4fe 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -114,7 +114,7 @@ namespace MWMechanics void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); - void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out); + void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); ///Returns the list of actors which are following the given actor /**ie AiFollow is active and the target is the actor **/ diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 9ec5bc19a0..83f9dffb47 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -64,7 +64,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat // Make all nearby actors also avoid the door std::vector actors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),100,actors); + MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence(); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index ee48d124f0..b013dbb1b7 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -28,7 +28,7 @@ float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg: return std::atan2((normal * (v1 ^ v2)), (v1 * v2)); } -bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition) +bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition) { std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : ""; if (!enchantmentName.empty()) @@ -166,7 +166,7 @@ namespace MWMechanics } void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile, - const Ogre::Vector3& hitPosition) + const osg::Vec3f& hitPosition) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &gmst = world->getStore().get(); @@ -221,7 +221,7 @@ namespace MWMechanics appliedEnchantment = applyEnchantment(attacker, victim, projectile, hitPosition); if (damage > 0) - MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, osg::Vec3f(hitPosition.x, hitPosition.y, hitPosition.z)); + MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index a2fd8b0067..0a31a1a7e3 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -15,7 +15,7 @@ void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, - const Ogre::Vector3& hitPosition); + const osg::Vec3f& hitPosition); /// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0ae9395c5d..8fbb31fb7b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1059,14 +1059,14 @@ namespace MWMechanics // Find all the actors within the alarm radius std::vector neighbors; - Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); + osg::Vec3f from (player.getRefData().getPosition().asVec3()); const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius - if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) + if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); // Did anyone see it? @@ -1149,13 +1149,13 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - Ogre::Vector3 from = Ogre::Vector3(player.getRefData().getPosition().pos); + osg::Vec3f from (player.getRefData().getPosition().asVec3()); float radius = esmStore.get().find("fAlarmRadius")->getFloat(); mActors.getObjectsInRange(from, radius, neighbors); // victim should be considered even beyond alarm radius - if (!victim.isEmpty() && from.squaredDistance(Ogre::Vector3(victim.getRefData().getPosition().pos)) > radius*radius) + if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId(); @@ -1430,13 +1430,13 @@ namespace MWMechanics MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); } - void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) + void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector &objects) { mActors.getObjectsInRange(position, radius, objects); mObjects.getObjectsInRange(position, radius, objects); } - void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) + void MechanicsManager::getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) { mActors.getObjectsInRange(position, radius, objects); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d08334ae8c..f695ec57a8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -145,8 +145,8 @@ namespace MWMechanics /// paused we may want to do it manually (after equipping permanent enchantment) virtual void updateMagicEffects (const MWWorld::Ptr& ptr); - virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects); - virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects); + virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); + virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index ba35af777d..d6f5da88d2 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -92,11 +92,11 @@ void Objects::skipAnimation(const MWWorld::Ptr& ptr) iter->second->skipAnim(); } -void Objects::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out) +void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) + if ((position - iter->first.getRefData().getPosition().asVec3()).length2() <= radius*radius) out.push_back(iter->first); } } diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 373a2a1056..6e22c0582b 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -41,7 +41,7 @@ namespace MWMechanics void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); - void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& out); + void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); }; } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8965d3b0d5..cdca6eeaad 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -779,7 +779,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, false, enchantment->mEffects, mCaster, mSourceName, // Not needed, enchantments can only be cast by actors - Ogre::Vector3(1,0,0)); + osg::Vec3f(1,0,0)); return true; } @@ -861,13 +861,13 @@ namespace MWMechanics getProjectileInfo(spell->mEffects, projectileModel, sound, speed); if (!projectileModel.empty()) { - Ogre::Vector3 fallbackDirection (0,1,0); + osg::Vec3f fallbackDirection (0,1,0); // Fall back to a "caster to target" direction if we have no other means of determining it // (e.g. when cast by a non-actor) if (!mTarget.isEmpty()) fallbackDirection = - Ogre::Vector3(mTarget.getRefData().getPosition().pos)- - Ogre::Vector3(mCaster.getRefData().getPosition().pos); + osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- + osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, false, spell->mEffects, mCaster, mSourceName, fallbackDirection); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index f50584edf2..4241c9e3e3 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -71,7 +71,7 @@ namespace MWMechanics bool mStack; std::string mId; // ID of spell, potion, item etc std::string mSourceName; // Display name for spell, potion, etc - Ogre::Vector3 mHitPosition; // Used for spawning area orb + osg::Vec3f mHitPosition; // Used for spawning area orb bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false) public: diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c0e7a80b9d..f97c5fd138 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -748,7 +748,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask) + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -762,7 +762,7 @@ namespace MWPhysics } ClosestNotMeRayResultCallback resultCallback(me, btFrom, btTo); - resultCallback.m_collisionFilterGroup = 0xff; + resultCallback.m_collisionFilterGroup = group; resultCallback.m_collisionFilterMask = mask; mCollisionWorld->rayTest(btFrom, btTo, resultCallback); @@ -860,6 +860,15 @@ namespace MWPhysics } } + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if (physactor) + return physactor->getHalfExtents(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: @@ -1128,7 +1137,7 @@ namespace MWPhysics if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() && cell->getCell()->hasWater() && !world->isUnderwater(iter->first.getCell(), - Ogre::Vector3(iter->first.getRefData().getPosition().pos))) + osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) waterCollision = true; ActorMap::iterator foundActor = mActors.find(iter->first); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index d4f7e25b10..7e3c279515 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -99,7 +99,7 @@ namespace MWPhysics /// @param me Optional, a Ptr to ignore in the list of results RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff); RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); @@ -108,6 +108,8 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index efdb49cf7f..8580eb8f88 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -937,7 +937,7 @@ namespace MWScript MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false); MWMechanics::CastSpell cast(ptr, target); - cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos); + cast.mHitPosition = target.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } @@ -955,7 +955,7 @@ namespace MWScript runtime.pop(); MWMechanics::CastSpell cast(ptr, ptr); - cast.mHitPosition = Ogre::Vector3(ptr.getRefData().getPosition().pos); + cast.mHitPosition = ptr.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index d153b7e618..68d7c69e9f 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -9,8 +9,8 @@ namespace MWWorld void ActionTrap::executeImp(const Ptr &actor) { - Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); - Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); + osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3()); float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); // GUI calcs if object in activation distance include object and player geometry @@ -20,7 +20,7 @@ namespace MWWorld // to open door/container. // Note, can't just detonate the trap at the trapped object's location and use the blast // radius, because for most trap spells this is 1 foot, much less than the activation distance. - if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + if ((trapPosition - actorPosition).length() < (activationDistance * fudgeFactor)) { // assume actor touched trap MWMechanics::CastSpell cast(mTrapSource, actor); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index acbe819f1e..84d86fba74 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,11 +1,11 @@ #include "projectilemanager.hpp" -#include -#include - -#include +#include #include +#include +#include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -22,72 +22,70 @@ #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/renderconst.hpp" +#include "../mwrender/vismask.hpp" #include "../mwsound/sound.hpp" +#include "../mwphysics/physicssystem.hpp" + + namespace MWWorld { - ProjectileManager::ProjectileManager(Ogre::SceneManager* sceneMgr, OEngine::Physic::PhysicEngine &engine) - : mPhysEngine(engine) - , mSceneMgr(sceneMgr) + ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, MWPhysics::PhysicsSystem* physics) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mPhysics(physics) { } void ProjectileManager::createModel(State &state, const std::string &model) { - state.mObject = NifOgre::Loader::createObjects(state.mNode, model); - for(size_t i = 0;i < state.mObject->mControllers.size();i++) - { - if(state.mObject->mControllers[i].getSource().isNull()) - state.mObject->mControllers[i].setSource(Ogre::SharedPtr (new MWRender::EffectAnimationTime())); - } + state.mNode = new osg::PositionAttitudeTransform; + state.mNode->setNodeMask(MWRender::Mask_Effect); + mParent->addChild(state.mNode); - MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Effects, - MWRender::RQG_Main, MWRender::RQG_Alpha, 0.f, false, NULL); + mResourceSystem->getSceneManager()->createInstance(model, state.mNode); + + state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); + + SceneUtil::AssignControllerSourcesVisitor assignVisitor (state.mEffectAnimationTime); + state.mNode->accept(assignVisitor); } - void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration) + void ProjectileManager::update(State& state, float duration) { - for(size_t i = 0; i < object->mControllers.size() ;i++) - { - MWRender::EffectAnimationTime* value = dynamic_cast(object->mControllers[i].getSource().get()); - if (value) - value->addTime(duration); - - object->mControllers[i].update(); - } + state.mEffectAnimationTime->addTime(duration); } void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, - const Ogre::Vector3& fallbackDirection) + const osg::Vec3f& fallbackDirection) { float height = 0; - if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle())) - height = actor->getHalfExtents().z * 2 * 0.75f; // Spawn at 0.75 * ActorHeight - Ogre::Vector3 pos(caster.getRefData().getPosition().pos); - pos.z += height; + height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight + + osg::Vec3f pos(caster.getRefData().getPosition().asVec3()); + pos.z() += height; if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; - Ogre::Quaternion orient; + osg::Quat orient; if (caster.getClass().isActor()) - orient = Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * - Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X); + orient = osg::Quat(caster.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(caster.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); else - orient = Ogre::Vector3::UNIT_Y.getRotationTo(fallbackDirection); + orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection)); MagicBoltState state; state.mSourceName = sourceName; state.mId = model; state.mSpellId = spellId; - state.mCasterHandle = caster.getRefData().getHandle(); + state.mCasterHandle = caster; if (caster.getClass().isActor()) state.mActorId = caster.getClass().getCreatureStats(caster).getActorId(); else @@ -107,8 +105,9 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient); createModel(state, ptr.getClass().getModel(ptr)); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -116,20 +115,21 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const Ogre::Vector3 &pos, - const Ogre::Quaternion &orient, Ptr bow, float speed) + void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); state.mBowId = bow.getCellRef().getRefId(); - state.mVelocity = orient.yAxis() * speed; + state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); + state.mCasterHandle = actor; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient); createModel(state, ptr.getClass().getModel(ptr)); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); mProjectiles.push_back(state); } @@ -144,60 +144,46 @@ namespace MWWorld { for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) { - Ogre::Quaternion orient = it->mNode->getOrientation(); + osg::Quat orient = it->mNode->getAttitude(); static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() .find("fTargetSpellMaxSpeed")->getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; - Ogre::Vector3 direction = orient.yAxis(); - direction.normalise(); - Ogre::Vector3 pos(it->mNode->getPosition()); - Ogre::Vector3 newPos = pos + direction * duration * speed; + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + direction.normalize(); + osg::Vec3f pos(it->mNode->getPosition()); + osg::Vec3f newPos = pos + direction * duration * speed; if (it->mSound.get()) it->mSound->setPosition(newPos); it->mNode->setPosition(newPos); - update(it->mObject, duration); + update(*it, duration); + + MWWorld::Ptr caster = it->getCaster(); // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - btVector3 from(pos.x, pos.y, pos.z); - btVector3 to(newPos.x, newPos.y, newPos.z); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - std::vector > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile); - bool hit=false; - - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) + bool hit = false; + if (result.mHit) { - MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second); - - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->mCasterHandle); - if (caster.isEmpty()) - caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); - - if (!obstacle.isEmpty() && obstacle == caster) - continue; - - if (caster.isEmpty()) - caster = obstacle; - - if (obstacle.isEmpty()) + hit = true; + if (result.mHitObject.isEmpty()) { - // Terrain + // terrain } else { - MWMechanics::CastSpell cast(caster, obstacle); + MWMechanics::CastSpell cast(caster, result.mHitObject); cast.mHitPosition = pos; cast.mId = it->mSpellId; cast.mSourceName = it->mSourceName; cast.mStack = it->mStack; - cast.inflict(obstacle, caster, it->mEffects, ESM::RT_Target, false, true); + cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true); } - - hit = true; } // Explodes when hitting water @@ -206,12 +192,11 @@ namespace MWWorld if (hit) { - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); continue; @@ -227,34 +212,26 @@ namespace MWWorld { // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all - it->mVelocity -= Ogre::Vector3(0, 0, 627.2f * 0.1f) * duration; + it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; - Ogre::Vector3 pos(it->mNode->getPosition()); - Ogre::Vector3 newPos = pos + it->mVelocity * duration; + osg::Vec3f pos(it->mNode->getPosition()); + osg::Vec3f newPos = pos + it->mVelocity * duration; - Ogre::Quaternion orient = Ogre::Vector3::UNIT_Y.getRotationTo(it->mVelocity); - it->mNode->setOrientation(orient); + osg::Quat orient; + orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); - update(it->mObject, duration); + update(*it, duration); + + MWWorld::Ptr caster = it->getCaster(); // Check for impact // TODO: use a proper btRigidBody / btGhostObject? - btVector3 from(pos.x, pos.y, pos.z); - btVector3 to(newPos.x, newPos.y, newPos.z); - std::vector > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile); - bool hit=false; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - for (std::vector >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) + if (result.mHit) { - MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second); - - MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); - - // Arrow intersects with player immediately after shooting :/ - if (obstacle == caster) - continue; - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); // Try to get a Ptr to the bow that was used. It might no longer exist. @@ -268,15 +245,11 @@ namespace MWWorld } if (caster.isEmpty()) - caster = obstacle; + caster = result.mHitObject; - MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first); + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos); - hit = true; - } - if (hit) - { - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); it = mProjectiles.erase(it); continue; @@ -290,13 +263,13 @@ namespace MWWorld { for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it) { - mSceneMgr->destroySceneNode(it->mNode); + mParent->removeChild(it->mNode); } mProjectiles.clear(); for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { + mParent->removeChild(it->mNode); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - mSceneMgr->destroySceneNode(it->mNode); } mMagicBolts.clear(); } @@ -309,8 +282,8 @@ namespace MWWorld ESM::ProjectileState state; state.mId = it->mId; - state.mPosition = it->mNode->getPosition(); - state.mOrientation = it->mNode->getOrientation(); + state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); + state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; state.mBowId = it->mBowId; @@ -327,8 +300,8 @@ namespace MWWorld ESM::MagicBoltState state; state.mId = it->mId; - state.mPosition = it->mNode->getPosition(); - state.mOrientation = it->mNode->getOrientation(); + state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); + state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; state.mSpellId = it->mSpellId; @@ -369,8 +342,9 @@ namespace MWWorld return true; } - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation); createModel(state, model); + state.mNode->setPosition(osg::Vec3f(esm.mPosition)); + state.mNode->setAttitude(osg::Quat(esm.mOrientation)); mProjectiles.push_back(state); return true; @@ -401,8 +375,9 @@ namespace MWWorld return true; } - state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation); createModel(state, model); + state.mNode->setPosition(osg::Vec3f(esm.mPosition)); + state.mNode->setAttitude(osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, @@ -421,4 +396,12 @@ namespace MWWorld return mMagicBolts.size() + mProjectiles.size(); } + MWWorld::Ptr ProjectileManager::State::getCaster() + { + if (!mCasterHandle.isEmpty()) + return mCasterHandle; + + return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); + } + } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f46f544d28..f42bc040f8 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include @@ -21,9 +21,20 @@ namespace Loading class Listener; } -namespace Ogre +namespace osg { - class SceneManager; + class Group; + class Quat; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWRender +{ + class EffectAnimationTime; } namespace MWWorld @@ -32,16 +43,16 @@ namespace MWWorld class ProjectileManager { public: - ProjectileManager (Ogre::SceneManager* sceneMgr, - OEngine::Physic::PhysicEngine& engine); + ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem, + MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const Ogre::Vector3& pos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); void update(float dt); @@ -53,22 +64,22 @@ namespace MWWorld int countSavedGameRecords() const; private: - OEngine::Physic::PhysicEngine& mPhysEngine; - Ogre::SceneManager* mSceneMgr; + osg::ref_ptr mParent; + Resource::ResourceSystem* mResourceSystem; + MWPhysics::PhysicsSystem* mPhysics; struct State { - NifOgre::ObjectScenePtr mObject; - Ogre::SceneNode* mNode; + osg::ref_ptr mNode; + boost::shared_ptr mEffectAnimationTime; int mActorId; - // actorId doesn't work for non-actors, so we also keep track of the Ogre-handle. - // For non-actors, the caster ptr is mainly needed to prevent the projectile - // from colliding with its caster. // TODO: this will break when the game is saved and reloaded, since there is currently // no way to write identifiers for non-actors to a savegame. - std::string mCasterHandle; + MWWorld::Ptr mCasterHandle; + + MWWorld::Ptr getCaster(); // MW-id of this projectile std::string mId; @@ -96,7 +107,7 @@ namespace MWWorld // RefID of the bow or crossbow the actor was using when this projectile was fired (may be empty) std::string mBowId; - Ogre::Vector3 mVelocity; + osg::Vec3f mVelocity; }; std::vector mMagicBolts; @@ -106,7 +117,7 @@ namespace MWWorld void moveMagicBolts(float dt); void createModel (State& state, const std::string& model); - void update (NifOgre::ObjectScenePtr object, float duration); + void update (State& state, float duration); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2f47c19e60..126267fd46 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,7 +54,7 @@ #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" -//#include "projectilemanager.hpp" +#include "projectilemanager.hpp" #include "weather.hpp" #include "contentloader.hpp" @@ -159,9 +159,7 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); -#if 0 - mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); -#endif + mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); @@ -276,9 +274,7 @@ namespace MWWorld { mWeatherManager->clear(); mRendering->clear(); -#if 0 mProjectileManager->clear(); -#endif mLocalScripts.clear(); mWorldScene->changeToVoid(); @@ -313,9 +309,7 @@ namespace MWWorld mCells.countSavedGameRecords() +mStore.countSavedGameRecords() +mGlobalVariables.countSavedGameRecords() - #if 0 +mProjectileManager->countSavedGameRecords() - #endif +1 // player record +1 // weather record +1 // actorId counter @@ -346,9 +340,8 @@ namespace MWWorld mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); mWeatherManager->write (writer, progress); -#if 0 mProjectileManager->write (writer, progress); -#endif + writer.startRecord(ESM::REC_ENAB); writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); @@ -377,9 +370,7 @@ namespace MWWorld !mPlayer->readRecord (reader, type) && !mWeatherManager->readRecord (reader, type) && !mCells.readRecord (reader, type, contentFileMap) - #if 0 && !mProjectileManager->readRecord (reader, type) - #endif ) { throw std::runtime_error ("unknown record in saved game"); @@ -472,10 +463,8 @@ namespace MWWorld World::~World() { -#if 0 // Must be cleared before mRendering is destroyed mProjectileManager->clear(); -#endif delete mWeatherManager; delete mWorldScene; delete mRendering; @@ -970,9 +959,7 @@ namespace MWWorld if (mCurrentWorldSpace != cellName) { // changed worldspace -#if 0 mProjectileManager->clear(); -#endif mRendering->notifyWorldSpaceChanged(); mCurrentWorldSpace = cellName; @@ -990,9 +977,7 @@ namespace MWWorld if (mCurrentWorldSpace != "sys::default") // FIXME { // changed worldspace -#if 0 mProjectileManager->clear(); -#endif mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); @@ -1388,7 +1373,7 @@ namespace MWWorld mPhysics->stepSimulation(duration); processDoors(duration); - //mProjectileManager->update(duration); + mProjectileManager->update(duration); const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); MWPhysics::PtrVelocityList::const_iterator player(results.end()); @@ -1637,9 +1622,7 @@ namespace MWWorld const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); osg::Vec3f playerPos = refpos.asVec3(); - const MWPhysics::Actor* actor = mPhysics->getActor(getPlayerPtr()); - if (actor) - playerPos.z() += 1.85f * actor->getHalfExtents().z(); + playerPos.z() += 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z(); osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * @@ -2015,24 +1998,19 @@ namespace MWWorld bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { - const float *fpos = object.getRefData().getPosition().pos; - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); + osg::Vec3f pos (object.getRefData().getPosition().asVec3()); - const MWPhysics::Actor* actor = mPhysics->getActor(object); - if (actor) - { - pos.z += heightRatio*2*actor->getHalfExtents().z(); - } + pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z(); return isUnderwater(object.getCell(), pos); } - bool World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const + bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const { if (!(cell->getCell()->mData.mFlags & ESM::Cell::HasWater)) { return false; } - return pos.z < cell->getWaterLevel(); + return pos.z() < cell->getWaterLevel(); } bool World::isOnGround(const MWWorld::Ptr &ptr) const @@ -2125,7 +2103,7 @@ namespace MWWorld Ptr player = mPlayer->getPlayer(); RefData &refdata = player.getRefData(); - Ogre::Vector3 playerPos(refdata.getPosition().pos); + osg::Vec3f playerPos(refdata.getPosition().asVec3()); const MWPhysics::Actor* actor = mPhysics->getActor(player); if (!actor) @@ -2519,7 +2497,7 @@ namespace MWWorld // Witnesses of the player's transformation will make them a globally known werewolf std::vector closeActors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(actor.getRefData().getPosition().pos), + MWBase::Environment::get().getMechanicsManager()->getActorsInRange(actor.getRefData().getPosition().asVec3(), getStore().get().search("fAlarmRadius")->getFloat(), closeActors); @@ -2695,7 +2673,7 @@ namespace MWWorld MWMechanics::CastSpell cast(actor, target); if (!target.isEmpty()) - cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos); + cast.mHitPosition = target.getRefData().getPosition().asVec3(); if (!selectedSpell.empty()) { @@ -2718,18 +2696,14 @@ namespace MWWorld void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) { -#if 0 mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); -#endif } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) { -#if 0 mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection); -#endif } const std::vector& World::getContentFiles() const @@ -3181,7 +3155,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Ogre::Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, + void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3200,7 +3174,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", osg::Vec3f(origin.x, origin.y, origin.z), static_cast(effectIt->mArea)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3209,9 +3183,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); else - sndMgr->playManualSound3D(osg::Vec3f(origin.x, origin.y, origin.z), schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); } // Get the actors in range of the effect std::vector objects; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b1718f0304..4c4df2c995 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -455,7 +455,7 @@ namespace MWWorld ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; @@ -572,7 +572,7 @@ namespace MWWorld virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection); + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); @@ -613,7 +613,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); - virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 51cd5d8c40..38429e4595 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -3,8 +3,8 @@ #include -#include -#include +#include +#include #include "effectlist.hpp" diff --git a/components/esm/util.hpp b/components/esm/util.hpp index bb7f3cf7cd..07a7655c74 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -4,6 +4,9 @@ #include #include +#include +#include + namespace ESM { @@ -21,11 +24,23 @@ struct Quaternion mValues[2] = q.y; mValues[3] = q.z; } + Quaternion(const osg::Quat& q) + { + mValues[0] = q.w(); + mValues[1] = q.x(); + mValues[2] = q.y(); + mValues[3] = q.z(); + } operator Ogre::Quaternion () const { return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); } + + operator osg::Quat () const + { + return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); + } }; struct Vector3 @@ -39,11 +54,22 @@ struct Vector3 mValues[1] = v.y; mValues[2] = v.z; } + Vector3(const osg::Vec3f& v) + { + mValues[0] = v.x(); + mValues[1] = v.y(); + mValues[2] = v.z(); + } operator Ogre::Vector3 () const { return Ogre::Vector3(&mValues[0]); } + + operator osg::Vec3f () const + { + return osg::Vec3f(mValues[0], mValues[1], mValues[2]); + } }; } From 01944c33f5a28eb2c64188f9e9259c0cf3b9b780 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 16:35:35 +0200 Subject: [PATCH 0359/1812] Basic water rendering --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/refraction.cpp | 110 ---- apps/openmw/mwrender/refraction.hpp | 45 -- apps/openmw/mwrender/renderingmanager.cpp | 63 ++- apps/openmw/mwrender/renderingmanager.hpp | 8 + apps/openmw/mwrender/rendermode.hpp | 4 +- apps/openmw/mwrender/vismask.hpp | 7 +- apps/openmw/mwrender/water.cpp | 581 +++++----------------- apps/openmw/mwrender/water.hpp | 171 +------ apps/openmw/mwworld/scene.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 6 +- components/nifosg/controller.cpp | 7 + components/nifosg/controller.hpp | 1 + components/sceneutil/controller.cpp | 5 +- 15 files changed, 250 insertions(+), 768 deletions(-) delete mode 100644 apps/openmw/mwrender/refraction.cpp delete mode 100644 apps/openmw/mwrender/refraction.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c46a831837..015d0db9ab 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap -# occlusionquery water shadows ripplesimulation refraction terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water +# occlusionquery shadows ripplesimulation refraction terrainstorage ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index edc88ac559..3003e47366 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -157,7 +157,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(MWRender::Mask_Scene); + camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp deleted file mode 100644 index 739ed24d9f..0000000000 --- a/apps/openmw/mwrender/refraction.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "refraction.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "renderconst.hpp" - -namespace MWRender -{ - - Refraction::Refraction(Ogre::Camera *parentCamera) - : mParentCamera(parentCamera) - , mRenderActive(false) - , mIsUnderwater(false) - { - mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); - - mParentCamera->getSceneManager()->addRenderQueueListener(this); - - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - mRenderTarget = texture->getBuffer()->getRenderTarget(); - Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Refraction); - vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); - mRenderTarget->setAutoUpdated(true); - mRenderTarget->addListener(this); - } - - Refraction::~Refraction() - { - mRenderTarget->removeListener(this); - Ogre::TextureManager::getSingleton().remove("WaterRefraction"); - mParentCamera->getSceneManager()->destroyCamera(mCamera); - mParentCamera->getSceneManager()->removeRenderQueueListener(this); - } - - void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - - mRenderActive = true; - } - - void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - mCamera->disableCustomNearClipPlane (); - mRenderActive = false; - } - - void Refraction::setHeight(float height) - { - mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,0,1), -(height + 5)); - mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,0,1), height - 5); - } - - void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) - { - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mRenderActive) - { - mCamera->disableCustomNearClipPlane(); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) - { - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::setActive(bool active) - { - mRenderTarget->setActive(active); - } - -} diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp deleted file mode 100644 index b9ab8deac2..0000000000 --- a/apps/openmw/mwrender/refraction.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MWRENDER_REFRACTION_H -#define MWRENDER_REFRACTION_H - -#include -#include -#include - -namespace Ogre -{ - class Camera; - class RenderTarget; -} - -namespace MWRender -{ - - class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener - { - - public: - Refraction(Ogre::Camera* parentCamera); - ~Refraction(); - - void setHeight (float height); - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void setUnderwater(bool underwater) {mIsUnderwater = underwater;} - void setActive (bool active); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - - private: - Ogre::Camera* mParentCamera; - Ogre::Camera* mCamera; - Ogre::RenderTarget* mRenderTarget; - Ogre::Plane mNearClipPlane; - Ogre::Plane mNearClipPlaneUnderwater; - bool mRenderActive; - bool mIsUnderwater; - }; - -} - -#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 31ff9b02b3..a708bbe88c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include "vismask.hpp" #include "pathgrid.hpp" #include "camera.hpp" +#include "water.hpp" namespace MWRender { @@ -129,7 +130,9 @@ namespace MWRender mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); - mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); + + mWater.reset(new Water(lightRoot, mResourceSystem)); mCamera.reset(new Camera(mViewer->getCamera())); @@ -177,6 +180,7 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); + mStateUpdater->setFogEnd(mViewDistance); } RenderingManager::~RenderingManager() @@ -230,6 +234,8 @@ namespace MWRender void RenderingManager::addCell(const MWWorld::CellStore *store) { mPathgrid->addCell(store); + + mWater->changeCell(store); } void RenderingManager::removeCell(const MWWorld::CellStore *store) @@ -253,6 +259,22 @@ namespace MWRender mStateUpdater->setWireframe(wireframe); return wireframe; } + else if (mode == Render_Water) + { + return mWater->toggle(); + } + else if (mode == Render_Scene) + { + int mask = mViewer->getCamera()->getCullMask(); + bool enabled = mask&Mask_Scene; + enabled = !enabled; + if (enabled) + mask |= Mask_Scene; + else + mask &= ~Mask_Scene; + mViewer->getCamera()->setCullMask(mask); + return enabled; + } /* else //if (mode == Render_BoundingBoxes) { @@ -271,12 +293,9 @@ namespace MWRender configureFog (cell->mAmbi.mFogDensity, color); } - void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) + void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color) { - mViewer->getCamera()->setClearColor(colour); - - mStateUpdater->setFogColor(colour); - mStateUpdater->setFogEnd(mViewDistance); + mFogColor = color; } SkyManager* RenderingManager::getSkyManager() @@ -289,6 +308,19 @@ namespace MWRender mEffectManager->update(dt); mSky->update(dt); mCamera->update(dt, paused); + + osg::Vec3f focal, cameraPos; + mCamera->getPosition(focal, cameraPos); + if (mWater->isUnderwater(cameraPos)) + { + setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); + mStateUpdater->setFogEnd(1000); + } + else + { + setFogColor(mFogColor); + mStateUpdater->setFogEnd(mViewDistance); + } } void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) @@ -325,6 +357,16 @@ namespace MWRender mObjects->removeObject(ptr); } + void RenderingManager::setWaterEnabled(bool enabled) + { + mWater->setEnabled(enabled); + } + + void RenderingManager::setWaterHeight(float height) + { + mWater->setHeight(height); + } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) { osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); @@ -390,7 +432,7 @@ namespace MWRender osgUtil::IntersectionVisitor intersectionVisitor(intersector); int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); if (ignorePlayer) mask &= ~(Mask_Player); @@ -521,6 +563,13 @@ namespace MWRender mViewer->startThreading(); } + void RenderingManager::setFogColor(const osg::Vec4f &color) + { + mViewer->getCamera()->setClearColor(color); + + mStateUpdater->setFogColor(color); + } + void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 57a2df60e5..d90a75c865 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -42,6 +42,7 @@ namespace MWRender class NpcAnimation; class Pathgrid; class Camera; + class Water; class RenderingManager : public MWRender::RenderingInterface { @@ -73,6 +74,9 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + void setWaterEnabled(bool enabled); + void setWaterHeight(float level); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); @@ -131,6 +135,7 @@ namespace MWRender private: void updateProjectionMatrix(); void updateTextureFiltering(); + void setFogColor(const osg::Vec4f& color); osg::ref_ptr mViewer; osg::ref_ptr mRootNode; @@ -141,6 +146,7 @@ namespace MWRender std::auto_ptr mPathgrid; std::auto_ptr mObjects; + std::auto_ptr mWater; std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; @@ -149,6 +155,8 @@ namespace MWRender osg::ref_ptr mStateUpdater; + osg::Vec4f mFogColor; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp index a74d9bd526..ba767bc55b 100644 --- a/apps/openmw/mwrender/rendermode.hpp +++ b/apps/openmw/mwrender/rendermode.hpp @@ -9,7 +9,9 @@ namespace MWRender Render_CollisionDebug, Render_Wireframe, Render_Pathgrid, - Render_BoundingBoxes + Render_BoundingBoxes, + Render_Water, + Render_Scene }; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index c9ac35c67c..3a0336f822 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,13 +15,14 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), + Mask_Water = (1<<6), // top level masks - Mask_Scene = (1<<6), - Mask_GUI = (1<<7), + Mask_Scene = (1<<7), + Mask_GUI = (1<<8), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<8) + Mask_RenderToTexture = (1<<9) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f2175ced57..2dd843e4ed 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,327 +1,164 @@ #include "water.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -#include "sky.hpp" -#include "renderingmanager.hpp" -#include "ripplesimulation.hpp" -#include "refraction.hpp" +#include +#include +#include +#include +#include +#include -#include -#include +#include +#include -using namespace Ogre; +#include +#include + +#include "vismask.hpp" + +namespace +{ + + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) + { + osg::ref_ptr verts (new osg::Vec3Array); + osg::ref_ptr texcoords (new osg::Vec2Array); + + // some drivers don't like huge triangles, so we do some subdivisons + // a paged solution would be even better + const float step = size/segments; + const float texCoordStep = textureRepeats / segments; + for (int x=0; xpush_back(osg::Vec3f(x1, y2, 0.f)); + verts->push_back(osg::Vec3f(x1, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y2, 0.f)); + + float u1 = x*texCoordStep; + float v1 = y*texCoordStep; + float u2 = u1 + texCoordStep; + float v2 = v1 + texCoordStep; + + texcoords->push_back(osg::Vec2f(u1, v2)); + texcoords->push_back(osg::Vec2f(u1, v1)); + texcoords->push_back(osg::Vec2f(u2, v1)); + texcoords->push_back(osg::Vec2f(u2, v2)); + } + } + + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); + + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } + + void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); + + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(9, "RenderBin"); + + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); + } + +} namespace MWRender { -CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager) - : Reflection(sceneManager) -{ - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP, - 512,512, 0, PF_R8G8B8, TU_RENDERTARGET); - - mCamera = mSceneMgr->createCamera ("CubeCamera"); - mCamera->setNearClipDistance (5); - mCamera->setFarClipDistance (1000); - - for (int face = 0; face < 6; ++face) - { - mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget(); - mRenderTargets[face]->removeAllViewports (); - Viewport* vp = mRenderTargets[face]->addViewport (mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setMaterialScheme ("water_reflection"); - mRenderTargets[face]->setAutoUpdated(false); - - /* - Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0); - switch(face) - { - case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X - case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X - case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y - case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y - case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z - case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z - } - Quaternion orient(right, up, lookAt); - mCamera->setOrientation(orient); - */ - } -} - -CubeReflection::~CubeReflection () -{ - Ogre::TextureManager::getSingleton ().remove("CubeReflection"); - mSceneMgr->destroyCamera (mCamera); -} - -void CubeReflection::update () -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setPosition(mParentCamera->getDerivedPosition()); -} - // -------------------------------------------------------------------------------------------------------------------------------- -PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) - : Reflection(sceneManager) - , mSky(sky) - , mRenderActive(false) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mEnabled(true) + , mToggled(true) + , mTop(0) { - mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); - mSceneMgr->addRenderQueueListener(this); + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); - mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(waterGeom); + geode->setNodeMask(Mask_Water); - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - vp->setMaterialScheme("water_reflection"); - mRenderTarget->addListener(this); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated(true); + createWaterStateSet(mResourceSystem, geode); - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); -} + mWaterNode = new osg::PositionAttitudeTransform; + mWaterNode->addChild(geode); -PlaneReflection::~PlaneReflection () -{ - mRenderTarget->removeListener (this); - mSceneMgr->destroyCamera (mCamera); - mSceneMgr->removeRenderQueueListener(this); - TextureManager::getSingleton ().remove("WaterReflection"); -} - -void PlaneReflection::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) -{ - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mRenderActive) - { - mCamera->disableCustomNearClipPlane(); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) -{ - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - mRenderActive = true; - - mCamera->enableReflection(mWaterPlane); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); -} - -void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - mCamera->disableReflection(); - mCamera->disableCustomNearClipPlane(); - mRenderActive = false; -} - -void PlaneReflection::setHeight (float height) -{ - mWaterPlane = Plane(Ogre::Vector3(0,0,1), height); - mErrorPlane = Plane(Ogre::Vector3(0,0,1), height - 5); - mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,0,-1), -height - 5); -} - -void PlaneReflection::setActive (bool active) -{ - mRenderTarget->setActive(active); -} - -void PlaneReflection::setViewportBackground(Ogre::ColourValue colour) -{ - mRenderTarget->getViewport (0)->setBackgroundColour (colour); -} - -void PlaneReflection::setVisibilityMask (int flags) -{ - mRenderTarget->getViewport (0)->setVisibilityMask (flags); -} - -// -------------------------------------------------------------------------------------------------------------------------------- - -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : - mCamera (camera), mSceneMgr (camera->getSceneManager()), - mIsUnderwater(false), mActive(1), - mToggled(1), mWaterTimer(0.f), - mRendering(rend), - mVisibilityFlags(0), - mReflection(NULL), - mRefraction(NULL), - mSimulation(NULL), - mPlayer(0,0) -{ - mSimulation = new RippleSimulation(mSceneMgr, fallback); - - mSky = rend->getSkyManager(); - - mMaterial = MaterialManager::getSingleton().getByName("Water"); - - mTop = 0; - - mIsUnderwater = false; - - mWaterPlane = Plane(Vector3::UNIT_Z, 0); - - int waterScale = 30; - - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), - 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); - - mWater = mSceneMgr->createEntity("water"); - mWater->setVisibilityFlags(RV_Water); - mWater->setCastShadows(false); - mWater->setRenderQueueGroup(RQG_Alpha); - - mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - - mWaterNode->attachObject(mWater); - - applyRTT(); - applyVisibilityMask(); - - mWater->setMaterial(mMaterial); + mParent->addChild(mWaterNode); 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"))) - mgr.destroy(overlay); - - overlay = mgr.create("ReflectionDebugOverlay"); - - if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) - MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/ReflectionDebugTexture", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName()); - - OverlayContainer* debugPanel; - - // destroy container if exists - try - { - if ((debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" - )))) - mgr.destroyOverlayElement(debugPanel); - } - catch (Ogre::Exception&) {} - - debugPanel = (OverlayContainer*) - (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel")); - debugPanel->_setPosition(0, 0.55); - debugPanel->_setDimensions(0.3, 0.3); - debugPanel->setMaterialName(debugMat->getName()); - debugPanel->show(); - 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.0f : 0.0f))); } Water::~Water() { - MeshManager::getSingleton().remove("water"); - - mWaterNode->detachObject(mWater); - mSceneMgr->destroyEntity(mWater); - mSceneMgr->destroySceneNode(mWaterNode); - - delete mReflection; - delete mRefraction; - delete mSimulation; + mParent->removeChild(mWaterNode); } -void Water::changeCell(const ESM::Cell* cell) +void Water::setEnabled(bool enabled) { - if(cell->isExterior()) - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); + mEnabled = enabled; + updateVisible(); +} + +void Water::changeCell(const MWWorld::CellStore* store) +{ + if (store->getCell()->isExterior()) + mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + else + mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); } void Water::setHeight(const float height) { mTop = height; - mSimulation->setWaterHeight(height); + osg::Vec3f pos = mWaterNode->getPosition(); + pos.z() = height; + mWaterNode->setPosition(pos); +} - mWaterPlane = Plane(Vector3::UNIT_Z, -height); - - if (mReflection) - mReflection->setHeight(height); - if (mRefraction) - mRefraction->setHeight(height); - - mWaterNode->setPosition(0, 0, height); - sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); +void Water::updateVisible() +{ + mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); } bool Water::toggle() @@ -331,161 +168,17 @@ bool Water::toggle() return mToggled; } -void -Water::updateUnderwater(bool underwater) +bool Water::isUnderwater(const osg::Vec3f &pos) const { - if (!mActive) { - return; - } - mIsUnderwater = - underwater && - mWater->isVisible() && - mCamera->getPolygonMode() == Ogre::PM_SOLID; - - if (mReflection) - mReflection->setUnderwater (mIsUnderwater); - if (mRefraction) - mRefraction->setUnderwater (mIsUnderwater); - - updateVisible(); + return pos.z() < mTop && mToggled && mEnabled; } -Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); -} - -void Water::setViewportBackground(const ColourValue& bg) -{ - if (mReflection) - mReflection->setViewportBackground(bg); -} - -void Water::updateVisible() -{ - mWater->setVisible(mToggled && mActive); - if (mReflection) - mReflection->setActive(mToggled && mActive); - if (mRefraction) - mRefraction->setActive(mToggled && mActive); -} - -void Water::update(float dt, Ogre::Vector3 player) -{ - mWaterTimer += dt; - sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); - - mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - - mPlayer = Ogre::Vector2(player.x, player.y); -} - -void Water::frameStarted(float dt) -{ - if (!mActive) - return; - - mSimulation->update(dt, mPlayer); - - if (mReflection) - { - mReflection->update(); - } -} - -void Water::applyRTT() -{ - delete mReflection; - mReflection = NULL; - delete mRefraction; - mRefraction = NULL; - - // Create rendertarget for reflection - //int rttsize = Settings::Manager::getInt("rtt size", "Water"); - - if (Settings::Manager::getBool("shader", "Water")) - { - mReflection = new PlaneReflection(mSceneMgr, mSky); - mReflection->setParentCamera (mCamera); - mReflection->setHeight(mTop); - - if (Settings::Manager::getBool("refraction", "Water")) - { - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); - } - } - - updateVisible(); -} - -void Water::applyVisibilityMask() -{ - mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") - + (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water") - + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Effects - + RV_Sky; - - if (mReflection) - mReflection->setVisibilityMask(mVisibilityFlags); -} - -void Water::processChangedSettings(const Settings::CategorySettingVector& settings) -{ - bool applyRT = false; - bool applyVisMask = false; - for (Settings::CategorySettingVector::const_iterator it=settings.begin(); - it != settings.end(); ++it) - { - if ( it->first == "Water" && ( - it->second == "shader" - || it->second == "refraction" - || it->second == "rtt size")) - applyRT = true; - - if ( it->first == "Water" && ( - it->second == "reflect actors" - || it->second == "reflect terrain" - || it->second == "reflect statics")) - applyVisMask = true; - } - - if(applyRT) - { - applyRTT(); - applyVisibilityMask(); - mWater->setMaterial(mMaterial); - } - if (applyVisMask) - 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); - } + return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } +/* void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mSimulation->addEmitter (ptr, scale, force); @@ -500,10 +193,6 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) { mSimulation->updateEmitterPtr(old, ptr); } +*/ -void Water::clearRipples() -{ - mSimulation->clear(); } - -} // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 53d54cdc92..45b4b38a60 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,183 +1,60 @@ -#ifndef GAME_MWRENDER_WATER_H -#define GAME_MWRENDER_WATER_H +#ifndef OPENMW_MWRENDER_WATER_H +#define OPENMW_MWRENDER_WATER_H -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include +#include "../mwworld/cellstore.hpp" -#include - - -#include "renderconst.hpp" - -#include "../mwworld/ptr.hpp" - -namespace Ogre +namespace osg { - class Camera; - class SceneManager; - class SceneNode; - class Entity; - class Vector3; - class Rectangle2D; - struct RenderTargetEvent; + class Group; + class PositionAttitudeTransform; } -namespace MWWorld +namespace Resource { - class Fallback; + class ResourceSystem; } -namespace MWRender { - - class SkyManager; - class RenderingManager; - class RippleSimulation; - class Refraction; - - class Reflection - { - public: - Reflection(Ogre::SceneManager* sceneManager) - : mCamera(NULL) - , mParentCamera(NULL) - , mSceneMgr(sceneManager) - , mIsUnderwater(false) - {} - virtual ~Reflection() {} - - virtual void setHeight (float height) {} - virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } - void setUnderwater(bool underwater) { mIsUnderwater = underwater; } - virtual void setActive (bool active) {} - virtual void setViewportBackground(Ogre::ColourValue colour) {} - virtual void update() {} - virtual void setVisibilityMask (int flags) {} - - protected: - Ogre::Camera* mCamera; - Ogre::Camera* mParentCamera; - Ogre::TexturePtr mTexture; - Ogre::SceneManager* mSceneMgr; - bool mIsUnderwater; - }; - - class CubeReflection : public Reflection - { - public: - CubeReflection(Ogre::SceneManager* sceneManager); - virtual ~CubeReflection(); - - virtual void update(); - protected: - Ogre::RenderTarget* mRenderTargets[6]; - }; - - class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener - { - public: - PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); - virtual ~PlaneReflection(); - - virtual void setHeight (float height); - virtual void setActive (bool active); - virtual void setVisibilityMask (int flags); - - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - - virtual void setViewportBackground(Ogre::ColourValue colour); - - protected: - Ogre::RenderTarget* mRenderTarget; - SkyManager* mSky; - Ogre::Plane mWaterPlane; - Ogre::Plane mErrorPlane; - Ogre::Plane mErrorPlaneUnderwater; - bool mRenderActive; - }; +namespace MWRender +{ /// Water rendering - class Water : public sh::MaterialInstanceListener + class Water { static const int CELL_SIZE = 8192; - Ogre::Camera *mCamera; - Ogre::SceneManager *mSceneMgr; - Ogre::Plane mWaterPlane; + osg::ref_ptr mParent; + osg::ref_ptr mWaterNode; + Resource::ResourceSystem* mResourceSystem; - Ogre::SceneNode *mWaterNode; - Ogre::Entity *mWater; - - bool mIsUnderwater; - bool mActive; + bool mEnabled; bool mToggled; float mTop; - float mWaterTimer; - - - Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); - - protected: - void applyRTT(); - void applyVisibilityMask(); - + osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - RenderingManager* mRendering; - SkyManager* mSky; - - Ogre::MaterialPtr mMaterial; - - bool mUnderwaterEffect; - int mVisibilityFlags; - - Reflection* mReflection; - Refraction* mRefraction; - RippleSimulation* mSimulation; - - Ogre::Vector2 mPlayer; - public: - Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem); ~Water(); - void clearRipples(); - - void setActive(bool active); + void setEnabled(bool enabled); bool toggle(); - void update(float dt, Ogre::Vector3 player); - void frameStarted(float dt); + bool isUnderwater(const osg::Vec3f& pos) const; + + /* /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + */ - void setViewportBackground(const Ogre::ColourValue& bg); - - void processChangedSettings(const Settings::CategorySettingVector& settings); - - /// Updates underwater state accordingly - void updateUnderwater(bool underwater); - void changeCell(const ESM::Cell* cell); + void changeCell(const MWWorld::CellStore* store); 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/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db1f9714ac..1a9ae34943 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -265,11 +265,11 @@ namespace MWWorld mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); - //mRendering.setWaterEnabled(waterEnabled); + mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { mPhysics->enableWater(waterLevel); - //mRendering.setWaterHeight(waterLevel); + mRendering.setWaterHeight(waterLevel); } else mPhysics->disableWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 126267fd46..799f82015d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1763,17 +1763,17 @@ namespace MWWorld void World::setWaterHeight(const float height) { mPhysics->setWaterHeight(height); - //mRendering->setWaterHeight(height); + mRendering->setWaterHeight(height); } bool World::toggleWater() { - return 0;//mRendering->toggleWater(); + return mRendering->toggleRenderMode(MWRender::Render_Water); } bool World::toggleWorld() { - return 0;//mRendering->toggleWorld(); + return mRendering->toggleRenderMode(MWRender::Render_Scene); } void World::PCDropped (const Ptr& item) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 06d5d8792d..a314910c5b 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -399,6 +399,13 @@ FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) + : mTexSlot(texSlot) + , mDelta(delta) + , mTextures(textures) +{ +} + FlipController::FlipController() { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4ebd4f41d2..4877c83dbb 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -218,6 +218,7 @@ namespace NifOsg public: FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(int texSlot, float delta, std::vector > textures); FlipController(); FlipController(const FlipController& copy, const osg::CopyOp& copyop); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 4b51485f20..b8b452dc3a 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -20,7 +20,10 @@ namespace SceneUtil float Controller::getInputValue(osg::NodeVisitor* nv) { - return mFunction->calculate(mSource->getValue(nv)); + if (mFunction) + return mFunction->calculate(mSource->getValue(nv)); + else + return mSource->getValue(nv); } void Controller::setSource(boost::shared_ptr source) From 5a7f2a4f1f2fb03d9f72fc0134b00648ec02ffde Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:02:56 +0200 Subject: [PATCH 0360/1812] Restore light attenuation settings --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 28 +++++++++++++++++++++------ components/sceneutil/lightmanager.cpp | 24 +++++++++++++++++++++++ components/sceneutil/lightmanager.hpp | 3 +++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 015d0db9ab..bb71cb6c9b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water -# occlusionquery shadows ripplesimulation refraction terrainstorage +# occlusionquery shadows ripplesimulation terrainstorage ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2279375c23..9fe9dd4515 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -31,6 +31,8 @@ #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/fallback.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority @@ -1000,14 +1002,28 @@ namespace MWRender osg::Light* light = new osg::Light; lightSource->setLight(light); - float realRadius = esmLight->mData.mRadius; + const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); - lightSource->setRadius(realRadius); - light->setLinearAttenuation(10.f/(esmLight->mData.mRadius*2.f)); - //light->setLinearAttenuation(0.05); - light->setConstantAttenuation(0.f); + float radius = esmLight->mData.mRadius; + lightSource->setRadius(radius); - light->setDiffuse(SceneUtil::colourFromRGB(esmLight->mData.mColor)); + static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); + static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); + static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); + static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); + + bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior(); + + SceneUtil::configureLight(light, radius, exterior, outQuadInLin, useQuadratic, quadraticValue, + quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + + osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); + if (esmLight->mData.mFlags & ESM::Light::Negative) + diffuse *= -1; + light->setDiffuse(diffuse); light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index e53a55bf37..6040f95364 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -325,4 +325,28 @@ namespace SceneUtil traverse(node, nv); } + void configureLight(osg::Light *light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, + float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue) + { + bool quadratic = useQuadratic && (!outQuadInLin || isExterior); + + float quadraticAttenuation = 0; + float linearAttenuation = 0; + if (quadratic) + { + float r = radius * quadraticRadiusMult; + quadraticAttenuation = quadraticValue / std::pow(r, 2); + } + if (useLinear) + { + float r = radius * linearRadiusMult; + linearAttenuation = linearValue / r; + } + + light->setLinearAttenuation(linearAttenuation); + light->setQuadraticAttenuation(quadraticAttenuation); + light->setConstantAttenuation(0.f); + + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index dd0c2d3e6c..d5aecdbb65 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -124,6 +124,9 @@ namespace SceneUtil LightManager* mLightManager; }; + /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. + void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue, + float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue); } From 8c50f8ed26a0b2fdf42d5be8ea95dd44e110e015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:06:55 +0200 Subject: [PATCH 0361/1812] Fix for lights with no mesh --- apps/openmw/mwrender/animation.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9fe9dd4515..34a397f9a6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1022,7 +1022,10 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); if (esmLight->mData.mFlags & ESM::Light::Negative) + { diffuse *= -1; + diffuse.a() = 1; + } light->setDiffuse(diffuse); light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); @@ -1197,10 +1200,9 @@ namespace MWRender if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); - - if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) - addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) + addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } } From 58ebf57154daa1c98c638e4778f5929090125753 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 17:13:30 +0200 Subject: [PATCH 0362/1812] Apply a comment that got lost in the endless depths of my git stash --- apps/openmw/mwmechanics/aicombat.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a909adb8b4..36ff927d80 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -239,7 +239,6 @@ namespace MWMechanics if(smoothTurn(actor, Ogre::Degree(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } - //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f float attacksPeriod = 1.0f; ESM::Weapon::AttackType attackType; @@ -260,7 +259,7 @@ namespace MWMechanics if (!minMaxAttackDurationInitialised) { // TODO: this must be updated when a different weapon is equipped - // FIXME: attack durations would be easier to control if we interact more closely with the CharacterController + // TODO: it would be much easier to ask the CharacterController about the current % completion of the weapon wind-up animation getMinMaxAttackDuration(actor, minMaxAttackDuration); minMaxAttackDurationInitialised = true; } @@ -319,6 +318,10 @@ namespace MWMechanics float rangeAttack = 0; float rangeFollow = 0; boost::shared_ptr& currentAction = storage.mCurrentAction; + // TODO: upperBodyReady() works fine for checking if we can start an attack, + // but doesn't work properly for checking if the attack is finished (as things like hit recovery or knockdown also play on the upper body) + // Only a minor problem, but can mess with the actionCooldown timer. + // To fix this the AI needs to be brought closer to the CharacterController, so we can simply check if a weapon animation is playing. if (anim->upperBodyReady()) { currentAction = prepareNextAction(actor, target); @@ -654,9 +657,6 @@ namespace MWMechanics } } - // NOTE: This section gets updated every tReaction, which is currently hard - // coded at 250ms or 1/4 second - // // TODO: Add a parameter to vary DURATION_SAME_SPOT? if((distToTarget > rangeAttack || followTarget) && mObstacleCheck.check(actor, tReaction)) // check if evasive action needed From 4d5c446a44ef80c76ea2dccf96c48daea9ece15d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 19:36:57 +0200 Subject: [PATCH 0363/1812] Minor cleanup --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index d8006b581b..1b02e13bef 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -308,7 +308,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // windex is set to 0 initially vp = &this->pictq[this->pictq_windex]; - // Convert the image into RGBA format for Ogre + // Convert the image into RGBA format // TODO: we could do this in a pixel shader instead, if the source format // matches a commonly used format (ie YUV420P) if(this->sws_context == NULL) From 10f938ff8763960afb873c283c57afd829690ede Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 01:18:03 +0200 Subject: [PATCH 0364/1812] Add comment --- components/myguiplatform/myguirendermanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e2f2f98206..bf1d66fe8a 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -195,7 +195,9 @@ public: META_Object(osgMyGUI, Drawable) private: + // double buffering approach, to avoid the need for synchronization with the draw thread std::vector mBatchVector[2]; + int mWriteTo; mutable int mReadFrom; }; From cdd062300946e7ce38152a28f2ae55c5ba754428 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 01:18:36 +0200 Subject: [PATCH 0365/1812] Terrain rendering --- CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 5 + apps/opencs/model/world/data.hpp | 2 + apps/opencs/view/render/cell.cpp | 20 +- apps/opencs/view/render/cell.hpp | 2 - apps/opencs/view/render/terrainstorage.cpp | 3 +- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/localmap.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 20 +- apps/openmw/mwrender/renderingmanager.hpp | 8 + apps/openmw/mwrender/terrainstorage.cpp | 3 +- apps/openmw/mwrender/terrainstorage.hpp | 2 +- apps/openmw/mwrender/vismask.hpp | 7 +- apps/openmw/mwrender/water.cpp | 7 +- apps/openmw/mwrender/water.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 4 +- components/CMakeLists.txt | 4 +- components/esm/loadland.hpp | 2 +- components/esmterrain/storage.cpp | 227 ++++---- components/esmterrain/storage.hpp | 48 +- components/terrain/buffercache.cpp | 129 ++--- components/terrain/buffercache.hpp | 14 +- components/terrain/chunk.cpp | 169 ------ components/terrain/chunk.hpp | 75 --- components/terrain/defaultworld.cpp | 336 ----------- components/terrain/defaultworld.hpp | 177 ------ components/terrain/defs.hpp | 42 +- components/terrain/material.cpp | 393 +++---------- components/terrain/material.hpp | 68 +-- components/terrain/quadtreenode.cpp | 611 --------------------- components/terrain/quadtreenode.hpp | 189 ------- components/terrain/storage.cpp | 2 + components/terrain/storage.hpp | 41 +- components/terrain/terraingrid.cpp | 227 ++++---- components/terrain/terraingrid.hpp | 49 +- components/terrain/world.cpp | 56 +- components/terrain/world.hpp | 82 +-- 37 files changed, 541 insertions(+), 2501 deletions(-) delete mode 100644 components/terrain/chunk.cpp delete mode 100644 components/terrain/chunk.hpp delete mode 100644 components/terrain/defaultworld.cpp delete mode 100644 components/terrain/defaultworld.hpp delete mode 100644 components/terrain/quadtreenode.cpp delete mode 100644 components/terrain/quadtreenode.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 43d40c2ef9..d134372141 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 064e96150a..9772a68fa7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -488,6 +488,11 @@ Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() return &mResourceSystem; } +const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const +{ + return &mResourceSystem; +} + const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const { return mGlobals; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 93cd46d861..a41946687d 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -140,6 +140,8 @@ namespace CSMWorld Resource::ResourceSystem* getResourceSystem(); + const Resource::ResourceSystem* getResourceSystem() const; + const IdCollection& getGlobals() const; IdCollection& getGlobals(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 343d0d2e68..063413248a 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -64,7 +64,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - /* const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) @@ -72,27 +71,18 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, - Terrain::Align_XY)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand->mX, esmLand->mY); - //float verts = ESM::Land::LAND_SIZE; - //float worldsize = ESM::Land::REAL_SIZE; mX = esmLand->mX; mY = esmLand->mY; - //mPhysics->addHeightField(sceneManager, - // esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } - */ } CSVRender::Cell::~Cell() { - //if (mTerrain.get()) - // mPhysics->removeHeightField(mSceneMgr, mX, mY); - for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) delete iter->second; @@ -221,11 +211,3 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } - -float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const -{ - if(mTerrain.get() != NULL) - return mTerrain->getHeightAt(pos); - else - return -std::numeric_limits::max(); -} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 259ab1779e..f4272b8879 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -75,8 +75,6 @@ namespace CSVRender /// \return Did this call result in a modification of the visual representation of /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); - - float getTerrainHeightAt(const Ogre::Vector3 &pos) const; }; } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index a14eea5dd6..fe302cef14 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -4,7 +4,8 @@ namespace CSVRender { TerrainStorage::TerrainStorage(const CSMWorld::Data &data) - : mData(data) + : ESMTerrain::Storage(data.getResourceSystem()->getVFS()) + , mData(data) { } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bb71cb6c9b..ef0c4e1351 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap water -# occlusionquery shadows ripplesimulation terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage +# occlusionquery shadows ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 3003e47366..16957a585f 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -157,7 +157,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water); + camera->setCullMask(Mask_Scene|Mask_Water|Mask_Terrain); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -309,7 +309,7 @@ void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene); + computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a708bbe88c..6205c3ad87 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include #include "sky.hpp" @@ -35,6 +37,7 @@ #include "pathgrid.hpp" #include "camera.hpp" #include "water.hpp" +#include "terrainstorage.hpp" namespace MWRender { @@ -132,7 +135,10 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem)); + mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation())); + + mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), + new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); mCamera.reset(new Camera(mViewer->getCamera())); @@ -236,12 +242,18 @@ namespace MWRender mPathgrid->addCell(store); mWater->changeCell(store); + + if (store->getCell()->isExterior()) + mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } void RenderingManager::removeCell(const MWWorld::CellStore *store) { mPathgrid->removeCell(store); mObjects->removeCell(store); + + if (store->getCell()->isExterior()) + mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } void RenderingManager::setSkyEnabled(bool enabled) @@ -482,7 +494,6 @@ namespace MWRender void RenderingManager::clear() { - //mLocalMap->clear(); notifyWorldSpaceChanged(); } @@ -595,6 +606,11 @@ namespace MWRender return mNearClip; } + float RenderingManager::getTerrainHeightAt(const osg::Vec3f &pos) + { + return mTerrain->getHeightAt(pos); + } + bool RenderingManager::vanityRotateCamera(const float *rot) { if(!mCamera->isVanityOrPreviewModeEnabled()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d90a75c865..c22d3c7bfd 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -32,6 +32,11 @@ namespace ESM struct Cell; } +namespace Terrain +{ + class World; +} + namespace MWRender { @@ -119,6 +124,8 @@ namespace MWRender float getNearClipDistance() const; + float getTerrainHeightAt(const osg::Vec3f& pos); + // camera stuff bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust, bool override); @@ -147,6 +154,7 @@ namespace MWRender std::auto_ptr mPathgrid; std::auto_ptr mObjects; std::auto_ptr mWater; + std::auto_ptr mTerrain; std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 8ad2ea3213..269e7f99fc 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -9,7 +9,8 @@ namespace MWRender { - TerrainStorage::TerrainStorage(bool preload) + TerrainStorage::TerrainStorage(const VFS::Manager* vfs, bool preload) + : ESMTerrain::Storage(vfs) { if (preload) { diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index e6f4a04ad3..93531a5523 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -16,7 +16,7 @@ namespace MWRender ///@param preload Preload all Land records at startup? If using the multithreaded terrain component, this /// should be set to "true" in order to avoid race conditions. - TerrainStorage(bool preload); + TerrainStorage(const VFS::Manager* vfs, bool preload); /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 3a0336f822..b794ac24a9 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -16,13 +16,14 @@ namespace MWRender Mask_Player = (1<<4), Mask_Sky = (1<<5), Mask_Water = (1<<6), + Mask_Terrain = (1<<7), // top level masks - Mask_Scene = (1<<7), - Mask_GUI = (1<<8), + Mask_Scene = (1<<8), + Mask_GUI = (1<<9), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<9) + Mask_RenderToTexture = (1<<10) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2dd843e4ed..c2149358bd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -105,7 +107,7 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico) : mParent(parent) , mResourceSystem(resourceSystem) , mEnabled(true) @@ -118,6 +120,9 @@ Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); + if (ico) + ico->add(geode); + createWaterStateSet(mResourceSystem, geode); mWaterNode = new osg::PositionAttitudeTransform; diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 45b4b38a60..d389392ba8 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,6 +11,11 @@ namespace osg class PositionAttitudeTransform; } +namespace osgUtil +{ + class IncrementalCompileOperation; +} + namespace Resource { class ResourceSystem; @@ -27,6 +32,7 @@ namespace MWRender osg::ref_ptr mParent; osg::ref_ptr mWaterNode; Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mIncrementalCompileOperation; bool mEnabled; bool mToggled; @@ -36,7 +42,7 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico); ~Water(); void setEnabled(bool enabled); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 799f82015d..e676977de3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1298,7 +1298,9 @@ namespace MWWorld return; } - float terrainHeight = -FLT_MAX;//mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + float terrainHeight = -std::numeric_limits::max(); + if (isCellExterior()) + terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6a5b7f59a9..51cb55aee2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -104,10 +104,8 @@ add_component_dir (translation translation ) -#add_definitions(-DTERRAIN_USE_SHADER=1) -add_definitions(-DTERRAIN_USE_SHADER=0) add_component_dir (terrain - quadtreenode chunk world defaultworld terraingrid storage material buffercache defs + storage world buffercache defs terraingrid material ) add_component_dir (loadinglistener diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e510616aff..edaeadb03d 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -80,7 +80,7 @@ struct Land VNML mNormals[LAND_NUM_VERTS * 3]; uint16_t mTextures[LAND_NUM_TEXTURES]; - char mColours[3 * LAND_NUM_VERTS]; + unsigned char mColours[3 * LAND_NUM_VERTS]; int mDataTypes; // low-LOD heightmap (used for rendering the global map) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5a69fd27a8..0795a3ffc9 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,34 +1,38 @@ #include "storage.hpp" -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include + +#include #include -#include #include +#include namespace ESMTerrain { - bool Storage::getMinMaxHeights(float size, const Ogre::Vector2 ¢er, float &min, float &max) + Storage::Storage(const VFS::Manager *vfs) + : mVFS(vfs) + { + } + + bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); /// \todo investigate if min/max heights should be stored at load time in ESM::Land instead - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); + osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); + assert(origin.x == (int) origin.x()); + assert(origin.y == (int) origin.y()); - int cellX = static_cast(origin.x); - int cellY = static_cast(origin.y); + int cellX = static_cast(origin.x()); + int cellY = static_cast(origin.y()); const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -50,7 +54,7 @@ namespace ESMTerrain return true; } - void Storage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row) + void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) { while (col >= ESM::Land::LAND_SIZE-1) { @@ -75,27 +79,27 @@ namespace ESMTerrain ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); + normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalize(); } else - normal = Ogre::Vector3(0,0,1); + normal = osg::Vec3f(0,0,1); } - void Storage::averageNormal(Ogre::Vector3 &normal, int cellX, int cellY, int col, int row) + void Storage::averageNormal(osg::Vec3f &normal, int cellX, int cellY, int col, int row) { - Ogre::Vector3 n1,n2,n3,n4; + osg::Vec3f n1,n2,n3,n4; fixNormal(n1, cellX, cellY, col+1, row); fixNormal(n2, cellX, cellY, col-1, row); fixNormal(n3, cellX, cellY, col, row+1); fixNormal(n4, cellX, cellY, col, row-1); normal = (n1+n2+n3+n4); - normal.normalise(); + normal.normalize(); } - void Storage::fixColour (Ogre::ColourValue& color, int cellX, int cellY, int col, int row) + void Storage::fixColour (osg::Vec4f& color, int cellX, int cellY, int col, int row) { if (col == ESM::Land::LAND_SIZE-1) { @@ -110,42 +114,42 @@ namespace ESMTerrain ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { - color.r = 1; - color.g = 1; - color.b = 1; + color.r() = 1; + color.g() = 1; + color.b() = 1; } } - void Storage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours) + void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours) { // LOD level n means every 2^n-th vertex is kept size_t increment = 1 << lodLevel; - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); + osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); + assert(origin.x() == (int) origin.x()); + assert(origin.y() == (int) origin.y()); - int startX = static_cast(origin.x); - int startY = static_cast(origin.y); + int startX = static_cast(origin.x()); + int startY = static_cast(origin.y()); size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); - colours.resize(numVerts*numVerts*4); - positions.resize(numVerts*numVerts*3); - normals.resize(numVerts*numVerts*3); + positions->resize(numVerts*numVerts); + normals->resize(numVerts*numVerts); + colours->resize(numVerts*numVerts); - Ogre::Vector3 normal; - Ogre::ColourValue color; + osg::Vec3f normal; + osg::Vec4f color; float vertY = 0; float vertX = 0; @@ -175,22 +179,24 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; row(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); + float height = -2048; if (land) - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; - else - positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048; + height = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + + (*positions)[static_cast(vertX*numVerts + vertY)] + = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, + (vertY / float(numVerts - 1) - 0.5f) * size * 8192, + height); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); + normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalize(); } else - normal = Ogre::Vector3(0,0,1); + normal = osg::Vec3f(0,0,1); // Normals apparently don't connect seamlessly between cells if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) @@ -200,33 +206,30 @@ namespace ESMTerrain if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1)) averageNormal(normal, cellX, cellY, col, row); - assert(normal.z > 0); + assert(normal.z() > 0); - normals[static_cast(vertX*numVerts * 3 + vertY * 3)] = normal.x; - normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; - normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; + (*normals)[static_cast(vertX*numVerts + vertY)] = normal; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { - color.r = 1; - color.g = 1; - color.b = 1; + color.r() = 1; + color.g() = 1; + color.b() = 1; } // Unlike normals, colors mostly connect seamlessly between cells, but not always... if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) fixColour(color, cellX, cellY, col, row); - color.a = 1; - Ogre::uint32 rsColor; - Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colours[static_cast(vertX*numVerts * 4 + vertY * 4)], &rsColor, sizeof(Ogre::uint32)); + color.a() = 1; + + (*colours)[static_cast(vertX*numVerts + vertY)] = color; ++vertX; } @@ -281,39 +284,22 @@ namespace ESMTerrain // NB: All vtex ids are +1 compared to the ltex ids const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); - //TODO this is needed due to MWs messed up texture handling - assert(0 && "no vfs here yet"); - std::string texture = ltex->mTexture; //Misc::ResourceHelpers::correctTexturePath(ltex->mTexture); + // this is needed due to MWs messed up texture handling + std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture, mVFS); return texture; } - void Storage::getBlendmaps (const std::vector& nodes, std::vector& out, bool pack) - { - for (std::vector::const_iterator it = nodes.begin(); it != nodes.end(); ++it) - { - out.push_back(Terrain::LayerCollection()); - out.back().mTarget = *it; - getBlendmapsImpl(static_cast((*it)->getSize()), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); - } - } - - void Storage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter, - bool pack, std::vector &blendmaps, std::vector &layerList) - { - getBlendmapsImpl(chunkSize, chunkCenter, pack, blendmaps, layerList); - } - - void Storage::getBlendmapsImpl(float chunkSize, const Ogre::Vector2 &chunkCenter, - bool pack, std::vector &blendmaps, std::vector &layerList) + void Storage::getBlendmaps(float chunkSize, const osg::Vec2f &chunkCenter, + bool pack, ImageVector &blendmaps, std::vector &layerList) { // TODO - blending isn't completely right yet; the blending radius appears to be // different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap // and interpolate the rest of the cell by hand? :/ - Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = static_cast(origin.x); - int cellY = static_cast(origin.y); + osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); + int cellX = static_cast(origin.x()); + int cellY = static_cast(origin.y()); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -353,11 +339,11 @@ namespace ESMTerrain for (int i=0; i image (new osg::Image); + image->allocateImage(blendmapSize, blendmapSize, 1, format, GL_UNSIGNED_BYTE); + unsigned char* pData = image->data(); for (int y=0; y(std::floor(worldPos.x / 8192.f)); - int cellY = static_cast(std::floor(worldPos.y / 8192.f)); + int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); + int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -390,8 +377,8 @@ namespace ESMTerrain // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell - float nX = (worldPos.x - (cellX * 8192))/8192.f; - float nY = (worldPos.y - (cellY * 8192))/8192.f; + float nX = (worldPos.x() - (cellX * 8192))/8192.f; + float nY = (worldPos.y() - (cellY * 8192))/8192.f; // get left / bottom points (rounded down) float factor = ESM::Land::LAND_SIZE - 1.0f; @@ -423,22 +410,23 @@ namespace ESMTerrain */ // Build all 4 positions in normalized cell space, using point-sampled height - Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); - Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); - Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); - Ogre::Vector3 v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); + osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); + osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); + osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); + osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); // define this plane in terrain space - Ogre::Plane plane; - // (At the moment, all rows have the same triangle alignment) + osg::Plane plane; + // FIXME: deal with differing triangle alignment if (true) { // odd row bool secondTri = ((1.0 - yParam) > xParam); if (secondTri) - plane.redefine(v0, v1, v3); + plane = osg::Plane(v0, v1, v3); else - plane.redefine(v1, v2, v3); + plane = osg::Plane(v1, v2, v3); } + /* else { // even row @@ -448,11 +436,12 @@ namespace ESMTerrain else plane.redefine(v0, v1, v2); } + */ // Solve plane equation for z - return (-plane.normal.x * nX - -plane.normal.y * nY - - plane.d) / plane.normal.z * 8192; + return (-plane.getNormal().x() * nX + -plane.getNormal().y() * nY + - plane[3]) / plane.getNormal().z() * 8192; } @@ -477,7 +466,7 @@ namespace ESMTerrain std::string texture_ = texture; boost::replace_last(texture_, ".", "_nh."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) { info.mNormalMap = texture_; info.mParallax = true; @@ -486,24 +475,18 @@ namespace ESMTerrain { texture_ = texture; boost::replace_last(texture_, ".", "_n."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) info.mNormalMap = texture_; } texture_ = texture; boost::replace_last(texture_, ".", "_diffusespec."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texture_)) + if (mVFS->exists(texture_)) { info.mDiffuseMap = texture_; info.mSpecular = true; } - // This wasn't cached, so the textures are probably not loaded either. - // Background load them so they are hopefully already loaded once we need them! - Ogre::ResourceBackgroundQueue::getSingleton().load("Texture", info.mDiffuseMap, "General"); - if (!info.mNormalMap.empty()) - Ogre::ResourceBackgroundQueue::getSingleton().load("Texture", info.mNormalMap, "General"); - mLayerInfoMap[texture] = info; return info; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index e184cbc4cd..8f4a3aa921 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -6,6 +6,11 @@ #include #include +namespace VFS +{ + class Manager; +} + namespace ESMTerrain { @@ -20,6 +25,7 @@ namespace ESMTerrain virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: + Storage(const VFS::Manager* vfs); // Not implemented in this class, because we need different Store implementations for game and editor /// Get bounds of the whole terrain in cell units @@ -33,11 +39,10 @@ namespace ESMTerrain /// @param min min height will be stored here /// @param max max height will be stored here /// @return true if there was data available for this terrain chunk - virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max); + virtual bool getMinMaxHeights (float size, const osg::Vec2f& center, float& min, float& max); /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! - /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed @@ -46,10 +51,10 @@ namespace ESMTerrain /// @param positions buffer to write vertices /// @param normals buffer to write vertex normals /// @param colours buffer to write vertex colours - virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours); + virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours); /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might @@ -62,23 +67,11 @@ namespace ESMTerrain /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, + ImageVector& blendmaps, std::vector& layerList); - /// Retrieve pixel data for textures holding layer blend values for terrain chunks and layer texture information. - /// This variant is provided to eliminate the overhead of virtual function calls when retrieving a large number of blendmaps at once. - /// @note The terrain chunks shouldn't be larger than one cell since otherwise we might - /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. - /// @note May be called from background threads. - /// @param nodes A collection of nodes for which to retrieve the aforementioned data - /// @param out Output vector - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. - virtual void getBlendmaps (const std::vector& nodes, std::vector& out, bool pack); - - virtual float getHeightAt (const Ogre::Vector3& worldPos); + virtual float getHeightAt (const osg::Vec3f& worldPos); virtual Terrain::LayerInfo getDefaultLayer(); @@ -89,9 +82,11 @@ namespace ESMTerrain virtual int getCellVertices(); private: - void fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); - void fixColour (Ogre::ColourValue& colour, int cellX, int cellY, int col, int row); - void averageNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); + const VFS::Manager* mVFS; + + void fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row); + void fixColour (osg::Vec4f& colour, int cellX, int cellY, int col, int row); + void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row); float getVertexHeight (const ESM::Land* land, int x, int y); @@ -107,11 +102,6 @@ namespace ESMTerrain std::map mLayerInfoMap; Terrain::LayerInfo getLayerInfo(const std::string& texture); - - // Non-virtual - void getBlendmapsImpl (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, - std::vector& layerList); }; } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 1b000fabb1..7dc93f1d65 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -21,15 +21,17 @@ */ #include "buffercache.hpp" -#include +#include + +#include #include "defs.hpp" namespace { -template -Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigned int verts, Ogre::HardwareIndexBuffer::IndexType type) +template +osg::ref_ptr createIndexBuffer(unsigned int flags, unsigned int verts) { // LOD level n means every 2^n-th vertex is kept size_t lodLevel = (flags >> (4*4)); @@ -42,8 +44,9 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne size_t increment = 1 << lodLevel; assert(increment < verts); - std::vector indices; - indices.reserve((verts-1)*(verts-1)*2*3 / increment); + + osg::ref_ptr indices (new IndexArrayType(osg::PrimitiveSet::TRIANGLES)); + indices->reserve((verts-1)*(verts-1)*2*3 / increment); size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; // If any edge needs stitching we'll skip all edges at this point, @@ -62,23 +65,23 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne // diamond pattern if ((row + col%2) % 2 == 1) { - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row+increment); - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col)+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col)+row+increment); } else { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row+increment); - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+increment)+row); + indices->push_back(verts*(col+increment)+row+increment); } } } @@ -94,22 +97,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne size_t outerStep = 1 << (lodDeltas[Terrain::South] + lodLevel); for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+outerStep)+row); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+outerStep)+row); // Make sure not to touch the right edge if (col+outerStep == verts-1) - indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); + indices->push_back(verts*(col+outerStep-innerStep)+row+innerStep); else - indices.push_back(verts*(col+outerStep)+row+innerStep); + indices->push_back(verts*(col+outerStep)+row+innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(verts*(col)+row); - indices.push_back(verts*(col+i+innerStep)+row+innerStep); - indices.push_back(verts*(col+i)+row+innerStep); + indices->push_back(verts*(col)+row); + indices->push_back(verts*(col+i+innerStep)+row+innerStep); + indices->push_back(verts*(col+i)+row+innerStep); } } @@ -118,22 +121,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel); for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(verts*(col+outerStep)+row); - indices.push_back(verts*col+row); + indices->push_back(verts*(col+outerStep)+row); + indices->push_back(verts*col+row); // Make sure not to touch the left edge if (col == 0) - indices.push_back(verts*(col+innerStep)+row-innerStep); + indices->push_back(verts*(col+innerStep)+row-innerStep); else - indices.push_back(verts*col+row-innerStep); + indices->push_back(verts*col+row-innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(verts*(col+i)+row-innerStep); - indices.push_back(verts*(col+i+innerStep)+row-innerStep); - indices.push_back(verts*(col+outerStep)+row); + indices->push_back(verts*(col+i)+row-innerStep); + indices->push_back(verts*(col+i+innerStep)+row-innerStep); + indices->push_back(verts*(col+outerStep)+row); } } @@ -142,22 +145,22 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel); for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*col+row); + indices->push_back(verts*col+row+outerStep); + indices->push_back(verts*col+row); // Make sure not to touch the top edge if (row+outerStep == verts-1) - indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); + indices->push_back(verts*(col+innerStep)+row+outerStep-innerStep); else - indices.push_back(verts*(col+innerStep)+row+outerStep); + indices->push_back(verts*(col+innerStep)+row+outerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(verts*col+row); - indices.push_back(verts*(col+innerStep)+row+i); - indices.push_back(verts*(col+innerStep)+row+i+innerStep); + indices->push_back(verts*col+row); + indices->push_back(verts*(col+innerStep)+row+i); + indices->push_back(verts*(col+innerStep)+row+i+innerStep); } } @@ -166,31 +169,27 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel); for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(verts*col+row); - indices.push_back(verts*col+row+outerStep); + indices->push_back(verts*col+row); + indices->push_back(verts*col+row+outerStep); // Make sure not to touch the bottom edge if (row == 0) - indices.push_back(verts*(col-innerStep)+row+innerStep); + indices->push_back(verts*(col-innerStep)+row+innerStep); else - indices.push_back(verts*(col-innerStep)+row); + indices->push_back(verts*(col-innerStep)+row); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*(col-innerStep)+row+i+innerStep); - indices.push_back(verts*(col-innerStep)+row+i); + indices->push_back(verts*col+row+outerStep); + indices->push_back(verts*(col-innerStep)+row+i+innerStep); + indices->push_back(verts*(col-innerStep)+row+i); } } } - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(type, - indices.size(), Ogre::HardwareBuffer::HBU_STATIC); - buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); - return buffer; + return indices; } } @@ -198,7 +197,7 @@ Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigne namespace Terrain { - Ogre::HardwareVertexBufferSharedPtr BufferCache::getUVBuffer() + osg::ref_ptr BufferCache::getUVBuffer() { if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end()) { @@ -207,30 +206,23 @@ namespace Terrain int vertexCount = mNumVerts * mNumVerts; - std::vector uvs; - uvs.reserve(vertexCount*2); + osg::ref_ptr uvs (new osg::Vec2Array); + uvs->reserve(vertexCount); for (unsigned int col = 0; col < mNumVerts; ++col) { for (unsigned int row = 0; row < mNumVerts; ++row) { - uvs.push_back(col / static_cast(mNumVerts-1)); // U - uvs.push_back(row / static_cast(mNumVerts-1)); // V + uvs->push_back(osg::Vec2f(col / static_cast(mNumVerts-1), + row / static_cast(mNumVerts-1))); } } - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr buffer = mgr->createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - buffer->writeData(0, buffer->getSizeInBytes(), &uvs[0], true); - - mUvBufferMap[mNumVerts] = buffer; - return buffer; + mUvBufferMap[mNumVerts] = uvs; + return uvs; } - Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(unsigned int flags) + osg::ref_ptr BufferCache::getIndexBuffer(unsigned int flags) { unsigned int verts = mNumVerts; @@ -239,11 +231,12 @@ namespace Terrain return mIndexBufferMap[flags]; } - Ogre::HardwareIndexBufferSharedPtr buffer; + osg::ref_ptr buffer; + if (verts*verts > (0xffffu)) - buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_32BIT); + buffer = createIndexBuffer(flags, verts); else - buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_16BIT); + buffer = createIndexBuffer(flags, verts); mIndexBufferMap[flags] = buffer; return buffer; diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 887f0822ef..575e9bca25 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -22,8 +22,8 @@ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H -#include -#include +#include +#include #include @@ -38,16 +38,18 @@ namespace Terrain /// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each) /// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices) - Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (unsigned int flags); + osg::ref_ptr getIndexBuffer (unsigned int flags); - Ogre::HardwareVertexBufferSharedPtr getUVBuffer (); + osg::ref_ptr getUVBuffer(); + + // TODO: add releaseGLObjects() for our vertex/element buffer objects private: // Index buffers are shared across terrain batches where possible. There is one index buffer for each // combination of LOD deltas and index buffer LOD we may need. - std::map mIndexBufferMap; + std::map > mIndexBufferMap; - std::map mUvBufferMap; + std::map > mUvBufferMap; unsigned int mNumVerts; }; diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp deleted file mode 100644 index e3bae11732..0000000000 --- a/components/terrain/chunk.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "chunk.hpp" - -#include -#include -#include -#include -#include - -namespace Terrain -{ - - Chunk::Chunk(Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, - const std::vector& positions, const std::vector& normals, const std::vector& colours) - : mBounds(bounds) - , mOwnMaterial(false) - { - mVertexData = OGRE_NEW Ogre::VertexData; - mVertexData->vertexStart = 0; - mVertexData->vertexCount = positions.size()/3; - - // Set up the vertex declaration, which specifies the info for each vertex (normals, colors, UVs, etc) - Ogre::VertexDeclaration* vertexDecl = mVertexData->vertexDeclaration; - - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - size_t nextBuffer = 0; - - // Positions - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - Ogre::HardwareVertexBufferSharedPtr vertexBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - // Normals - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - Ogre::HardwareVertexBufferSharedPtr normalBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - - // UV texture coordinates - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT2, - Ogre::VES_TEXTURE_COORDINATES, 0); - - // Colours - vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - Ogre::HardwareVertexBufferSharedPtr colourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); - - vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true); - normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true); - colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colours[0], true); - - mVertexData->vertexBufferBinding->setBinding(0, vertexBuffer); - mVertexData->vertexBufferBinding->setBinding(1, normalBuffer); - mVertexData->vertexBufferBinding->setBinding(2, uvBuffer); - mVertexData->vertexBufferBinding->setBinding(3, colourBuffer); - - // Assign a default material in case terrain material fails to be created - mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); - - mIndexData = OGRE_NEW Ogre::IndexData(); - mIndexData->indexStart = 0; - } - - void Chunk::setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer) - { - mIndexData->indexBuffer = buffer; - mIndexData->indexCount = buffer->getNumIndexes(); - } - - Chunk::~Chunk() - { - if (!mMaterial.isNull() && mOwnMaterial) - { -#if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); -#endif - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - OGRE_DELETE mVertexData; - OGRE_DELETE mIndexData; - } - - void Chunk::setMaterial(const Ogre::MaterialPtr &material, bool own) - { - // Clean up the previous material, if we own it - if (!mMaterial.isNull() && mOwnMaterial) - { -#if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); -#endif - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - } - - mMaterial = material; - mOwnMaterial = own; - } - - const Ogre::AxisAlignedBox& Chunk::getBoundingBox(void) const - { - return mBounds; - } - - Ogre::Real Chunk::getBoundingRadius(void) const - { - return mBounds.getHalfSize().length(); - } - - void Chunk::_updateRenderQueue(Ogre::RenderQueue* queue) - { - queue->addRenderable(this, mRenderQueueID); - } - - void Chunk::visitRenderables(Ogre::Renderable::Visitor* visitor, - bool debugRenderables) - { - visitor->visit(this, 0, false); - } - - const Ogre::MaterialPtr& Chunk::getMaterial(void) const - { - return mMaterial; - } - - void Chunk::getRenderOperation(Ogre::RenderOperation& op) - { - assert (!mIndexData->indexBuffer.isNull() && "Trying to render, but no index buffer set!"); - assert(!mMaterial.isNull() && "Trying to render, but no material set!"); - op.useIndexes = true; - op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; - op.vertexData = mVertexData; - op.indexData = mIndexData; - } - - void Chunk::getWorldTransforms(Ogre::Matrix4* xform) const - { - *xform = getParentSceneNode()->_getFullTransform(); - } - - Ogre::Real Chunk::getSquaredViewDepth(const Ogre::Camera* cam) const - { - return getParentSceneNode()->getSquaredViewDepth(cam); - } - - const Ogre::LightList& Chunk::getLights(void) const - { - return queryLights(); - } - -} diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp deleted file mode 100644 index 22b4f26ef4..0000000000 --- a/components/terrain/chunk.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H -#define COMPONENTS_TERRAIN_TERRAINBATCH_H - -#include -#include - -namespace Terrain -{ - - /** - * @brief A movable object representing a chunk of terrain. - */ - class Chunk : public Ogre::Renderable, public Ogre::MovableObject - { - public: - Chunk (Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, - const std::vector& positions, - const std::vector& normals, - const std::vector& colours); - - virtual ~Chunk(); - - /// @param own Should we take ownership of the material? - void setMaterial (const Ogre::MaterialPtr& material, bool own=true); - - void setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer); - - // Inherited from MovableObject - virtual const Ogre::String& getMovableType(void) const { static Ogre::String t = "MW_TERRAIN"; return t; } - virtual const Ogre::AxisAlignedBox& getBoundingBox(void) const; - virtual Ogre::Real getBoundingRadius(void) const; - virtual void _updateRenderQueue(Ogre::RenderQueue* queue); - virtual void visitRenderables(Renderable::Visitor* visitor, - bool debugRenderables = false); - - // Inherited from Renderable - virtual const Ogre::MaterialPtr& getMaterial(void) const; - virtual void getRenderOperation(Ogre::RenderOperation& op); - virtual void getWorldTransforms(Ogre::Matrix4* xform) const; - virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const; - virtual const Ogre::LightList& getLights(void) const; - - private: - Ogre::AxisAlignedBox mBounds; - Ogre::MaterialPtr mMaterial; - bool mOwnMaterial; // Should we remove mMaterial on destruction? - - Ogre::VertexData* mVertexData; - Ogre::IndexData* mIndexData; - }; - -} - -#endif diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp deleted file mode 100644 index 7bc73ddda8..0000000000 --- a/components/terrain/defaultworld.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "defaultworld.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "storage.hpp" -#include "quadtreenode.hpp" - -namespace -{ - - bool isPowerOfTwo(int x) - { - return ( (x > 0) && ((x & (x - 1)) == 0) ); - } - - int nextPowerOfTwo (int v) - { - if (isPowerOfTwo(v)) return v; - int depth=0; - while(v) - { - v >>= 1; - depth++; - } - return 1 << depth; - } - - Terrain::QuadTreeNode* findNode (const Ogre::Vector2& center, Terrain::QuadTreeNode* node) - { - if (center == node->getCenter()) - return node; - - if (center.x > node->getCenter().x && center.y > node->getCenter().y) - return findNode(center, node->getChild(Terrain::NE)); - else if (center.x > node->getCenter().x && center.y < node->getCenter().y) - return findNode(center, node->getChild(Terrain::SE)); - else if (center.x < node->getCenter().x && center.y > node->getCenter().y) - return findNode(center, node->getChild(Terrain::NW)); - else //if (center.x < node->getCenter().x && center.y < node->getCenter().y) - return findNode(center, node->getChild(Terrain::SW)); - } - -} - -namespace Terrain -{ - - const Ogre::uint REQ_ID_CHUNK = 1; - const Ogre::uint REQ_ID_LAYERS = 2; - - DefaultWorld::DefaultWorld(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align, float minBatchSize, float maxBatchSize) - : World(sceneMgr, storage, visibilityFlags, shaders, align) - , mWorkQueueChannel(0) - , mVisible(true) - , mChunksLoading(0) - , mMinX(0) - , mMaxX(0) - , mMinY(0) - , mMaxY(0) - , mMinBatchSize(minBatchSize) - , mMaxBatchSize(maxBatchSize) - , mLayerLoadPending(true) - { -#if TERRAIN_USE_SHADER == 0 - if (mShaders) - std::cerr << "Compiled Terrain without shader support, disabling..." << std::endl; - mShaders = false; -#endif - - mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - /// \todo make composite map size configurable - Ogre::Camera* compositeMapCam = mCompositeMapSceneMgr->createCamera("a"); - mCompositeMapRenderTexture = Ogre::TextureManager::getSingleton().createManual( - "terrain/comp/rt", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, 128, 128, 0, Ogre::PF_A8B8G8R8, Ogre::TU_RENDERTARGET); - mCompositeMapRenderTarget = mCompositeMapRenderTexture->getBuffer()->getRenderTarget(); - mCompositeMapRenderTarget->setAutoUpdated(false); - mCompositeMapRenderTarget->addViewport(compositeMapCam); - - storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); - - int origSizeX = static_cast(mMaxX - mMinX); - int origSizeY = static_cast(mMaxY - mMinY); - - // Dividing a quad tree only works well for powers of two, so round up to the nearest one - int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); - - // Adjust the center according to the new size - float centerX = (mMinX+mMaxX)/2.f + (size-origSizeX)/2.f; - float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f; - - mRootSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - - // While building the quadtree, remember leaf nodes since we need to load their layers - LayersRequestData data; - data.mPack = getShadersEnabled(); - - mRootNode = new QuadTreeNode(this, Root, static_cast(size), Ogre::Vector2(centerX, centerY), NULL); - buildQuadTree(mRootNode, data.mNodes); - //loadingListener->indicateProgress(); - mRootNode->initAabb(); - //loadingListener->indicateProgress(); - mRootNode->initNeighbours(); - //loadingListener->indicateProgress(); - - Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue(); - mWorkQueueChannel = wq->getChannel("LargeTerrain"); - wq->addRequestHandler(mWorkQueueChannel, this); - wq->addResponseHandler(mWorkQueueChannel, this); - - // Start loading layers in the background (for leaf nodes) - wq->addRequest(mWorkQueueChannel, REQ_ID_LAYERS, Ogre::Any(data)); - } - - DefaultWorld::~DefaultWorld() - { - Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue(); - wq->removeRequestHandler(mWorkQueueChannel, this); - wq->removeResponseHandler(mWorkQueueChannel, this); - - delete mRootNode; - } - - void DefaultWorld::buildQuadTree(QuadTreeNode *node, std::vector& leafs) - { - float halfSize = node->getSize()/2.f; - - if (node->getSize() <= mMinBatchSize) - { - // We arrived at a leaf - float minZ,maxZ; - Ogre::Vector2 center = node->getCenter(); - float cellWorldSize = getStorage()->getCellWorldSize(); - if (mStorage->getMinMaxHeights(static_cast(node->getSize()), center, minZ, maxZ)) - { - Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), - Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); - convertBounds(bounds); - node->setBoundingBox(bounds); - leafs.push_back(node); - } - else - node->markAsDummy(); // no data available for this node, skip it - return; - } - - if (node->getCenter().x - halfSize > mMaxX - || node->getCenter().x + halfSize < mMinX - || node->getCenter().y - halfSize > mMaxY - || node->getCenter().y + halfSize < mMinY ) - // Out of bounds of the actual terrain - this will happen because - // we rounded the size up to the next power of two - { - node->markAsDummy(); - return; - } - - // Not a leaf, create its children - node->createChild(SW, halfSize, node->getCenter() - halfSize/2.f); - node->createChild(SE, halfSize, node->getCenter() + Ogre::Vector2(halfSize/2.f, -halfSize/2.f)); - node->createChild(NW, halfSize, node->getCenter() + Ogre::Vector2(-halfSize/2.f, halfSize/2.f)); - node->createChild(NE, halfSize, node->getCenter() + halfSize/2.f); - buildQuadTree(node->getChild(SW), leafs); - buildQuadTree(node->getChild(SE), leafs); - buildQuadTree(node->getChild(NW), leafs); - buildQuadTree(node->getChild(NE), leafs); - - // if all children are dummy, we are also dummy - for (int i=0; i<4; ++i) - { - if (!node->getChild((ChildDirection)i)->isDummy()) - return; - } - node->markAsDummy(); - } - - void DefaultWorld::update(const Ogre::Vector3& cameraPos) - { - if (!mVisible) - return; - mRootNode->update(cameraPos); - mRootNode->updateIndexBuffers(); - } - - Ogre::AxisAlignedBox DefaultWorld::getWorldBoundingBox (const Ogre::Vector2& center) - { - if (center.x > mMaxX - || center.x < mMinX - || center.y > mMaxY - || center.y < mMinY) - return Ogre::AxisAlignedBox::BOX_NULL; - QuadTreeNode* node = findNode(center, mRootNode); - return node->getWorldBoundingBox(); - } - - void DefaultWorld::renderCompositeMap(Ogre::TexturePtr target) - { - mCompositeMapRenderTarget->update(); - target->getBuffer()->blit(mCompositeMapRenderTexture->getBuffer()); - } - - void DefaultWorld::clearCompositeMapSceneManager() - { - mCompositeMapSceneMgr->destroyAllManualObjects(); - mCompositeMapSceneMgr->clearScene(); - } - - void DefaultWorld::applyMaterials(bool shadows, bool splitShadows) - { - mShadows = shadows; - mSplitShadows = splitShadows; - mRootNode->applyMaterials(); - } - - void DefaultWorld::setVisible(bool visible) - { - if (visible && !mVisible) - mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode); - else if (!visible && mVisible) - mSceneMgr->getRootSceneNode()->removeChild(mRootSceneNode); - - mVisible = visible; - } - - bool DefaultWorld::getVisible() - { - return mVisible; - } - - void DefaultWorld::syncLoad() - { - while (mChunksLoading || mLayerLoadPending) - { - OGRE_THREAD_SLEEP(0); - Ogre::Root::getSingleton().getWorkQueue()->processResponses(); - } - } - - Ogre::WorkQueue::Response* DefaultWorld::handleRequest(const Ogre::WorkQueue::Request *req, const Ogre::WorkQueue *srcQ) - { - if (req->getType() == REQ_ID_CHUNK) - { - const LoadRequestData data = Ogre::any_cast(req->getData()); - - QuadTreeNode* node = data.mNode; - - LoadResponseData* responseData = new LoadResponseData(); - - getStorage()->fillVertexBuffers(node->getNativeLodLevel(), static_cast(node->getSize()), node->getCenter(), getAlign(), - responseData->mPositions, responseData->mNormals, responseData->mColours); - - return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); - } - else // REQ_ID_LAYERS - { - const LayersRequestData data = Ogre::any_cast(req->getData()); - - LayersResponseData* responseData = new LayersResponseData(); - - getStorage()->getBlendmaps(data.mNodes, responseData->mLayerCollections, data.mPack); - - return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); - } - } - - void DefaultWorld::handleResponse(const Ogre::WorkQueue::Response *res, const Ogre::WorkQueue *srcQ) - { - assert(res->succeeded() && "Response failure not handled"); - - if (res->getRequest()->getType() == REQ_ID_CHUNK) - { - LoadResponseData* data = Ogre::any_cast(res->getData()); - - const LoadRequestData requestData = Ogre::any_cast(res->getRequest()->getData()); - - requestData.mNode->load(*data); - - delete data; - - --mChunksLoading; - } - else // REQ_ID_LAYERS - { - LayersResponseData* data = Ogre::any_cast(res->getData()); - - for (std::vector::iterator it = data->mLayerCollections.begin(); it != data->mLayerCollections.end(); ++it) - { - it->mTarget->loadLayers(*it); - } - - delete data; - - mRootNode->loadMaterials(); - - mLayerLoadPending = false; - } - } - - void DefaultWorld::queueLoad(QuadTreeNode *node) - { - LoadRequestData data; - data.mNode = node; - - Ogre::Root::getSingleton().getWorkQueue()->addRequest(mWorkQueueChannel, REQ_ID_CHUNK, Ogre::Any(data)); - ++mChunksLoading; - } -} diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp deleted file mode 100644 index 4caef8462f..0000000000 --- a/components/terrain/defaultworld.hpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_H -#define COMPONENTS_TERRAIN_H - -#include -#include -#include - -#include "world.hpp" - -namespace Ogre -{ - class Camera; -} - -namespace Terrain -{ - - class QuadTreeNode; - class Storage; - - /** - * @brief A quadtree-based terrain implementation suitable for large data sets. \n - * Near cells are rendered with alpha splatting, distant cells are merged - * together in batches and have their layers pre-rendered onto a composite map. \n - * Cracks at LOD transitions are avoided using stitching. - * @note Multiple cameras are not supported yet - */ - class DefaultWorld : public World, public Ogre::WorkQueue::RequestHandler, public Ogre::WorkQueue::ResponseHandler - { - public: - /// @note takes ownership of \a storage - /// @param sceneMgr scene manager to use - /// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..) - /// @param visbilityFlags visibility flags for the created meshes - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - /// @param minBatchSize Minimum size of a terrain batch along one side (in cell units). Used for building the quad tree. - /// @param maxBatchSize Maximum size of a terrain batch along one side (in cell units). Used when traversing the quad tree. - DefaultWorld(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align, float minBatchSize, float maxBatchSize); - ~DefaultWorld(); - - /// Update chunk LODs according to this camera position - /// @note Calling this method might lead to composite textures being rendered, so it is best - /// not to call it when render commands are still queued, since that would cause a flush. - virtual void update (const Ogre::Vector3& cameraPos); - - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center); - - Ogre::SceneNode* getRootSceneNode() { return mRootSceneNode; } - - /// Show or hide the whole terrain - /// @note this setting will be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible); - virtual bool getVisible(); - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows); - - int getMaxBatchSize() { return static_cast(mMaxBatchSize); } - - /// Wait until all background loading is complete. - void syncLoad(); - - private: - // Called from a background worker thread - virtual Ogre::WorkQueue::Response* handleRequest(const Ogre::WorkQueue::Request* req, const Ogre::WorkQueue* srcQ); - // Called from the main thread - virtual void handleResponse(const Ogre::WorkQueue::Response* res, const Ogre::WorkQueue* srcQ); - Ogre::uint16 mWorkQueueChannel; - - bool mVisible; - - QuadTreeNode* mRootNode; - Ogre::SceneNode* mRootSceneNode; - - /// The number of chunks currently loading in a background thread. If 0, we have finished loading! - int mChunksLoading; - - Ogre::SceneManager* mCompositeMapSceneMgr; - - /// Bounds in cell units - float mMinX, mMaxX, mMinY, mMaxY; - - /// Minimum size of a terrain batch along one side (in cell units) - float mMinBatchSize; - /// Maximum size of a terrain batch along one side (in cell units) - float mMaxBatchSize; - - void buildQuadTree(QuadTreeNode* node, std::vector& leafs); - - // Are layers for leaf nodes loaded? This is done once at startup (but in a background thread) - bool mLayerLoadPending; - - public: - // ----INTERNAL---- - Ogre::SceneManager* getCompositeMapSceneManager() { return mCompositeMapSceneMgr; } - - bool areLayersLoaded() { return !mLayerLoadPending; } - - // Delete all quads - void clearCompositeMapSceneManager(); - void renderCompositeMap (Ogre::TexturePtr target); - - // Adds a WorkQueue request to load a chunk for this node in the background. - void queueLoad (QuadTreeNode* node); - - private: - Ogre::RenderTarget* mCompositeMapRenderTarget; - Ogre::TexturePtr mCompositeMapRenderTexture; - }; - - struct LoadRequestData - { - QuadTreeNode* mNode; - - friend std::ostream& operator<<(std::ostream& o, const LoadRequestData& r) - { return o; } - }; - - struct LoadResponseData - { - std::vector mPositions; - std::vector mNormals; - std::vector mColours; - - friend std::ostream& operator<<(std::ostream& o, const LoadResponseData& r) - { return o; } - }; - - struct LayersRequestData - { - std::vector mNodes; - bool mPack; - - friend std::ostream& operator<<(std::ostream& o, const LayersRequestData& r) - { return o; } - }; - - struct LayersResponseData - { - std::vector mLayerCollections; - - friend std::ostream& operator<<(std::ostream& o, const LayersResponseData& r) - { return o; } - }; - -} - -#endif diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 6d173d1361..7b40ad4792 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -22,41 +22,10 @@ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP +#include + namespace Terrain { - class QuadTreeNode; - - /// The alignment of the terrain - enum Alignment - { - /// Terrain is in the X/Z plane - Align_XZ = 0, - /// Terrain is in the X/Y plane - Align_XY = 1, - /// Terrain is in the Y/Z plane. - /// UNTESTED - use at own risk. - /// Besides, X as up axis? What is wrong with you? ;) - Align_YZ = 2 - }; - - inline void convertPosition(Alignment align, float &x, float &y, float &z) - { - switch (align) - { - case Align_XY: - return; - case Align_XZ: - std::swap(y, z); - // This is since -Z should be going *into* the screen - // If not doing this, we'd get wrong vertex winding - z *= -1; - return; - case Align_YZ: - std::swap(x, y); - std::swap(y, z); - return; - } - } enum Direction { @@ -74,13 +43,6 @@ namespace Terrain bool mSpecular; // Specular info in diffuse map alpha channel? }; - struct LayerCollection - { - QuadTreeNode* mTarget; - // Since we can't create a texture from a different thread, this only holds the raw texel data - std::vector mBlendmaps; - std::vector mLayers; - }; } #endif diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 4d2318aa6b..17acd940b9 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -21,353 +21,86 @@ */ #include "material.hpp" -#include -#include -#include +#include -#include +#include +#include +#include +#include +#include -#if TERRAIN_USE_SHADER -#include -#endif - -namespace -{ - -int getBlendmapIndexForLayer (int layerIndex) -{ - return static_cast(std::floor((layerIndex - 1) / 4.f)); -} - -std::string getBlendmapComponentForLayer (int layerIndex) -{ - int n = (layerIndex-1)%4; - if (n == 0) - return "x"; - if (n == 1) - return "y"; - if (n == 2) - return "z"; - else - return "w"; -} - -} +#include namespace Terrain { - MaterialGenerator::MaterialGenerator() - : mShaders(true) - , mShadows(false) - , mSplitShadows(false) - , mNormalMapping(true) - , mParallaxMapping(true) + FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, + const std::vector >& blendmaps) { - - } - - Ogre::MaterialPtr MaterialGenerator::generate() - { - assert(!mLayerList.empty() && "Can't create material with no layers"); - - return create(false, false); - } - - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMapRTT() - { - assert(!mLayerList.empty() && "Can't create material with no layers"); - - return create(true, false); - } - - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMap() - { - return create(false, true); - } - - Ogre::MaterialPtr MaterialGenerator::create(bool renderCompositeMap, bool displayCompositeMap) - { - assert(!renderCompositeMap || !displayCompositeMap); - - static int count = 0; - std::stringstream name; - name << "terrain/mat" << count++; - - if (!mShaders) + bool firstLayer = true; + int i=0; + for (std::vector >::const_iterator it = layers.begin(); it != layers.end(); ++it) { - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(name.str(), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - Ogre::Technique* technique = mat->getTechnique(0); - technique->removeAllPasses(); + osg::ref_ptr stateset (new osg::StateSet); - if (displayCompositeMap) + if (!firstLayer) { - Ogre::Pass* pass = technique->createPass(); - pass->setVertexColourTracking(Ogre::TVC_AMBIENT|Ogre::TVC_DIFFUSE); - pass->createTextureUnitState(mCompositeMap)->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); - } - else - { - assert(mLayerList.size() == mBlendmapList.size()+1); - std::vector::iterator blend = mBlendmapList.begin(); - for (std::vector::iterator layer = mLayerList.begin(); layer != mLayerList.end(); ++layer) - { - Ogre::Pass* pass = technique->createPass(); - pass->setLightingEnabled(false); - pass->setVertexColourTracking(Ogre::TVC_NONE); - // TODO: How to handle fog? - pass->setFog(true, Ogre::FOG_NONE); - - bool first = (layer == mLayerList.begin()); - - Ogre::TextureUnitState* tus; - - if (!first) - { - pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); - pass->setDepthFunction(Ogre::CMPF_EQUAL); - - tus = pass->createTextureUnitState((*blend)->getName()); - tus->setAlphaOperation(Ogre::LBX_BLEND_TEXTURE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_TEXTURE); - tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_TEXTURE); - tus->setIsAlpha(true); - tus->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); - - float scale = (16/(16.f+1.f)); - tus->setTextureScale(1.f/scale,1.f/scale); - } - - // Add the actual layer texture on top of the alpha map. - tus = pass->createTextureUnitState(layer->mDiffuseMap); - if (!first) - tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA, - Ogre::LBS_TEXTURE, - Ogre::LBS_CURRENT); - - tus->setTextureScale(1/16.f,1/16.f); - - if (!first) - ++blend; - } - - if (!renderCompositeMap) - { - Ogre::Pass* lightingPass = technique->createPass(); - lightingPass->setSceneBlending(Ogre::SBT_MODULATE); - lightingPass->setVertexColourTracking(Ogre::TVC_AMBIENT|Ogre::TVC_DIFFUSE); - lightingPass->setFog(true, Ogre::FOG_NONE); - } + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::EQUAL); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); } - return mat; + int texunit = 0; + if(!firstLayer) + { + osg::ref_ptr blendmap = blendmaps.at(i++); + + stateset->setTextureAttributeAndModes(texunit, blendmap.get()); + + // This is to map corner vertices directly to the center of a blendmap texel. + osg::Matrixf texMat; + float scale = (16/(16.f+1.f)); + texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); + texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); + texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); + + stateset->setTextureAttributeAndModes(texunit, new osg::TexMat(texMat)); + + ++texunit; + } + + // Add the actual layer texture multiplied by the alpha map. + osg::ref_ptr tex = *it; + stateset->setTextureAttributeAndModes(texunit, tex.get()); + + osg::ref_ptr texMat (new osg::TexMat); + float scale = 16.f; + texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(scale,scale,1.f))); + stateset->setTextureAttributeAndModes(texunit, texMat, osg::StateAttribute::ON); + + firstLayer = false; + + addPass(stateset); } -#if TERRAIN_USE_SHADER - else - { - sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance (name.str()); - material->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); + } - if (displayCompositeMap) - { - sh::MaterialInstancePass* p = material->createPass (); + Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps) + : mLayers(layers) + , mBlendmaps(blendmaps) + { + osg::ref_ptr material (new osg::Material); + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + getOrCreateStateSet()->setAttributeAndModes(material, osg::StateAttribute::ON); - 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 ("is_first_pass", sh::makeProperty(new sh::BooleanValue(true))); - p->mShaderProperties.setProperty ("render_composite_map", sh::makeProperty(new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(true))); - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue("0"))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue("0"))); - p->mShaderProperties.setProperty ("normal_map_enabled", sh::makeProperty (new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("parallax_enabled", sh::makeProperty (new sh::BooleanValue(false))); - p->mShaderProperties.setProperty ("normal_maps", - sh::makeProperty (new sh::IntValue(0))); + selectTechnique(0); + } - sh::MaterialInstanceTextureUnit* tex = p->createTextureUnit ("compositeMap"); - tex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mCompositeMap))); - tex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + bool Effect::define_techniques() + { + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); - // shadow. TODO: repeated, put in function - if (mShadows) - { - for (int i = 0; i < (mSplitShadows ? 3 : 1); ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } - } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( - Ogre::StringConverter::toString(1)))); - - p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(0))); - } - else - { - - bool shadows = mShadows && !renderCompositeMap; - - int layerOffset = 0; - while (layerOffset < (int)mLayerList.size()) - { - int blendmapOffset = (layerOffset == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map - - // Check how many layers we can fit in this pass - int numLayersInThisPass = 0; - int numBlendTextures = 0; - std::vector blendTextures; - int remainingTextureUnits = OGRE_MAX_TEXTURE_LAYERS; - if (shadows) - remainingTextureUnits -= (mSplitShadows ? 3 : 1); - while (remainingTextureUnits && layerOffset + numLayersInThisPass < (int)mLayerList.size()) - { - int layerIndex = numLayersInThisPass + layerOffset; - - int neededTextureUnits=0; - int neededBlendTextures=0; - - if (layerIndex != 0) - { - std::string blendTextureName = mBlendmapList[getBlendmapIndexForLayer(layerIndex)]->getName(); - if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) - { - blendTextures.push_back(blendTextureName); - ++neededBlendTextures; - ++neededTextureUnits; // blend texture - } - } - ++neededTextureUnits; // layer texture - - // Check if this layer has a normal map - if (mNormalMapping && !mLayerList[layerIndex].mNormalMap.empty() && !renderCompositeMap) - ++neededTextureUnits; // normal map - if (neededTextureUnits <= remainingTextureUnits) - { - // We can fit another! - remainingTextureUnits -= neededTextureUnits; - numBlendTextures += neededBlendTextures; - ++numLayersInThisPass; - } - else - break; // We're full - } - - - sh::MaterialInstancePass* p = material->createPass (); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - if (layerOffset != 0) - { - p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); - // Only write if depth is equal to the depth value written by the previous pass. - p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); - } - - p->mShaderProperties.setProperty ("render_composite_map", sh::makeProperty(new sh::BooleanValue(renderCompositeMap))); - p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(displayCompositeMap))); - - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); - p->mShaderProperties.setProperty ("normal_map_enabled", - sh::makeProperty (new sh::BooleanValue(false))); - - // blend maps - // the index of the first blend map used in this pass - int blendmapStart; - if (mLayerList.size() == 1) // special case. if there's only one layer, we don't need blend maps at all - blendmapStart = 0; - else - blendmapStart = getBlendmapIndexForLayer(layerOffset+blendmapOffset); - for (int i = 0; i < numBlendTextures; ++i) - { - sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); - blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mBlendmapList[blendmapStart+i]->getName()))); - blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - } - - // layer maps - bool anyNormalMaps = false; - bool anyParallax = false; - size_t normalMaps = 0; - for (int i = 0; i < numLayersInThisPass; ++i) - { - const LayerInfo& layer = mLayerList[layerOffset+i]; - // diffuse map - sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); - diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mDiffuseMap))); - - // normal map (optional) - bool useNormalMap = mNormalMapping && !mLayerList[layerOffset+i].mNormalMap.empty() && !renderCompositeMap; - bool useParallax = useNormalMap && mParallaxMapping && layer.mParallax; - bool useSpecular = layer.mSpecular; - if (useNormalMap) - { - anyNormalMaps = true; - anyParallax = anyParallax || useParallax; - sh::MaterialInstanceTextureUnit* normalTex = p->createTextureUnit ("normalMap" + Ogre::StringConverter::toString(i)); - normalTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mNormalMap))); - } - p->mShaderProperties.setProperty ("use_normal_map_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useNormalMap))); - p->mShaderProperties.setProperty ("use_parallax_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useParallax))); - p->mShaderProperties.setProperty ("use_specular_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::BooleanValue(useSpecular))); - boost::hash_combine(normalMaps, useNormalMap); - boost::hash_combine(normalMaps, useNormalMap && layer.mParallax); - boost::hash_combine(normalMaps, useSpecular); - - if (i+layerOffset > 0) - { - int blendTextureIndex = getBlendmapIndexForLayer(layerOffset+i); - std::string blendTextureComponent = getBlendmapComponentForLayer(layerOffset+i); - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + blendTextureComponent))); - } - else - { - // just to make it shut up about blendmap_component_0 not existing in the first pass. - // it might be retrieved, but will never survive the preprocessing step. - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty (new sh::StringValue(""))); - } - } - p->mShaderProperties.setProperty ("normal_map_enabled", - sh::makeProperty (new sh::BooleanValue(anyNormalMaps))); - p->mShaderProperties.setProperty ("parallax_enabled", - sh::makeProperty (new sh::BooleanValue(anyParallax))); - // Since the permutation handler can't handle dynamic property names, - // combine normal map settings for all layers into one value - p->mShaderProperties.setProperty ("normal_maps", - sh::makeProperty (new sh::IntValue(normalMaps))); - - // shadow - if (shadows) - { - for (int i = 0; i < (mSplitShadows ? 3 : 1); ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } - } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( - Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass)))); - - // Make sure the pass index is fed to the permutation handler, because blendmap components may be different - p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(layerOffset))); - - assert ((int)p->mTexUnits.size() == OGRE_MAX_TEXTURE_LAYERS - remainingTextureUnits); - - layerOffset += numLayersInThisPass; - } - } - } -#endif - return Ogre::MaterialManager::getSingleton().getByName(name.str()); + return true; } } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b79df9f48c..47c5142c94 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -22,51 +22,55 @@ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H -#include +#include +#include -#include "storage.hpp" +#include "defs.hpp" + +namespace osg +{ + class Texture2D; +} namespace Terrain { - class MaterialGenerator + class FixedFunctionTechnique : public osgFX::Technique { public: - MaterialGenerator (); + FixedFunctionTechnique( + const std::vector >& layers, + const std::vector >& blendmaps); - void setLayerList (const std::vector& layerList) { mLayerList = layerList; } - bool hasLayers() { return mLayerList.size() > 0; } - void setBlendmapList (const std::vector& blendmapList) { mBlendmapList = blendmapList; } - const std::vector& getBlendmapList() { return mBlendmapList; } - void setCompositeMap (const std::string& name) { mCompositeMap = name; } + protected: + virtual void define_passes() {} + }; - void enableShaders(bool shaders) { mShaders = shaders; } - void enableShadows(bool shadows) { mShadows = shadows; } - void enableNormalMapping(bool normalMapping) { mNormalMapping = normalMapping; } - void enableParallaxMapping(bool parallaxMapping) { mParallaxMapping = parallaxMapping; } - void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; } + class Effect : public osgFX::Effect + { + public: + Effect( + const std::vector >& layers, + const std::vector >& blendmaps); - /// Creates a material suitable for displaying a chunk of terrain using alpha-blending. - Ogre::MaterialPtr generate (); + virtual bool define_techniques(); - /// Creates a material suitable for displaying a chunk of terrain using a ready-made composite map. - Ogre::MaterialPtr generateForCompositeMap (); - - /// Creates a material suitable for rendering composite maps, i.e. for "baking" several layer textures - /// into one. The main difference compared to a normal material is that no shading is applied at this point. - Ogre::MaterialPtr generateForCompositeMapRTT (); + virtual const char *effectName() const + { + return NULL; + } + virtual const char *effectDescription() const + { + return NULL; + } + virtual const char *effectAuthor() const + { + return NULL; + } private: - Ogre::MaterialPtr create (bool renderCompositeMap, bool displayCompositeMap); - - std::vector mLayerList; - std::vector mBlendmapList; - std::string mCompositeMap; - bool mShaders; - bool mShadows; - bool mSplitShadows; - bool mNormalMapping; - bool mParallaxMapping; + std::vector > mLayers; + std::vector > mBlendmaps; }; } diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp deleted file mode 100644 index 89e5e34a36..0000000000 --- a/components/terrain/quadtreenode.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "quadtreenode.hpp" - -#include -#include -#include -#include -#include - -#include "defaultworld.hpp" -#include "chunk.hpp" -#include "storage.hpp" -#include "buffercache.hpp" -#include "material.hpp" - -using namespace Terrain; - -namespace -{ - int Log2( int n ) - { - assert(n > 0); - int targetlevel = 0; - while (n >>= 1) ++targetlevel; - return targetlevel; - } - - // Utility functions for neighbour finding algorithm - ChildDirection reflect(ChildDirection dir, Direction dir2) - { - assert(dir != Root); - - const int lookupTable[4][4] = - { - // NW NE SW SE - { SW, SE, NW, NE }, // N - { NE, NW, SE, SW }, // E - { SW, SE, NW, NE }, // S - { NE, NW, SE, SW } // W - }; - return (ChildDirection)lookupTable[dir2][dir]; - } - - bool adjacent(ChildDirection dir, Direction dir2) - { - assert(dir != Root); - const bool lookupTable[4][4] = - { - // NW NE SW SE - { true, true, false, false }, // N - { false, true, false, true }, // E - { false, false, true, true }, // S - { true, false, true, false } // W - }; - return lookupTable[dir2][dir]; - } - - // Algorithm described by Hanan Samet - 'Neighbour Finding in Quadtrees' - // http://www.cs.umd.edu/~hjs/pubs/SametPRIP81.pdf - QuadTreeNode* searchNeighbourRecursive (QuadTreeNode* currentNode, Direction dir) - { - if (!currentNode->getParent()) - return NULL; // Arrived at root node, the root node does not have neighbours - - QuadTreeNode* nextNode; - if (adjacent(currentNode->getDirection(), dir)) - nextNode = searchNeighbourRecursive(currentNode->getParent(), dir); - else - nextNode = currentNode->getParent(); - - if (nextNode && nextNode->hasChildren()) - return nextNode->getChild(reflect(currentNode->getDirection(), dir)); - else - return NULL; - } - - // Create a 2D quad - void makeQuad(Ogre::SceneManager* sceneMgr, float left, float top, float right, float bottom, Ogre::MaterialPtr material) - { - Ogre::ManualObject* manual = sceneMgr->createManualObject(); - - // Use identity view/projection matrices to get a 2d quad - manual->setUseIdentityProjection(true); - manual->setUseIdentityView(true); - - manual->begin(material->getName()); - - float normLeft = left*2-1; - float normTop = top*2-1; - float normRight = right*2-1; - float normBottom = bottom*2-1; - - manual->position(normLeft, normTop, 0.0); - manual->textureCoord(0, 1); - manual->position(normRight, normTop, 0.0); - manual->textureCoord(1, 1); - manual->position(normRight, normBottom, 0.0); - manual->textureCoord(1, 0); - manual->position(normLeft, normBottom, 0.0); - manual->textureCoord(0, 0); - - manual->quad(0,1,2,3); - - manual->end(); - - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - manual->setBoundingBox(aabInf); - - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } -} - -QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) - : mMaterialGenerator(NULL) - , mLoadState(LS_Unloaded) - , mIsDummy(false) - , mSize(size) - , mLodLevel(Log2(static_cast(mSize))) - , mBounds(Ogre::AxisAlignedBox::BOX_NULL) - , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) - , mDirection(dir) - , mCenter(center) - , mSceneNode(NULL) - , mParent(parent) - , mChunk(NULL) - , mTerrain(terrain) -{ - mBounds.setNull(); - for (int i=0; i<4; ++i) - mChildren[i] = NULL; - for (int i=0; i<4; ++i) - mNeighbours[i] = NULL; - - if (mDirection == Root) - mSceneNode = mTerrain->getRootSceneNode(); - else - mSceneNode = mTerrain->getSceneManager()->createSceneNode(); - Ogre::Vector2 pos (0,0); - if (mParent) - pos = mParent->getCenter(); - pos = mCenter - pos; - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - - Ogre::Vector3 sceneNodePos (pos.x*cellWorldSize, pos.y*cellWorldSize, 0); - mTerrain->convertPosition(sceneNodePos); - - mSceneNode->setPosition(sceneNodePos); - - mMaterialGenerator = new MaterialGenerator(); - mMaterialGenerator->enableShaders(mTerrain->getShadersEnabled()); -} - -void QuadTreeNode::createChild(ChildDirection id, float size, const Ogre::Vector2 ¢er) -{ - mChildren[id] = new QuadTreeNode(mTerrain, id, size, center, this); -} - -QuadTreeNode::~QuadTreeNode() -{ - for (int i=0; i<4; ++i) - delete mChildren[i]; - delete mChunk; - delete mMaterialGenerator; -} - -QuadTreeNode* QuadTreeNode::getNeighbour(Direction dir) -{ - return mNeighbours[static_cast(dir)]; -} - -void QuadTreeNode::initNeighbours() -{ - for (int i=0; i<4; ++i) - mNeighbours[i] = searchNeighbourRecursive(this, (Direction)i); - - if (hasChildren()) - for (int i=0; i<4; ++i) - mChildren[i]->initNeighbours(); -} - -void QuadTreeNode::initAabb() -{ - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - if (hasChildren()) - { - for (int i=0; i<4; ++i) - { - mChildren[i]->initAabb(); - mBounds.merge(mChildren[i]->getBoundingBox()); - } - float minH, maxH; - switch (mTerrain->getAlign()) - { - case Terrain::Align_XY: - minH = mBounds.getMinimum().z; - maxH = mBounds.getMaximum().z; - break; - case Terrain::Align_XZ: - minH = mBounds.getMinimum().y; - maxH = mBounds.getMaximum().y; - break; - case Terrain::Align_YZ: - minH = mBounds.getMinimum().x; - maxH = mBounds.getMaximum().x; - break; - } - Ogre::Vector3 min(-mSize/2*cellWorldSize, -mSize/2*cellWorldSize, minH); - Ogre::Vector3 max(Ogre::Vector3(mSize/2*cellWorldSize, mSize/2*cellWorldSize, maxH)); - mBounds = Ogre::AxisAlignedBox (min, max); - mTerrain->convertBounds(mBounds); - } - Ogre::Vector3 offset(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0); - mTerrain->convertPosition(offset); - mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + offset, - mBounds.getMaximum() + offset); -} - -void QuadTreeNode::setBoundingBox(const Ogre::AxisAlignedBox &box) -{ - mBounds = box; -} - -const Ogre::AxisAlignedBox& QuadTreeNode::getBoundingBox() -{ - return mBounds; -} - -const Ogre::AxisAlignedBox& QuadTreeNode::getWorldBoundingBox() -{ - return mWorldBounds; -} - -bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos) -{ - if (isDummy()) - return true; - - if (mBounds.isNull()) - return true; - - float dist = mWorldBounds.distance(cameraPos); - - // Make sure our scene node is attached - if (!mSceneNode->isInSceneGraph()) - { - mParent->getSceneNode()->addChild(mSceneNode); - } - - // Simple LOD selection - /// \todo use error metrics? - size_t wantedLod = 0; - float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); - - if (dist > cellWorldSize*64) - wantedLod = 6; - else if (dist > cellWorldSize*32) - wantedLod = 5; - else if (dist > cellWorldSize*12) - wantedLod = 4; - else if (dist > cellWorldSize*5) - wantedLod = 3; - else if (dist > cellWorldSize*2) - wantedLod = 2; - else if (dist > cellWorldSize * 1.42) // < sqrt2 so the 3x3 grid around player is always highest lod - wantedLod = 1; - - bool wantToDisplay = mSize <= mTerrain->getMaxBatchSize() && mLodLevel <= wantedLod; - - if (wantToDisplay) - { - // Wanted LOD is small enough to render this node in one chunk - if (mLoadState == LS_Unloaded) - { - mLoadState = LS_Loading; - mTerrain->queueLoad(this); - return false; - } - - if (mLoadState == LS_Loaded) - { - // Additional (index buffer) LOD is currently disabled. - // This is due to a problem with the LOD selection when a node splits. - // After splitting, the distance is measured from the children's bounding boxes, which are possibly - // further away than the original node's bounding box, possibly causing a child to switch to a *lower* LOD - // than the original node. - // In short, we'd sometimes get a switch to a lesser detail when actually moving closer. - // This wouldn't be so bad, but unfortunately it also breaks LOD edge connections if a neighbour - // node hasn't split yet, and has a higher LOD than our node's child: - // ----- ----- ------------ - // | LOD | LOD | | - // | 1 | 1 | | - // |-----|-----| LOD 0 | - // | LOD | LOD | | - // | 0 | 0 | | - // ----- ----- ------------ - // To prevent this, nodes of the same size need to always select the same LOD, which is basically what we're - // doing here. - // But this "solution" does increase triangle overhead, so eventually we need to find a more clever way. - //mChunk->setAdditionalLod(wantedLod - mLodLevel); - - if (!mChunk->getVisible() && hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->unload(true); - } - mChunk->setVisible(true); - - return true; - } - return false; // LS_Loading - } - - // We do not want to display this node - delegate to children if they are already loaded - if (!wantToDisplay && hasChildren()) - { - if (mChunk) - { - // Are children already loaded? - bool childrenLoaded = true; - for (int i=0; i<4; ++i) - if (!mChildren[i]->update(cameraPos)) - childrenLoaded = false; - - if (!childrenLoaded) - { - mChunk->setVisible(true); - // Make sure child scene nodes are detached until all children are loaded - mSceneNode->removeAllChildren(); - } - else - { - // Delegation went well, we can unload now - unload(); - - for (int i=0; i<4; ++i) - { - if (!mChildren[i]->getSceneNode()->isInSceneGraph()) - mSceneNode->addChild(mChildren[i]->getSceneNode()); - } - } - return true; - } - else - { - bool success = true; - for (int i=0; i<4; ++i) - success = mChildren[i]->update(cameraPos) & success; - return success; - } - } - return false; -} - -void QuadTreeNode::load(const LoadResponseData &data) -{ - assert (!mChunk); - - mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data.mPositions, data.mNormals, data.mColours); - mChunk->setVisibilityFlags(mTerrain->getVisibilityFlags()); - mChunk->setCastShadows(true); - mSceneNode->attachObject(mChunk); - - mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); - mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); - - if (mTerrain->areLayersLoaded()) - { - if (mSize == 1) - { - mChunk->setMaterial(mMaterialGenerator->generate()); - } - else - { - ensureCompositeMap(); - mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - } - // else: will be loaded in loadMaterials() after background thread has finished loading layers - mChunk->setVisible(false); - - mLoadState = LS_Loaded; -} - -void QuadTreeNode::unload(bool recursive) -{ - if (mChunk) - { - mSceneNode->detachObject(mChunk); - - delete mChunk; - mChunk = NULL; - - if (!mCompositeMap.isNull()) - { - Ogre::TextureManager::getSingleton().remove(mCompositeMap->getName()); - mCompositeMap.setNull(); - } - - // Do *not* set this when we are still loading! - mLoadState = LS_Unloaded; - } - - if (recursive && hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->unload(true); - } -} - -void QuadTreeNode::updateIndexBuffers() -{ - if (hasChunk()) - { - // Fetch a suitable index buffer (which may be shared) - size_t ourLod = getActualLodLevel(); - - unsigned int flags = 0; - - for (int i=0; i<4; ++i) - { - QuadTreeNode* neighbour = getNeighbour((Direction)i); - - // If the neighbour isn't currently rendering itself, - // go up until we find one. NOTE: We don't need to go down, - // because in that case neighbour's detail would be higher than - // our detail and the neighbour would handle stitching by itself. - while (neighbour && !neighbour->hasChunk()) - neighbour = neighbour->getParent(); - size_t lod = 0; - if (neighbour) - lod = neighbour->getActualLodLevel(); - if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are - - lod = 0; // neighbours with more detail will do the stitching themselves - // Use 4 bits for each LOD delta - if (lod > 0) - { - assert (lod - ourLod < (1 << 4)); - flags |= static_cast(lod - ourLod) << (4*i); - } - } - flags |= 0 /*((int)mAdditionalLod)*/ << (4*4); - - mChunk->setIndexBuffer(mTerrain->getBufferCache().getIndexBuffer(flags)); - } - else if (hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->updateIndexBuffers(); - } -} - -bool QuadTreeNode::hasChunk() -{ - return mSceneNode->isInSceneGraph() && mChunk && mChunk->getVisible(); -} - -size_t QuadTreeNode::getActualLodLevel() -{ - assert(hasChunk() && "Can't get actual LOD level if this node has no render chunk"); - return mLodLevel /* + mChunk->getAdditionalLod() */; -} - -void QuadTreeNode::loadLayers(const LayerCollection& collection) -{ - assert (!mMaterialGenerator->hasLayers()); - - std::vector blendTextures; - for (std::vector::const_iterator it = collection.mBlendmaps.begin(); it != collection.mBlendmaps.end(); ++it) - { - // TODO: clean up blend textures on destruction - static int count=0; - Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" - + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, it->getWidth(), it->getHeight(), 0, it->format); - - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(it->data, it->getWidth()*it->getHeight()*Ogre::PixelUtil::getNumElemBytes(it->format), true)); - map->loadRawData(stream, it->getWidth(), it->getHeight(), it->format); - blendTextures.push_back(map); - } - - mMaterialGenerator->setLayerList(collection.mLayers); - mMaterialGenerator->setBlendmapList(blendTextures); -} - -void QuadTreeNode::loadMaterials() -{ - if (isDummy()) - return; - - // Load children first since we depend on them when creating a composite map - if (hasChildren()) - { - for (int i=0; i<4; ++i) - mChildren[i]->loadMaterials(); - } - - if (mChunk) - { - if (mSize == 1) - { - mChunk->setMaterial(mMaterialGenerator->generate()); - } - else - { - ensureCompositeMap(); - mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - } -} - -void QuadTreeNode::prepareForCompositeMap(Ogre::TRect area) -{ - Ogre::SceneManager* sceneMgr = mTerrain->getCompositeMapSceneManager(); - - if (mIsDummy) - { - // TODO - store this default material somewhere instead of creating one for each empty cell - MaterialGenerator matGen; - matGen.enableShaders(mTerrain->getShadersEnabled()); - std::vector layer; - layer.push_back(mTerrain->getStorage()->getDefaultLayer()); - matGen.setLayerList(layer); - makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT()); - return; - } - if (mSize > 1) - { - assert(hasChildren()); - - // 0,0 -------- 1,0 - // | | | - // |-----|------| - // | | | - // 0,1 -------- 1,1 - - float halfW = area.width()/2.f; - float halfH = area.height()/2.f; - mChildren[NW]->prepareForCompositeMap(Ogre::TRect(area.left, area.top, area.right-halfW, area.bottom-halfH)); - mChildren[NE]->prepareForCompositeMap(Ogre::TRect(area.left+halfW, area.top, area.right, area.bottom-halfH)); - mChildren[SW]->prepareForCompositeMap(Ogre::TRect(area.left, area.top+halfH, area.right-halfW, area.bottom)); - mChildren[SE]->prepareForCompositeMap(Ogre::TRect(area.left+halfW, area.top+halfH, area.right, area.bottom)); - } - else - { - // TODO: when to destroy? - Ogre::MaterialPtr material = mMaterialGenerator->generateForCompositeMapRTT(); - makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, material); - } -} - -void QuadTreeNode::ensureCompositeMap() -{ - if (!mCompositeMap.isNull()) - return; - - static int i=0; - std::stringstream name; - name << "terrain/comp" << i++; - - const int size = 128; - mCompositeMap = Ogre::TextureManager::getSingleton().createManual( - name.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, size, size, Ogre::MIP_DEFAULT, Ogre::PF_A8B8G8R8); - - // Create quads for each cell - prepareForCompositeMap(Ogre::TRect(0,0,1,1)); - - mTerrain->renderCompositeMap(mCompositeMap); - - mTerrain->clearCompositeMapSceneManager(); - -} - -void QuadTreeNode::applyMaterials() -{ - if (mChunk) - { - mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); - mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); - if (mSize <= 1) - mChunk->setMaterial(mMaterialGenerator->generate()); - else - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); - } - if (hasChildren()) - for (int i=0; i<4; ++i) - mChildren[i]->applyMaterials(); -} diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp deleted file mode 100644 index e44b646004..0000000000 --- a/components/terrain/quadtreenode.hpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef COMPONENTS_TERRAIN_QUADTREENODE_H -#define COMPONENTS_TERRAIN_QUADTREENODE_H - -#include -#include -#include - -#include "defs.hpp" - -namespace Ogre -{ - class Rectangle2D; -} - -namespace Terrain -{ - class DefaultWorld; - class Chunk; - class MaterialGenerator; - struct LoadResponseData; - - enum ChildDirection - { - NW = 0, - NE = 1, - SW = 2, - SE = 3, - Root - }; - - enum LoadState - { - LS_Unloaded, - LS_Loading, - LS_Loaded - }; - - /** - * @brief A node in the quad tree for our terrain. Depending on LOD, - * a node can either choose to render itself in one batch (merging its children), - * or delegate the render process to its children, rendering each child in at least one batch. - */ - class QuadTreeNode - { - public: - /// @param terrain - /// @param dir relative to parent, or Root if we are the root node - /// @param size size (in *cell* units!) - /// @param center center (in *cell* units!) - /// @param parent parent node - QuadTreeNode (DefaultWorld* terrain, ChildDirection dir, float size, const Ogre::Vector2& center, QuadTreeNode* parent); - ~QuadTreeNode(); - - /// Rebuild all materials - void applyMaterials(); - - /// Initialize neighbours - do this after the quadtree is built - void initNeighbours(); - /// Initialize bounding boxes of non-leafs by merging children bounding boxes. - /// Do this after the quadtree is built - note that leaf bounding boxes - /// need to be set first via setBoundingBox! - void initAabb(); - - /// @note takes ownership of \a child - void createChild (ChildDirection id, float size, const Ogre::Vector2& center); - - /// Mark this node as a dummy node. This can happen if the terrain size isn't a power of two. - /// For the QuadTree to work, we need to round the size up to a power of two, which means we'll - /// end up with empty nodes that don't actually render anything. - void markAsDummy() { mIsDummy = true; } - bool isDummy() { return mIsDummy; } - - QuadTreeNode* getParent() { return mParent; } - - Ogre::SceneNode* getSceneNode() { return mSceneNode; } - - int getSize() { return static_cast(mSize); } - Ogre::Vector2 getCenter() { return mCenter; } - - bool hasChildren() { return mChildren[0] != 0; } - QuadTreeNode* getChild(ChildDirection dir) { return mChildren[dir]; } - - /// Get neighbour node in this direction - QuadTreeNode* getNeighbour (Direction dir); - - /// Returns our direction relative to the parent node, or Root if we are the root node. - ChildDirection getDirection() { return mDirection; } - - /// Set bounding box in local coordinates. Should be done at load time for leaf nodes. - /// Other nodes can merge AABB of child nodes. - void setBoundingBox (const Ogre::AxisAlignedBox& box); - - /// Get bounding box in local coordinates - const Ogre::AxisAlignedBox& getBoundingBox(); - - const Ogre::AxisAlignedBox& getWorldBoundingBox(); - - DefaultWorld* getTerrain() { return mTerrain; } - - /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @return Did we (or all of our children) choose to render? - bool update (const Ogre::Vector3& cameraPos); - - /// Adjust index buffers of chunks to stitch together chunks of different LOD, so that cracks are avoided. - /// Call after QuadTreeNode::update! - void updateIndexBuffers(); - - /// Destroy chunks rendered by this node *and* its children (if param is true) - void destroyChunks(bool children); - - /// Get the effective LOD level if this node was rendered in one chunk - /// with Storage::getCellVertices^2 vertices - size_t getNativeLodLevel() { return mLodLevel; } - - /// Get the effective current LOD level used by the chunk rendering this node - size_t getActualLodLevel(); - - /// Is this node currently configured to render itself? - bool hasChunk(); - - /// Add a textured quad to a specific 2d area in the composite map scenemanager. - /// Only nodes with size <= 1 can be rendered with alpha blending, so larger nodes will simply - /// call this method on their children. - /// @note Do not call this before World::areLayersLoaded() == true - /// @param area area in image space to put the quad - void prepareForCompositeMap(Ogre::TRect area); - - /// Create a chunk for this node from the given data. - void load (const LoadResponseData& data); - void unload(bool recursive=false); - void loadLayers (const LayerCollection& collection); - /// This is recursive! Call it once on the root node after all leafs have loaded layers. - void loadMaterials(); - - LoadState getLoadState() { return mLoadState; } - - private: - // Stored here for convenience in case we need layer list again - MaterialGenerator* mMaterialGenerator; - - LoadState mLoadState; - - bool mIsDummy; - float mSize; - size_t mLodLevel; // LOD if we were to render this node in one chunk - Ogre::AxisAlignedBox mBounds; - Ogre::AxisAlignedBox mWorldBounds; - ChildDirection mDirection; - Ogre::Vector2 mCenter; - - Ogre::SceneNode* mSceneNode; - - QuadTreeNode* mParent; - QuadTreeNode* mChildren[4]; - QuadTreeNode* mNeighbours[4]; - - Chunk* mChunk; - - DefaultWorld* mTerrain; - - Ogre::TexturePtr mCompositeMap; - - void ensureCompositeMap(); - }; - -} - -#endif diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 14009127d2..857713a82b 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -19,3 +19,5 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#include "storage.hpp" diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 7846e91c6e..a302c8f8ce 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -22,10 +22,20 @@ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H -#include +#include + +#include +#include +#include +#include #include "defs.hpp" +namespace osg +{ + class Image; +} + namespace Terrain { /// We keep storage of terrain data abstract here since we need different implementations for game and editor @@ -46,7 +56,7 @@ namespace Terrain /// @param min min height will be stored here /// @param max max height will be stored here /// @return true if there was data available for this terrain chunk - virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max) = 0; + virtual bool getMinMaxHeights (float size, const osg::Vec2f& center, float& min, float& max) = 0; /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! @@ -59,11 +69,12 @@ namespace Terrain /// @param positions buffer to write vertices /// @param normals buffer to write vertex normals /// @param colours buffer to write vertex colours - virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align, - std::vector& positions, - std::vector& normals, - std::vector& colours) = 0; + virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, + osg::ref_ptr positions, + osg::ref_ptr normals, + osg::ref_ptr colours) = 0; + typedef std::vector > ImageVector; /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. @@ -75,23 +86,11 @@ namespace Terrain /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, - std::vector& blendmaps, + virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, bool pack, + ImageVector& blendmaps, std::vector& layerList) = 0; - /// Retrieve pixel data for textures holding layer blend values for terrain chunks and layer texture information. - /// This variant is provided to eliminate the overhead of virtual function calls when retrieving a large number of blendmaps at once. - /// @note The terrain chunks shouldn't be larger than one cell since otherwise we might - /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. - /// @note May be called from background threads. Make sure to only call thread-safe functions from here! - /// @param nodes A collection of nodes for which to retrieve the aforementioned data - /// @param out Output vector - /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - - /// otherwise, each texture contains blend values for one layer only. Shader-based rendering - /// can utilize packing, FFP can't. - virtual void getBlendmaps (const std::vector& nodes, std::vector& out, bool pack) = 0; - - virtual float getHeightAt (const Ogre::Vector3& worldPos) = 0; + virtual float getHeightAt (const osg::Vec3f& worldPos) = 0; virtual LayerInfo getDefaultLayer() = 0; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index bb99ca23e4..e99126a2a8 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -19,22 +19,54 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "terraingrid.hpp" -#include -#include -#include +#include -#include "chunk.hpp" +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include "material.hpp" +#include "storage.hpp" + +namespace +{ + class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback + { + public: + StaticBoundingBoxCallback(const osg::BoundingBox& bounds) + : mBoundingBox(bounds) + { + } + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const + { + return mBoundingBox; + } + + private: + osg::BoundingBox mBoundingBox; + }; +} namespace Terrain { -TerrainGrid::TerrainGrid(Ogre::SceneManager *sceneMgr, Terrain::Storage *storage, int visibilityFlags, bool shaders, Terrain::Alignment align) - : Terrain::World(sceneMgr, storage, visibilityFlags, shaders, align) - , mVisible(true) +TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask) + : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) { - mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); } TerrainGrid::~TerrainGrid() @@ -43,81 +75,105 @@ TerrainGrid::~TerrainGrid() { unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second); } - - mSceneMgr->destroySceneNode(mRootNode); } -void TerrainGrid::update(const Ogre::Vector3 &cameraPos) +class GridElement { -} +public: + osg::ref_ptr mNode; +}; void TerrainGrid::loadCell(int x, int y) { if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - Ogre::Vector2 center(x+0.5f, y+0.5f); + osg::Vec2f center(x+0.5f, y+0.5f); float minH, maxH; if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) return; // no terrain defined - Ogre::Vector3 min (-0.5f*mStorage->getCellWorldSize(), - -0.5f*mStorage->getCellWorldSize(), - minH); - Ogre::Vector3 max (0.5f*mStorage->getCellWorldSize(), + std::auto_ptr element (new GridElement); + + osg::Vec2f worldCenter = center*mStorage->getCellWorldSize(); + element->mNode = new osg::PositionAttitudeTransform; + element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + mTerrainRoot->addChild(element->mNode); + + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); + + mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); + + osg::ref_ptr geometry (new osg::Geometry); + geometry->setVertexArray(positions); + geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); + geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + geometry->setUseDisplayList(false); + geometry->setUseVertexBufferObjects(true); + + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); + + // we already know the bounding box, so no need to let OSG compute it. + osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(), + -0.5f*mStorage->getCellWorldSize(), + minH); + osg::Vec3f max (0.5f*mStorage->getCellWorldSize(), 0.5f*mStorage->getCellWorldSize(), maxH); + osg::BoundingBox bounds(min, max); + geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - Ogre::AxisAlignedBox bounds(min, max); + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); - GridElement element; + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); - Ogre::Vector2 worldCenter = center*mStorage->getCellWorldSize(); - element.mSceneNode = mRootNode->createChildSceneNode(Ogre::Vector3(worldCenter.x, worldCenter.y, 0)); + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); - std::vector positions; - std::vector normals; - std::vector colours; - mStorage->fillVertexBuffers(0, 1, center, mAlign, positions, normals, colours); - - element.mChunk = new Terrain::Chunk(mCache.getUVBuffer(), bounds, positions, normals, colours); - element.mChunk->setIndexBuffer(mCache.getIndexBuffer(0)); - element.mChunk->setVisibilityFlags(mVisibilityFlags); - element.mChunk->setCastShadows(true); - - std::vector blendmaps; - std::vector layerList; - mStorage->getBlendmaps(1, center, mShaders, blendmaps, layerList); - - element.mMaterialGenerator.setLayerList(layerList); - - // upload blendmaps to GPU - std::vector blendTextures; - for (std::vector::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + std::vector > layerTextures; + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { - static int count=0; - Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" - + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, it->getWidth(), it->getHeight(), 0, it->format); - - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(it->data, it->getWidth()*it->getHeight()*Ogre::PixelUtil::getNumElemBytes(it->format), true)); - map->loadRawData(stream, it->getWidth(), it->getHeight(), it->format); - blendTextures.push_back(map); + layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); } - element.mMaterialGenerator.setBlendmapList(blendTextures); + std::vector > blendmapTextures; + for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + { + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(*it); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + blendmapTextures.push_back(texture); - element.mSceneNode->attachObject(element.mChunk); - updateMaterial(element); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } - mGrid[std::make_pair(x,y)] = element; -} + for (unsigned int i=0; isetTexCoordArray(i, mCache.getUVBuffer()); -void TerrainGrid::updateMaterial(GridElement &element) -{ - element.mMaterialGenerator.enableShadows(getShadowsEnabled()); - element.mMaterialGenerator.enableSplitShadows(getSplitShadowsEnabled()); - element.mChunk->setMaterial(element.mMaterialGenerator.generate()); + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); + + effect->addCullCallback(new SceneUtil::LightListCallback); + + effect->addChild(geode); + element->mNode->addChild(effect); + + if (mIncrementalCompileOperation) + { + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); + } + + mGrid[std::make_pair(x,y)] = element.release(); } void TerrainGrid::unloadCell(int x, int y) @@ -126,60 +182,11 @@ void TerrainGrid::unloadCell(int x, int y) if (it == mGrid.end()) return; - GridElement& element = it->second; - delete element.mChunk; - element.mChunk = NULL; - - const std::vector& blendmaps = element.mMaterialGenerator.getBlendmapList(); - for (std::vector::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - Ogre::TextureManager::getSingleton().remove((*it)->getName()); - - mSceneMgr->destroySceneNode(element.mSceneNode); - element.mSceneNode = NULL; + GridElement* element = it->second; + mTerrainRoot->removeChild(element->mNode); + delete element; mGrid.erase(it); } -void TerrainGrid::applyMaterials(bool shadows, bool splitShadows) -{ - mShadows = shadows; - mSplitShadows = splitShadows; - for (Grid::iterator it = mGrid.begin(); it != mGrid.end(); ++it) - { - updateMaterial(it->second); - } -} - -bool TerrainGrid::getVisible() -{ - return mVisible; -} - -void TerrainGrid::setVisible(bool visible) -{ - mVisible = visible; - mRootNode->setVisible(visible); -} - -Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) -{ - int cellX = static_cast(std::floor(center.x)); - int cellY = static_cast(std::floor(center.y)); - - Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); - if (it == mGrid.end()) - return Ogre::AxisAlignedBox::BOX_NULL; - - Terrain::Chunk* chunk = it->second.mChunk; - Ogre::SceneNode* node = it->second.mSceneNode; - Ogre::AxisAlignedBox box = chunk->getBoundingBox(); - box = Ogre::AxisAlignedBox(box.getMinimum() + node->getPosition(), box.getMaximum() + node->getPosition()); - return box; -} - -void TerrainGrid::syncLoad() -{ - -} - } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 97ef6d14d3..3a6d717933 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -27,64 +27,23 @@ namespace Terrain { - class Chunk; - struct GridElement - { - Ogre::SceneNode* mSceneNode; - - Terrain::MaterialGenerator mMaterialGenerator; - - Terrain::Chunk* mChunk; - }; + class GridElement; /// @brief Simple terrain implementation that loads cells in a grid, with no LOD class TerrainGrid : public Terrain::World { public: - /// @note takes ownership of \a storage - /// @param sceneMgr scene manager to use - /// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..) - /// @param visbilityFlags visibility flags for the created meshes - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - TerrainGrid(Ogre::SceneManager* sceneMgr, - Terrain::Storage* storage, int visibilityFlags, bool shaders, Terrain::Alignment align); + TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask); ~TerrainGrid(); - /// Update chunk LODs according to this camera position - virtual void update (const Ogre::Vector3& cameraPos); - virtual void loadCell(int x, int y); virtual void unloadCell(int x, int y); - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center); - - /// Show or hide the whole terrain - /// @note this setting may be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible); - virtual bool getVisible(); - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows); - - /// Wait until all background loading is complete. - virtual void syncLoad(); - private: - void updateMaterial (GridElement& element); - - typedef std::map, GridElement> Grid; + typedef std::map, GridElement*> Grid; Grid mGrid; - - Ogre::SceneNode* mRootNode; - bool mVisible; }; } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 3baaaed44e..1cfcc80acb 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -21,63 +21,39 @@ */ #include "world.hpp" -#include +#include +#include #include "storage.hpp" namespace Terrain { -World::World(Ogre::SceneManager* sceneMgr, - Storage* storage, int visibilityFlags, bool shaders, Alignment align) - : mShaders(shaders) - , mShadows(false) - , mSplitShadows(false) - , mAlign(align) - , mStorage(storage) - , mVisibilityFlags(visibilityFlags) - , mSceneMgr(sceneMgr) +World::World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask) + : mStorage(storage) , mCache(storage->getCellVertices()) + , mParent(parent) + , mResourceSystem(resourceSystem) + , mIncrementalCompileOperation(ico) { + mTerrainRoot = new osg::Group; + mTerrainRoot->setNodeMask(nodeMask); + mTerrainRoot->getOrCreateStateSet()->setRenderingHint(osg::StateSet::OPAQUE_BIN); + + mParent->addChild(mTerrainRoot); } World::~World() { + mParent->removeChild(mTerrainRoot); + delete mStorage; } -float World::getHeightAt(const Ogre::Vector3 &worldPos) +float World::getHeightAt(const osg::Vec3f &worldPos) { return mStorage->getHeightAt(worldPos); } -void World::convertPosition(float &x, float &y, float &z) -{ - Terrain::convertPosition(mAlign, x, y, z); -} - -void World::convertPosition(Ogre::Vector3 &pos) -{ - convertPosition(pos.x, pos.y, pos.z); -} - -void World::convertBounds(Ogre::AxisAlignedBox& bounds) -{ - switch (mAlign) - { - case Align_XY: - return; - case Align_XZ: - convertPosition(bounds.getMinimum()); - convertPosition(bounds.getMaximum()); - // Because we changed sign of Z - std::swap(bounds.getMinimum().z, bounds.getMaximum().z); - return; - case Align_YZ: - convertPosition(bounds.getMinimum()); - convertPosition(bounds.getMaximum()); - return; - } -} - } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 3e63b4c936..70ec304102 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -22,14 +22,24 @@ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H -#include +#include #include "defs.hpp" #include "buffercache.hpp" -namespace Ogre +namespace osg { - class SceneManager; + class Group; +} + +namespace osgUtil +{ + class IncrementalCompileOperation; +} + +namespace Resource +{ + class ResourceSystem; } namespace Terrain @@ -44,79 +54,31 @@ namespace Terrain { public: /// @note takes ownership of \a storage - /// @param sceneMgr scene manager to use /// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..) - /// @param visbilityFlags visibility flags for the created meshes - /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually - /// faster so this is just here for compatibility. - /// @param align The align of the terrain, see Alignment enum - World(Ogre::SceneManager* sceneMgr, - Storage* storage, int visiblityFlags, bool shaders, Alignment align); + /// @param nodeMask mask for the terrain root + World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, + Storage* storage, int nodeMask); virtual ~World(); - bool getShadersEnabled() { return mShaders; } - bool getShadowsEnabled() { return mShadows; } - bool getSplitShadowsEnabled() { return mSplitShadows; } - - float getHeightAt (const Ogre::Vector3& worldPos); - - /// Update chunk LODs according to this camera position - /// @note Calling this method might lead to composite textures being rendered, so it is best - /// not to call it when render commands are still queued, since that would cause a flush. - virtual void update (const Ogre::Vector3& cameraPos) = 0; + float getHeightAt (const osg::Vec3f& worldPos); // This is only a hint and may be ignored by the implementation. virtual void loadCell(int x, int y) {} virtual void unloadCell(int x, int y) {} - /// Get the world bounding box of a chunk of terrain centered at \a center - virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center) = 0; - - Ogre::SceneManager* getSceneManager() { return mSceneMgr; } - Storage* getStorage() { return mStorage; } - /// Show or hide the whole terrain - /// @note this setting may be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden - virtual void setVisible(bool visible) = 0; - virtual bool getVisible() = 0; - - /// Recreate materials used by terrain chunks. This should be called whenever settings of - /// the material factory are changed. (Relying on the factory to update those materials is not - /// enough, since turning a feature on/off can change the number of texture units available for layer/blend - /// textures, and to properly respond to this we may need to change the structure of the material, such as - /// adding or removing passes. This can only be achieved by a full rebuild.) - virtual void applyMaterials(bool shadows, bool splitShadows) = 0; - - int getVisibilityFlags() { return mVisibilityFlags; } - - Alignment getAlign() { return mAlign; } - - /// Wait until all background loading is complete. - virtual void syncLoad() {} - protected: - bool mShaders; - bool mShadows; - bool mSplitShadows; - Alignment mAlign; - Storage* mStorage; - int mVisibilityFlags; - - Ogre::SceneManager* mSceneMgr; - BufferCache mCache; - public: - // ----INTERNAL---- - BufferCache& getBufferCache() { return mCache; } + osg::ref_ptr mParent; + osg::ref_ptr mTerrainRoot; - // Convert the given position from Z-up align, i.e. Align_XY to the wanted align set in mAlign - void convertPosition (float& x, float& y, float& z); - void convertPosition (Ogre::Vector3& pos); - void convertBounds (Ogre::AxisAlignedBox& bounds); + Resource::ResourceSystem* mResourceSystem; + + osg::ref_ptr mIncrementalCompileOperation; }; } From 5666e0254653543398b8441acc00eb68bf1733ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:21:41 +0200 Subject: [PATCH 0366/1812] Fix for dark terrain in some cases --- components/terrain/material.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 17acd940b9..ddfa10f129 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -67,6 +68,12 @@ namespace Terrain stateset->setTextureAttributeAndModes(texunit, new osg::TexMat(texMat)); + osg::ref_ptr texEnvCombine (new osg::TexEnvCombine); + texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + + stateset->setTextureAttributeAndModes(texunit, texEnvCombine, osg::StateAttribute::ON); + ++texunit; } From b978153edbe735000227eb99ee7414086ffcc3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:24:09 +0200 Subject: [PATCH 0367/1812] Enable VBO sharing for terrain geometry --- components/terrain/buffercache.cpp | 6 ++++++ components/terrain/terraingrid.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 7dc93f1d65..dfb3eff883 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -218,6 +218,9 @@ namespace Terrain } } + // Assign a VBO here to enable state sharing between different Geometries. + uvs->setVertexBufferObject(new osg::VertexBufferObject); + mUvBufferMap[mNumVerts] = uvs; return uvs; } @@ -238,6 +241,9 @@ namespace Terrain else buffer = createIndexBuffer(flags, verts); + // Assign a EBO here to enable state sharing between different Geometries. + buffer->setElementBufferObject(new osg::ElementBufferObject); + mIndexBufferMap[flags] = buffer; return buffer; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index e99126a2a8..7ae4d85116 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -104,6 +104,11 @@ void TerrainGrid::loadCell(int x, int y) osg::ref_ptr normals (new osg::Vec3Array); osg::ref_ptr colors (new osg::Vec4Array); + osg::ref_ptr vbo (new osg::VertexBufferObject); + positions->setVertexBufferObject(vbo); + normals->setVertexBufferObject(vbo); + colors->setVertexBufferObject(vbo); + mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); osg::ref_ptr geometry (new osg::Geometry); From 2883ecc19af0721183001810e6c58fc406e7f208 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 02:41:04 +0200 Subject: [PATCH 0368/1812] Fix the hilarious bug of NPCs falling to their deaths in interiors --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e676977de3..93a34f2337 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1299,7 +1299,7 @@ namespace MWWorld } float terrainHeight = -std::numeric_limits::max(); - if (isCellExterior()) + if (ptr.getCell()->isExterior()) terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); if (pos.pos[2] < terrainHeight) From cd47dff1963d7ae0035e5a04fdf137256b0382ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:02:43 +0200 Subject: [PATCH 0369/1812] Minor cleanup --- apps/opencs/view/render/scenewidget.cpp | 1 - components/terrain/material.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 5937759701..a9c9a8c6bf 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index ddfa10f129..2af8ddcda0 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -30,8 +30,6 @@ #include #include -#include - namespace Terrain { From cee1db532f653f5f373bbafcfddd1a2464809d4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:04:39 +0200 Subject: [PATCH 0370/1812] Improve area orb positioning for "on touch" spells --- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 93a34f2337..6376772c36 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2636,11 +2636,14 @@ namespace MWWorld // Get the target to use for "on touch" effects MWWorld::Ptr target; float distance = 192.f; // ?? + osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); if (actor == getPlayerPtr()) { // For the player, use camera to aim target = getFacedObject(distance); + if (!target.isEmpty()) + hitPosition = target.getRefData().getPosition().asVec3(); } else { @@ -2669,13 +2672,13 @@ namespace MWWorld MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); target = result.mHitObject; + hitPosition = result.mHitPos; } std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); - if (!target.isEmpty()) - cast.mHitPosition = target.getRefData().getPosition().asVec3(); + cast.mHitPosition = hitPosition; if (!selectedSpell.empty()) { From 292fa0b5e319081a48e2065f92fb3c769bc881bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:13:51 +0200 Subject: [PATCH 0371/1812] Unify raycasting techniques for "on touch" magic We don't want pixel-precise raycasting here. Gets annoying when trying to hit a skeleton. --- apps/openmw/mwworld/worldimp.cpp | 54 +++++++++++++------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6376772c36..2f9a13f78e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2638,43 +2638,33 @@ namespace MWWorld float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - if (actor == getPlayerPtr()) - { - // For the player, use camera to aim - target = getFacedObject(distance); - if (!target.isEmpty()) - hitPosition = target.getRefData().getPosition().asVec3(); - } - else - { - // For NPCs use facing direction from Head node - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); + // For NPCs use facing direction from Head node + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - MWRender::Animation* anim = mRendering->getAnimation(actor); - if (anim != NULL) + MWRender::Animation* anim = mRendering->getAnimation(actor); + if (anim != NULL) + { + const osg::Node* node = anim->getNode("Head"); + if (node == NULL) + node = anim->getNode("Bip01 Head"); + if (node != NULL) { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) - { - osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); - } + osg::MatrixList mats = node->getWorldMatrices(); + if (mats.size()) + origin = mats[0].getTrans(); } - - osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) - * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); - - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); - osg::Vec3f dest = origin + direction * distance; - - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); - target = result.mHitObject; - hitPosition = result.mHitPos; } + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + osg::Vec3f dest = origin + direction * distance; + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); + target = result.mHitObject; + hitPosition = result.mHitPos; + std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From 41cce5240fc4e225288b924daddaec9a62a3868e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 03:29:21 +0200 Subject: [PATCH 0372/1812] Delete remaining files that won't be of any use --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwrender/occlusionquery.cpp | 208 ---------------------- apps/openmw/mwrender/occlusionquery.hpp | 77 -------- apps/openmw/mwrender/ripplesimulation.cpp | 169 ------------------ apps/openmw/mwrender/ripplesimulation.hpp | 64 ------- apps/openmw/mwrender/shadows.cpp | 187 ------------------- apps/openmw/mwrender/shadows.hpp | 37 ---- 7 files changed, 743 deletions(-) delete mode 100644 apps/openmw/mwrender/occlusionquery.cpp delete mode 100644 apps/openmw/mwrender/occlusionquery.hpp delete mode 100644 apps/openmw/mwrender/ripplesimulation.cpp delete mode 100644 apps/openmw/mwrender/ripplesimulation.hpp delete mode 100644 apps/openmw/mwrender/shadows.cpp delete mode 100644 apps/openmw/mwrender/shadows.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ef0c4e1351..b238282544 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,6 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage -# occlusionquery shadows ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp deleted file mode 100644 index 2693d68b2e..0000000000 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "occlusionquery.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "renderconst.hpp" - -using namespace MWRender; -using namespace Ogre; - -OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : - mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mActiveQuery(0), - mBBQueryVisible(0), mBBQueryTotal(0), mSunNode(sunNode), mBBNodeReal(0), - mSunVisibility(0), - mWasVisible(false), - mActive(false), - mFirstFrame(true), - mDoQuery(0), - mRendering(renderer) -{ - try { - RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - - mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery(); - mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery(); - - mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0); - } - catch (Ogre::Exception&) - { - mSupported = false; - } - - if (!mSupported) - { - std::cout << "Hardware occlusion queries not supported." << std::endl; - return; - } - - mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); - - static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("occlusionbillboard", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); - plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); - - mBBQueryTotal = mRendering->getScene()->createEntity("occlusionbillboard"); - mBBQueryTotal->setCastShadows(false); - mBBQueryTotal->setVisibilityFlags(RV_OcclusionQuery); - mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); - mBBQueryTotal->setMaterialName("QueryTotalPixels"); - mBBNodeReal->attachObject(mBBQueryTotal); - - mBBQueryVisible = mRendering->getScene()->createEntity("occlusionbillboard"); - mBBQueryVisible->setCastShadows(false); - mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); - mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); - mBBQueryVisible->setMaterialName("QueryVisiblePixels"); - mBBNodeReal->attachObject(mBBQueryVisible); - - mRendering->getScene()->addRenderObjectListener(this); - mRendering->getScene()->addRenderQueueListener(this); - mDoQuery = true; -} - -OcclusionQuery::~OcclusionQuery() -{ - mRendering->getScene()->removeRenderObjectListener (this); - mRendering->getScene()->removeRenderQueueListener(this); - - RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - if (mSunTotalAreaQuery) - renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); - if (mSunVisibleAreaQuery) - renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); -} - -bool OcclusionQuery::supported() -{ - return mSupported; -} - -void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, - const LightList* pLightList, bool suppressRenderStateChanges) -{ - if (!mActive) return; - - // The following code activates and deactivates the occlusion queries - // so that the queries only include the rendering of the intended meshes - - // Close the last occlusion query - // Each occlusion query should only last a single rendering - if (mActiveQuery != NULL) - { - mActiveQuery->endOcclusionQuery(); - mActiveQuery = NULL; - } - - // Open a new occlusion query - if (mDoQuery == true) - { - if (rend == mBBQueryTotal->getSubEntity(0)) - { - mActiveQuery = mSunTotalAreaQuery; - mWasVisible = true; - } - else if (rend == mBBQueryVisible->getSubEntity(0)) - { - mActiveQuery = mSunVisibleAreaQuery; - } - } - - if (mActiveQuery != NULL) - mActiveQuery->beginOcclusionQuery(); -} - -void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation) -{ - if (!mActive) return; - - if (mActiveQuery != NULL) - { - mActiveQuery->endOcclusionQuery(); - mActiveQuery = NULL; - } - /** - * for every beginOcclusionQuery(), we want a respective pullOcclusionQuery() and vice versa - * this also means that results can be wrong at other places if we pull, but beginOcclusionQuery() was never called - * this can happen for example if the object that is tested is outside of the view frustum - * to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually - */ - if (queueGroupId == RQG_SkiesLate) - { - if (mWasVisible == false && mDoQuery) - { - mSunTotalAreaQuery->beginOcclusionQuery(); - mSunTotalAreaQuery->endOcclusionQuery(); - mSunVisibleAreaQuery->beginOcclusionQuery(); - mSunVisibleAreaQuery->endOcclusionQuery(); - } - } -} - -void OcclusionQuery::update(float duration) -{ - if (mFirstFrame) - { - // GLHardwareOcclusionQuery::isStillOutstanding doesn't seem to like getting called when nothing has been rendered yet - mFirstFrame = false; - return; - } - if (!mSupported) return; - - mWasVisible = false; - - // Adjust the position of the sun billboards according to camera viewing distance - // we need to do this to make sure that _everything_ can occlude the sun - float dist = mRendering->getCamera()->getFarClipDistance(); - if (dist==0) dist = 10000000; - dist -= 1000; // bias - dist /= 1000.f; - if (mSunNode) - { - mBBNodeReal->setPosition(mSunNode->getPosition() * dist); - mBBNodeReal->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-mBBNodeReal->getPosition().normalisedCopy())); - mBBNodeReal->setScale(150.f*dist, 150.f*dist, 150.f*dist); - } - - // Stop occlusion queries until we get their information - // (may not happen on the same frame they are requested in) - mDoQuery = false; - - if (!mSunTotalAreaQuery->isStillOutstanding() - && !mSunVisibleAreaQuery->isStillOutstanding()) - { - unsigned int totalPixels; - unsigned int visiblePixels; - - mSunTotalAreaQuery->pullOcclusionQuery(&totalPixels); - mSunVisibleAreaQuery->pullOcclusionQuery(&visiblePixels); - - if (totalPixels == 0) - { - // probably outside of the view frustum - mSunVisibility = 0; - } - else - { - mSunVisibility = float(visiblePixels) / float(totalPixels); - if (mSunVisibility > 1) mSunVisibility = 1; - } - - mDoQuery = true; - } -} - -void OcclusionQuery::setSunNode(Ogre::SceneNode* node) -{ - mSunNode = node; -} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp deleted file mode 100644 index 6974f37b96..0000000000 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef GAME_OCCLUSION_QUERY_H -#define GAME_OCCLUSION_QUERY_H - -#include -#include - -namespace Ogre -{ - class HardwareOcclusionQuery; - class Entity; - class SceneNode; -} - -#include - -namespace MWRender -{ - /// - /// \brief Implements hardware occlusion queries on the GPU - /// - class OcclusionQuery : public Ogre::RenderObjectListener, public Ogre::RenderQueueListener - { - public: - OcclusionQuery(OEngine::Render::OgreRenderer*, Ogre::SceneNode* sunNode); - ~OcclusionQuery(); - - /** - * @return true if occlusion queries are supported on the user's hardware - */ - bool supported(); - - /** - * make sure to disable occlusion queries before updating unrelated render targets - * @param active - */ - void setActive (bool active) { mActive = active; } - - /** - * per-frame update - */ - void update(float duration); - - float getSunVisibility() const {return mSunVisibility;}; - - void setSunNode(Ogre::SceneNode* node); - - private: - Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery; - Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery; - Ogre::HardwareOcclusionQuery* mActiveQuery; - - Ogre::Entity* mBBQueryVisible; - Ogre::Entity* mBBQueryTotal; - - Ogre::SceneNode* mSunNode; - Ogre::SceneNode* mBBNodeReal; - float mSunVisibility; - - bool mWasVisible; - - bool mActive; - bool mFirstFrame; - - bool mSupported; - bool mDoQuery; - - OEngine::Render::OgreRenderer* mRendering; - - protected: - virtual void notifyRenderSingleObject(Ogre::Renderable* rend, const Ogre::Pass* pass, const Ogre::AutoParamDataSource* source, - const Ogre::LightList* pLightList, bool suppressRenderStateChanges); - - virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation); - }; -} - -#endif diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp deleted file mode 100644 index f75061af49..0000000000 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "ripplesimulation.hpp" - -#include - -#include -#include -#include -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include "../mwworld/fallback.hpp" - -#include "renderconst.hpp" - -namespace MWRender -{ - -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) - : mSceneMgr(mainSceneManager) - , mParticleSystem(NULL) - , mSceneNode(NULL) -{ - mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); - mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - - // Unknown: - // fallback=Water_RippleScale,0.15, 6.5 - // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - - // Instantiate from ripples.particle file - mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - - mParticleSystem->setRenderQueueGroup(RQG_Ripples); - mParticleSystem->setVisibilityFlags(RV_Effects); - - int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); - std::string tex = fallback->getFallbackString("Water_RippleTexture"); - - sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); - mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " - + Ogre::StringConverter::toString(rippleFrameCount) - + " " - + Ogre::StringConverter::toString(0.3)))); - - // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better - mParticleSystem->_update(0.f); - - mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mSceneNode->attachObject(mParticleSystem); -} - -RippleSimulation::~RippleSimulation() -{ - if (mParticleSystem) - mSceneMgr->destroyParticleSystem(mParticleSystem); - mParticleSystem = NULL; - - if (mSceneNode) - mSceneMgr->destroySceneNode(mSceneNode); - mSceneNode = NULL; -} - -void RippleSimulation::update(float dt, Ogre::Vector2 position) -{ - bool newParticle = false; - for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) - { - if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) - { - // fetch a new ptr (to handle cell change etc) - // for non-player actors this is done in updateObjectCell - it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - } - Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); - currentPos.z = 0; - if ( (currentPos - it->mLastEmitPosition).length() > 10 - // Only emit when close to the water surface, not above it and not too deep in the water - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), - Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) - && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) - { - it->mLastEmitPosition = currentPos; - - newParticle = true; - Ogre::Particle* created = mParticleSystem->createParticle(); - if (!created) - break; // TODO: cleanup the oldest particle to make room -#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3& position = created->mPosition; - Ogre::Vector3& direction = created->mDirection; - Ogre::ColourValue& colour = created->mColour; - float& totalTimeToLive = created->mTotalTimeToLive; - float& timeToLive = created->mTimeToLive; - Ogre::Radian& rotSpeed = created->mRotationSpeed; - Ogre::Radian& rotation = created->mRotation; -#else - Ogre::Vector3& position = created->position; - Ogre::Vector3& direction = created->direction; - Ogre::ColourValue& colour = created->colour; - float& totalTimeToLive = created->totalTimeToLive; - float& timeToLive = created->timeToLive; - Ogre::Radian& rotSpeed = created->rotationSpeed; - Ogre::Radian& rotation = created->rotation; -#endif - timeToLive = totalTimeToLive = mRippleLifeTime; - colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7f); // Water_RippleAlphas.x? - direction = Ogre::Vector3(0,0,0); - position = currentPos; - position.z = 0; // Z is set by the Scene Node - rotSpeed = mRippleRotSpeed; - rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); - } - } - - if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better - mParticleSystem->_update(0.f); -} - -void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) -{ - Emitter newEmitter; - newEmitter.mPtr = ptr; - newEmitter.mScale = scale; - newEmitter.mForce = force; - newEmitter.mLastEmitPosition = Ogre::Vector3(0,0,0); - mEmitters.push_back (newEmitter); -} - -void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) -{ - for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) - { - if (it->mPtr == ptr) - { - mEmitters.erase(it); - return; - } - } -} - -void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) -{ - for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) - { - if (it->mPtr == old) - { - it->mPtr = ptr; - return; - } - } -} - -void RippleSimulation::setWaterHeight(float height) -{ - mSceneNode->setPosition(0,0,height); -} - -void RippleSimulation::clear() -{ - mParticleSystem->clear(); -} - - -} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp deleted file mode 100644 index 4551476a4c..0000000000 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef RIPPLE_SIMULATION_H -#define RIPPLE_SIMULATION_H - -#include - -#include "../mwworld/ptr.hpp" - -namespace Ogre -{ - class SceneManager; - class ParticleSystem; -} - -namespace MWWorld -{ - class Fallback; -} - -namespace MWRender -{ - -struct Emitter -{ - MWWorld::Ptr mPtr; - Ogre::Vector3 mLastEmitPosition; - float mScale; - float mForce; -}; - -class RippleSimulation -{ -public: - RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); - ~RippleSimulation(); - - /// @param dt Time since the last frame - /// @param position Position of the player - void update(float dt, Ogre::Vector2 position); - - /// adds an emitter, position will be tracked automatically - void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeEmitter (const MWWorld::Ptr& ptr); - void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - - /// Change the height of the water surface, thus moving all ripples with it - void setWaterHeight(float height); - - /// Remove all active ripples - void clear(); - -private: - Ogre::SceneManager* mSceneMgr; - Ogre::ParticleSystem* mParticleSystem; - Ogre::SceneNode* mSceneNode; - - std::vector mEmitters; - - float mRippleLifeTime; - float mRippleRotSpeed; -}; - -} - -#endif diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp deleted file mode 100644 index f2e60b11b0..0000000000 --- a/apps/openmw/mwrender/shadows.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "shadows.hpp" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "renderconst.hpp" - -using namespace Ogre; -using namespace MWRender; - -Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : - mRendering(rend), mSceneMgr(rend->getScene()), mPSSMSetup(NULL), - mShadowFar(1000), mFadeStart(0.9f) -{ - recreate(); -} - -void Shadows::recreate() -{ - bool enabled = Settings::Manager::getBool("enabled", "Shadows"); - - bool split = Settings::Manager::getBool("split", "Shadows"); - - sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); - sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); - - if (!enabled) - { - mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); - return; - } - - int texsize = Settings::Manager::getInt("texture size", "Shadows"); - mSceneMgr->setShadowTextureSize(texsize); - - mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED); - - // no point light shadows, i'm afraid. might revisit this with Deferred Shading - mSceneMgr->setShadowTextureCountPerLightType(Light::LT_POINT, 0); - - mSceneMgr->setShadowTextureCountPerLightType(Light::LT_DIRECTIONAL, split ? 3 : 1); - mSceneMgr->setShadowTextureCount(split ? 3 : 1); - - mSceneMgr->setShadowTextureSelfShadow(true); - mSceneMgr->setShadowCasterRenderBackFaces(true); - mSceneMgr->setShadowTextureCasterMaterial("openmw_shadowcaster_default"); - mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); - mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - - mShadowFar = Settings::Manager::getFloat(split ? "split shadow distance" : "shadow distance", "Shadows"); - mSceneMgr->setShadowFarDistance(mShadowFar); - - mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); - - ShadowCameraSetupPtr shadowCameraSetup; - if (split) - { - mPSSMSetup = new PSSMShadowCameraSetup(); - - // Make sure to keep this in sync with the camera's near clip distance! - mPSSMSetup->setSplitPadding(mRendering->getCamera()->getNearClipDistance()); - - mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar); - - const Real adjustFactors[3] = {64, 64, 64}; - for (int i=0; i < 3; ++i) - { - mPSSMSetup->setOptimalAdjustFactor(i, adjustFactors[i]); - /*if (i==0) - mSceneMgr->setShadowTextureConfig(i, texsize, texsize, Ogre::PF_FLOAT32_R); - else if (i ==1) - mSceneMgr->setShadowTextureConfig(i, texsize/2, texsize/2, Ogre::PF_FLOAT32_R); - else if (i ==2) - 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(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") - + RV_Misc * Settings::Manager::getBool("misc shadows", "Shadows") - + RV_Terrain * (Settings::Manager::getBool("terrain shadows", "Shadows")); - for (int i = 0; i < (split ? 3 : 1); ++i) - { - TexturePtr shadowTexture = mSceneMgr->getShadowTexture(i); - Viewport* vp = shadowTexture->getBuffer()->getRenderTarget()->getViewport(0); - vp->setVisibilityMask(visibilityMask); - } - - // -------------------------------------------------------------------------------------------------------------------- - // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- - // -------------------------------------------------------------------------------------------------------------------- - /* - if (Settings::Manager::getBool("debug", "Shadows")) - { - 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); - - 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() -{ - return mPSSMSetup; -} diff --git a/apps/openmw/mwrender/shadows.hpp b/apps/openmw/mwrender/shadows.hpp deleted file mode 100644 index fe125f54c3..0000000000 --- a/apps/openmw/mwrender/shadows.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GAME_SHADOWS_H -#define GAME_SHADOWS_H - -// forward declares -namespace Ogre -{ - class SceneManager; - class PSSMShadowCameraSetup; -} -namespace OEngine{ - namespace Render{ - class OgreRenderer; - } -} - -namespace MWRender -{ - class Shadows - { - public: - Shadows(OEngine::Render::OgreRenderer* rend); - - void recreate(); - - Ogre::PSSMShadowCameraSetup* getPSSMSetup(); - - protected: - OEngine::Render::OgreRenderer* mRendering; - Ogre::SceneManager* mSceneMgr; - - Ogre::PSSMShadowCameraSetup* mPSSMSetup; - float mShadowFar; - float mFadeStart; - }; -} - -#endif From 24551c7bab5cc818f258af5e366ff8da03b56481 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 14:56:57 +0200 Subject: [PATCH 0373/1812] Fix for savegame incompatibility with master branch --- apps/openmw/mwrender/localmap.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 16957a585f..77138a124b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -99,12 +99,15 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { const MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; - std::auto_ptr fog (new ESM::FogState()); - fog->mFogTextures.push_back(ESM::FogTexture()); + if (segment.mFogOfWarImage && segment.mHasFogState) + { + std::auto_ptr fog (new ESM::FogState()); + fog->mFogTextures.push_back(ESM::FogTexture()); - segment.saveFogOfWar(fog->mFogTextures.back()); + segment.saveFogOfWar(fog->mFogTextures.back()); - cell->setFog(fog.release()); + cell->setFog(fog.release()); + } } else { @@ -133,6 +136,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) fog->mFogTextures.push_back(ESM::FogTexture()); + // saving even if !segment.mHasFogState so we don't mess up the segmenting + // plus, older openmw versions can't deal with empty images segment.saveFogOfWar(fog->mFogTextures.back()); fog->mFogTextures.back().mX = x; @@ -644,7 +649,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const { - if (!mFogOfWarImage || !mHasFogState) + if (!mFogOfWarImage) return; std::ostringstream ostream; From 2a85a22dba62c875cb579a414be90729e092626a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 16:40:16 +0200 Subject: [PATCH 0374/1812] Write savegame screenshot --- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwrender/renderingmanager.cpp | 59 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 3 ++ apps/openmw/mwstate/statemanagerimp.cpp | 41 ++++++++++++---- apps/openmw/mwstate/statemanagerimp.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 4 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 101 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f258eb300a..bb48afc9d6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -23,6 +23,7 @@ namespace osg { class Vec3f; class Quat; + class Image; } namespace Loading @@ -438,7 +439,7 @@ namespace MWBase virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here - virtual void screenshot (Ogre::Image& image, int w, int h) = 0; + virtual void screenshot (osg::Image* image, int w, int h) = 0; /// Find default position inside exterior cell specified by name /// \return false if exterior with given name not exists, true otherwise diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6205c3ad87..7af21a5a6e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -379,6 +379,65 @@ namespace MWRender mWater->setHeight(height); } + class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback + { + public: + virtual void operator () (osg::RenderInfo& renderInfo) const + { + mCondition.signal(); + } + + mutable OpenThreads::Condition mCondition; + }; + + void RenderingManager::screenshot(osg::Image *image, int w, int h) + { + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getCamera()->setCullMask(oldCullMask & (~Mask_GUI)); + + osg::ref_ptr rttCamera (new osg::Camera); + rttCamera->setNodeMask(Mask_RenderToTexture); + rttCamera->attach(osg::Camera::COLOR_BUFFER, image); + rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); + rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + rttCamera->setClearColor(mViewer->getCamera()->getClearColor()); + rttCamera->setClearMask(mViewer->getCamera()->getClearMask()); + rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); + rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); + rttCamera->setViewport(0, 0, w, h); + rttCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + + osg::ref_ptr texture (new osg::Texture2D); + texture->setInternalFormat(GL_RGB); + texture->setTextureSize(w, h); + texture->setResizeNonPowerOfTwoHint(false); + rttCamera->attach(osg::Camera::COLOR_BUFFER, texture); + + image->setDataType(GL_UNSIGNED_BYTE); + image->setPixelFormat(texture->getInternalFormat()); + + rttCamera->addChild(mLightRoot); + + mRootNode->addChild(rttCamera); + + mViewer->frame(); + + // The draw needs to complete before we can copy back our image. + osg::ref_ptr callback (new NotifyDrawCompletedCallback); + rttCamera->setFinalDrawCallback(callback); + OpenThreads::Mutex m; + m.lock(); + callback->mCondition.wait(&m); + m.unlock(); + + rttCamera->removeChildren(0, rttCamera->getNumChildren()); + rttCamera->setGraphicsContext(NULL); + mRootNode->removeChild(rttCamera); + + mViewer->getCamera()->setCullMask(oldCullMask); + } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) { osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c22d3c7bfd..4452ae9f85 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -82,6 +82,9 @@ namespace MWRender void setWaterEnabled(bool enabled); void setWaterHeight(float level); + /// Take a screenshot of w*h onto the given image, not including the GUI. + void screenshot(osg::Image* image, int w, int h); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index d403590dd1..ce4d8f9581 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -10,7 +10,9 @@ #include -#include +#include + +#include #include #include @@ -179,14 +181,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mTimePlayed = mTimePlayed; profile.mDescription = description; - /* - int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing - Ogre::Image screenshot; - world.screenshot(screenshot, screenshotW, screenshotH); - Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); - profile.mScreenshot.resize(encoded->size()); - encoded->read(&profile.mScreenshot[0], encoded->size()); - */ + writeScreenshot(profile.mScreenshot); if (!slot) slot = getCurrentCharacter()->createSlot (profile); @@ -572,3 +567,31 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const } return true; } + +void MWState::StateManager::writeScreenshot(std::vector &imageData) const +{ + int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing + + osg::ref_ptr screenshot (new osg::Image); + + MWBase::Environment::get().getWorld()->screenshot(screenshot.get(), screenshotW, screenshotH); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "Unable to write screenshot, can't find a jpg ReaderWriter" << std::endl; + return; + } + + std::ostringstream ostream; + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream); + if (!result.success()) + { + std::cerr << "Unable to write screenshot: " << result.message() << std::endl; + return; + } + + std::string data = ostream.str(); + imageData = std::vector(data.begin(), data.end()); + +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 37f38f8df7..59dc919d14 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -25,6 +25,8 @@ namespace MWState bool verifyProfile (const ESM::SavedGame& profile) const; + void writeScreenshot (std::vector& imageData) const; + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7528e9286e..7bc46c0780 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2128,9 +2128,9 @@ namespace MWWorld return mRendering->getAnimation(ptr); } - void World::screenshot(Ogre::Image &image, int w, int h) + void World::screenshot(osg::Image* image, int w, int h) { - //mRendering->screenshot(image, w, h); + mRendering->screenshot(image, w, h); } void World::activateDoor(const MWWorld::Ptr& door) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4c4df2c995..20d6bf9a1c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -524,7 +524,7 @@ namespace MWWorld virtual void reattachPlayerCamera(); /// \todo this does not belong here - virtual void screenshot (Ogre::Image& image, int w, int h); + virtual void screenshot (osg::Image* image, int w, int h); /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise From e642f20a65972f7e6bb9900816f42e54a41390e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 17:25:18 +0200 Subject: [PATCH 0375/1812] Restore screenshot key functionality --- apps/openmw/engine.cpp | 73 +++++++++++++++++++------- apps/openmw/engine.hpp | 6 +++ components/sdlutil/sdlinputwrapper.cpp | 2 + 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fed1f134b8..a37d84621e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -532,6 +533,54 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } } +class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation +{ +public: + WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat) + : mScreenshotPath(screenshotPath) + , mScreenshotFormat(screenshotFormat) + { + } + + virtual void operator()(const osg::Image& image, const unsigned int context_id) + { + // Count screenshots. + int shotCount = 0; + + // Find the first unused filename with a do-while + std::ostringstream stream; + do + { + // Reset the stream + stream.str(""); + stream.clear(); + + stream << mScreenshotPath << "/screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << mScreenshotFormat; + + } while (boost::filesystem::exists(stream.str())); + + boost::filesystem::ofstream outStream; + outStream.open(boost::filesystem::path(stream.str()), std::ios::binary); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat); + if (!readerwriter) + { + std::cerr << "Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream); + if (!result.success()) + { + std::cerr << "Can't write screenshot: " << result.message() << std::endl; + } + } + +private: + std::string mScreenshotPath; + std::string mScreenshotFormat; +}; + // Initialise and enter main loop. void OMW::Engine::go() @@ -557,6 +606,10 @@ void OMW::Engine::go() settingspath = loadSettings (settings); + mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(), + Settings::Manager::getString("screenshot format", "General"))); + mViewer->addEventHandler(mScreenCaptureHandler); + // Create encoder ToUTF8::Utf8Encoder encoder (mEncoding); mEncoder = &encoder; @@ -639,24 +692,8 @@ void OMW::Engine::activate() void OMW::Engine::screenshot() { - // Count screenshots. - int shotCount = 0; - - const std::string& screenshotPath = mCfgMgr.getUserDataPath().string(); - std::string format = Settings::Manager::getString("screenshot format", "General"); - // Find the first unused filename with a do-while - std::ostringstream stream; - do - { - // Reset the stream - stream.str(""); - stream.clear(); - - stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << format; - - } while (boost::filesystem::exists(stream.str())); - - //mOgre->screenshot(stream.str(), format); + mScreenCaptureHandler->setFramesToCapture(1); + mScreenCaptureHandler->captureNextFrame(*mViewer); } void OMW::Engine::setCompileAll (bool all) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8b792c5a89..8ac6098b8a 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -53,6 +53,11 @@ namespace Files struct ConfigurationManager; } +namespace osgViewer +{ + class ScreenCaptureHandler; +} + struct SDL_Window; namespace OMW @@ -70,6 +75,7 @@ namespace OMW std::vector mArchives; boost::filesystem::path mResDir; osg::ref_ptr mViewer; + osg::ref_ptr mScreenCaptureHandler; std::string mCellName; std::vector mContentFiles; bool mVerboseScripts; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index a9209bf58b..f607b7046b 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -41,6 +41,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v void InputWrapper::capture(bool windowEventsOnly) { + mViewer->getEventQueue()->frame(0.f); + SDL_PumpEvents(); SDL_Event evt; From bd0233ce68a14d9d191149f382145c36e785adf2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:00:34 +0200 Subject: [PATCH 0376/1812] Error handling improvement --- components/resource/texturemanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 5f2ca19efd..50cfd9d57d 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -107,6 +107,12 @@ namespace Resource if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; + return mWarningTexture; + } + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { From dd23981eabb35fb7e119be042d80d82f161f87c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:00:45 +0200 Subject: [PATCH 0377/1812] Font workaround for older MyGUI versions, works with 3.2.2 now --- components/fontloader/fontloader.cpp | 30 ++++++++++++------- .../myguiplatform/myguirendermanager.cpp | 8 +++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 7635c43daf..1313366834 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -275,18 +276,13 @@ namespace Gui std::string textureName = name; - osg::ref_ptr image = new osg::Image; - - image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); - assert (image->isDataContiguous()); - - memcpy(image->data(), &textureData[0], textureData.size()); - - osg::ref_ptr texture = new osg::Texture2D; - texture->setImage(image); - if (exportToFile) { + osg::ref_ptr image = new osg::Image; + image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert (image->isDataContiguous()); + memcpy(image->data(), &textureData[0], textureData.size()); + std::cout << "Writing " << resourceName + ".png" << std::endl; osgDB::writeImageFile(*image, resourceName + ".png"); } @@ -295,9 +291,23 @@ namespace Gui MyGUI::ResourceManualFont* font = static_cast( MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); mFonts.push_back(font); + + MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture(bitmapFilename); + tex->createManual(width, height, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8); + unsigned char* texData = reinterpret_cast(tex->lock(MyGUI::TextureUsage::Write)); + memcpy(texData, &textureData[0], textureData.size()); + tex->unlock(); + + font->setSource(bitmapFilename); + + // Using ResourceManualFont::setTexture, enable for MyGUI 3.2.3 + /* + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(image); osgMyGUI::OSGTexture* myguiTex = new osgMyGUI::OSGTexture(texture); mTextures.push_back(myguiTex); font->setTexture(myguiTex); + */ // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 MyGUI::xml::Document xmlDocument; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index bf1d66fe8a..e00b0221da 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -453,8 +453,12 @@ bool RenderManager::isFormatSupported(MyGUI::PixelFormat /*format*/, MyGUI::Text MyGUI::ITexture* RenderManager::createTexture(const std::string &name) { - MapTexture::const_iterator item = mTextures.find(name); - MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '"<second; + mTextures.erase(item); + } OSGTexture* texture = new OSGTexture(name, mTextureManager); mTextures.insert(std::make_pair(name, texture)); From 1ba3fa4169b55641d57c4fc17d4704a8e64d71ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:11:34 +0200 Subject: [PATCH 0378/1812] Remove leftovers of the old OpenCS navigation --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/lightingday.hpp | 5 - apps/opencs/view/render/lightingnight.hpp | 5 - apps/opencs/view/render/navigation.cpp | 24 ----- apps/opencs/view/render/navigation.hpp | 47 --------- apps/opencs/view/render/navigation1st.cpp | 86 ---------------- apps/opencs/view/render/navigation1st.hpp | 35 ------- apps/opencs/view/render/navigationfree.cpp | 66 ------------ apps/opencs/view/render/navigationfree.hpp | 35 ------- apps/opencs/view/render/navigationorbit.cpp | 100 ------------------- apps/opencs/view/render/navigationorbit.hpp | 42 -------- apps/opencs/view/render/previewwidget.hpp | 2 - apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/render/scenewidget.hpp | 1 - apps/opencs/view/render/worldspacewidget.hpp | 6 -- 15 files changed, 1 insertion(+), 456 deletions(-) delete mode 100644 apps/opencs/view/render/navigation.cpp delete mode 100644 apps/opencs/view/render/navigation.hpp delete mode 100644 apps/opencs/view/render/navigation1st.cpp delete mode 100644 apps/opencs/view/render/navigation1st.hpp delete mode 100644 apps/opencs/view/render/navigationfree.cpp delete mode 100644 apps/opencs/view/render/navigationfree.hpp delete mode 100644 apps/opencs/view/render/navigationorbit.cpp delete mode 100644 apps/opencs/view/render/navigationorbit.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6fec6f1945..7c539fb14c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -82,7 +82,7 @@ opencs_units (view/render ) opencs_units_noqt (view/render - navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight + lighting lightingday lightingnight lightingbright object cell terrainstorage ) diff --git a/apps/opencs/view/render/lightingday.hpp b/apps/opencs/view/render/lightingday.hpp index 407933ec66..2dc3c02b6f 100644 --- a/apps/opencs/view/render/lightingday.hpp +++ b/apps/opencs/view/render/lightingday.hpp @@ -3,11 +3,6 @@ #include "lighting.hpp" -namespace Ogre -{ - class Light; -} - namespace CSVRender { class LightingDay : public Lighting diff --git a/apps/opencs/view/render/lightingnight.hpp b/apps/opencs/view/render/lightingnight.hpp index 8743cc438b..dae2a8fa38 100644 --- a/apps/opencs/view/render/lightingnight.hpp +++ b/apps/opencs/view/render/lightingnight.hpp @@ -3,11 +3,6 @@ #include "lighting.hpp" -namespace Ogre -{ - class Light; -} - namespace CSVRender { class LightingNight : public Lighting diff --git a/apps/opencs/view/render/navigation.cpp b/apps/opencs/view/render/navigation.cpp deleted file mode 100644 index 7057591041..0000000000 --- a/apps/opencs/view/render/navigation.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include "navigation.hpp" - -float CSVRender::Navigation::getFactor (bool mouse) const -{ - float factor = mFastModeFactor; - - if (mouse) - factor /= 2; /// \todo make this configurable - - return factor; -} - -CSVRender::Navigation::Navigation() - : mFastModeFactor(1) -{ -} - -CSVRender::Navigation::~Navigation() {} - -void CSVRender::Navigation::setFastModeFactor (float factor) -{ - mFastModeFactor = factor; -} diff --git a/apps/opencs/view/render/navigation.hpp b/apps/opencs/view/render/navigation.hpp deleted file mode 100644 index ead8f3e135..0000000000 --- a/apps/opencs/view/render/navigation.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATION_H -#define OPENCS_VIEW_NAVIGATION_H - -class QPoint; - -namespace Ogre -{ - class Camera; -} - -namespace CSVRender -{ - class Navigation - { - float mFastModeFactor; - - protected: - - float getFactor (bool mouse) const; - - public: - - Navigation(); - virtual ~Navigation(); - - void setFastModeFactor (float factor); - ///< Set currently applying fast mode factor. - - virtual bool activate (Ogre::Camera *camera) = 0; - ///< \return Update required? - - virtual bool wheelMoved (int delta) = 0; - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode) = 0; - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal) = 0; - ///< \return Update required? - - virtual bool handleRollKeys (int delta) = 0; - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigation1st.cpp b/apps/opencs/view/render/navigation1st.cpp deleted file mode 100644 index 5d9a034688..0000000000 --- a/apps/opencs/view/render/navigation1st.cpp +++ /dev/null @@ -1,86 +0,0 @@ - -#include "navigation1st.hpp" - -#include - -#include - -CSVRender::Navigation1st::Navigation1st() : mCamera (0) {} - -bool CSVRender::Navigation1st::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (true, Ogre::Vector3::UNIT_Z); - - Ogre::Radian pitch = mCamera->getOrientation().getPitch(); - - Ogre::Radian limit (Ogre::Math::PI/2-0.5); - - if (pitch>limit) - mCamera->pitch (-(pitch-limit)); - else if (pitch<-limit) - mCamera->pitch (pitch-limit); - - return true; -} - -bool CSVRender::Navigation1st::wheelMoved (int delta) -{ - mCamera->move (getFactor (true) * mCamera->getDirection() * delta); - return true; -} - -bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode) -{ - if (mode==0) - { - // turn camera - if (delta.x()) - mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x())); - - if (delta.y()) - { - Ogre::Radian oldPitch = mCamera->getOrientation().getPitch(); - float deltaPitch = getFactor (true) * delta.y(); - Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch); - - if ((deltaPitch>0 && newPitchOgre::Radian(0.5))) - { - mCamera->pitch (Ogre::Degree (deltaPitch)); - } - } - - return true; - } - else if (mode==1) - { - // pan camera - if (delta.x()) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x()); - - if (delta.y()) - mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y()); - - return true; - } - - return false; -} - -bool CSVRender::Navigation1st::handleMovementKeys (int vertical, int horizontal) -{ - if (vertical) - mCamera->move (getFactor (false) * mCamera->getDirection() * vertical); - - if (horizontal) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal); - - return true; -} - -bool CSVRender::Navigation1st::handleRollKeys (int delta) -{ - // we don't roll this way in 1st person mode - return false; -} diff --git a/apps/opencs/view/render/navigation1st.hpp b/apps/opencs/view/render/navigation1st.hpp deleted file mode 100644 index d1e09d2367..0000000000 --- a/apps/opencs/view/render/navigation1st.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATION1ST_H -#define OPENCS_VIEW_NAVIGATION1ST_H - -#include "navigation.hpp" - -namespace CSVRender -{ - /// \brief First person-like camera controls - class Navigation1st : public Navigation - { - Ogre::Camera *mCamera; - - public: - - Navigation1st(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigationfree.cpp b/apps/opencs/view/render/navigationfree.cpp deleted file mode 100644 index 950e137a7d..0000000000 --- a/apps/opencs/view/render/navigationfree.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -#include "navigationfree.hpp" - -#include - -#include - -CSVRender::NavigationFree::NavigationFree() : mCamera (0) {} - -bool CSVRender::NavigationFree::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (false); - return false; -} - -bool CSVRender::NavigationFree::wheelMoved (int delta) -{ - mCamera->move (getFactor (true) * mCamera->getDirection() * delta); - return true; -} - -bool CSVRender::NavigationFree::mouseMoved (const QPoint& delta, int mode) -{ - if (mode==0) - { - // turn camera - if (delta.x()) - mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x())); - - if (delta.y()) - mCamera->pitch (Ogre::Degree (getFactor (true) * delta.y())); - - return true; - } - else if (mode==1) - { - // pan camera - if (delta.x()) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x()); - - if (delta.y()) - mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y()); - - return true; - } - - return false; -} - -bool CSVRender::NavigationFree::handleMovementKeys (int vertical, int horizontal) -{ - if (vertical) - mCamera->move (getFactor (false) * mCamera->getDerivedUp() * vertical); - - if (horizontal) - mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal); - - return true; -} - -bool CSVRender::NavigationFree::handleRollKeys (int delta) -{ - mCamera->roll (Ogre::Degree (getFactor (false) * delta)); - return true; -} diff --git a/apps/opencs/view/render/navigationfree.hpp b/apps/opencs/view/render/navigationfree.hpp deleted file mode 100644 index e30722f75d..0000000000 --- a/apps/opencs/view/render/navigationfree.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATIONFREE_H -#define OPENCS_VIEW_NAVIGATIONFREE_H - -#include "navigation.hpp" - -namespace CSVRender -{ - /// \brief Free camera controls - class NavigationFree : public Navigation - { - Ogre::Camera *mCamera; - - public: - - NavigationFree(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/navigationorbit.cpp b/apps/opencs/view/render/navigationorbit.cpp deleted file mode 100644 index c5f3eda96f..0000000000 --- a/apps/opencs/view/render/navigationorbit.cpp +++ /dev/null @@ -1,100 +0,0 @@ - -#include "navigationorbit.hpp" - -#include - -#include - -void CSVRender::NavigationOrbit::rotateCamera (const Ogre::Vector3& diff) -{ - Ogre::Vector3 pos = mCamera->getPosition(); - - float distance = (pos-mCentre).length(); - - Ogre::Vector3 direction = (pos+diff)-mCentre; - direction.normalise(); - - mCamera->setPosition (mCentre + direction*distance); - mCamera->lookAt (mCentre); -} - -CSVRender::NavigationOrbit::NavigationOrbit() : mCamera (0), mCentre (0, 0, 0), mDistance (100) -{} - -bool CSVRender::NavigationOrbit::activate (Ogre::Camera *camera) -{ - mCamera = camera; - mCamera->setFixedYawAxis (false); - - if ((mCamera->getPosition()-mCentre).length()getPosition(); - direction.normalise(); - - if (direction.length()==0) - direction = Ogre::Vector3 (1, 0, 0); - - mCamera->setPosition (mCentre - direction * mDistance); - } - - mCamera->lookAt (mCentre); - - return true; -} - -bool CSVRender::NavigationOrbit::wheelMoved (int delta) -{ - Ogre::Vector3 diff = getFactor (true) * mCamera->getDirection() * delta; - - Ogre::Vector3 pos = mCamera->getPosition(); - - if (delta>0 && diff.length()>=(pos-mCentre).length()-mDistance) - { - pos = mCentre-(mCamera->getDirection() * mDistance); - } - else - { - pos += diff; - } - - mCamera->setPosition (pos); - - return true; -} - -bool CSVRender::NavigationOrbit::mouseMoved (const QPoint& delta, int mode) -{ - Ogre::Vector3 diff = - getFactor (true) * -mCamera->getDerivedRight() * delta.x() - + getFactor (true) * mCamera->getDerivedUp() * delta.y(); - - if (mode==0) - { - rotateCamera (diff); - return true; - } - else if (mode==1) - { - mCamera->move (diff); - mCentre += diff; - return true; - } - - return false; -} - -bool CSVRender::NavigationOrbit::handleMovementKeys (int vertical, int horizontal) -{ - rotateCamera ( - - getFactor (false) * -mCamera->getDerivedRight() * horizontal - + getFactor (false) * mCamera->getDerivedUp() * vertical); - - return true; -} - -bool CSVRender::NavigationOrbit::handleRollKeys (int delta) -{ - mCamera->roll (Ogre::Degree (getFactor (false) * delta)); - return true; -} diff --git a/apps/opencs/view/render/navigationorbit.hpp b/apps/opencs/view/render/navigationorbit.hpp deleted file mode 100644 index 7796eb9e7c..0000000000 --- a/apps/opencs/view/render/navigationorbit.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef OPENCS_VIEW_NAVIGATIONORBIT_H -#define OPENCS_VIEW_NAVIGATIONORBIT_H - -#include "navigation.hpp" - -#include - -namespace CSVRender -{ - /// \brief Orbiting camera controls - class NavigationOrbit : public Navigation - { - Ogre::Camera *mCamera; - Ogre::Vector3 mCentre; - int mDistance; - - void rotateCamera (const Ogre::Vector3& diff); - ///< Rotate camera around centre. - - public: - - NavigationOrbit(); - - virtual bool activate (Ogre::Camera *camera); - ///< \return Update required? - - virtual bool wheelMoved (int delta); - ///< \return Update required? - - virtual bool mouseMoved (const QPoint& delta, int mode); - ///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1 - /// \return Update required? - - virtual bool handleMovementKeys (int vertical, int horizontal); - ///< \return Update required? - - virtual bool handleRollKeys (int delta); - ///< \return Update required? - }; -} - -#endif diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 58a7d8552d..73f7dc810f 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -3,7 +3,6 @@ #include "scenewidget.hpp" -#include "navigationorbit.hpp" #include "object.hpp" class QModelIndex; @@ -25,7 +24,6 @@ namespace CSVRender Q_OBJECT CSMWorld::Data& mData; - CSVRender::NavigationOrbit mOrbit; CSVRender::Object mObject; public: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a9c9a8c6bf..6136abb40f 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -17,7 +17,6 @@ #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" -#include "navigation.hpp" #include "lighting.hpp" namespace CSVRender diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index acfc0bbd48..58c376418c 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -29,7 +29,6 @@ namespace CSVWidget namespace CSVRender { - class Navigation; class Lighting; class RenderWidget : public QWidget diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e935daae26..fe4555820a 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,9 +5,6 @@ #include "scenewidget.hpp" -#include "navigation1st.hpp" -#include "navigationfree.hpp" -#include "navigationorbit.hpp" #include #include @@ -30,9 +27,6 @@ namespace CSVRender { Q_OBJECT - CSVRender::Navigation1st m1st; - CSVRender::NavigationFree mFree; - CSVRender::NavigationOrbit mOrbit; CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; From 4f0387bdb5fa6ed40fa4b0231750984c7e134651 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:34:47 +0200 Subject: [PATCH 0379/1812] Fix for recent merge --- cmake/FindMyGUI.cmake | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index e883a29c13..eccfb54ed9 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -25,38 +25,21 @@ IF (WIN32) #Windows IF(MINGW) FIND_PATH ( MYGUI_INCLUDE_DIRS MyGUI.h PATH_SUFFIXES MYGUI) - FIND_PATH ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h PATH_SUFFIXES MYGUI) FIND_LIBRARY ( MYGUI_LIBRARIES_REL NAMES libMyGUIEngine${CMAKE_SHARED_LIBRARY_SUFFIX} - libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) FIND_LIBRARY ( MYGUI_LIBRARIES_DBG NAMES libMyGUIEngine_d${CMAKE_SHARED_LIBRARY_SUFFIX} - libMyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} - HINTS - ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" debug ) - - FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_REL NAMES - libMyGUI.OgrePlatform${CMAKE_STATIC_LIBRARY_SUFFIX} - HINTS - ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" release relwithdebinfo minsizerel ) - - FIND_LIBRARY ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES - MyGUI.OgrePlatform_d${CMAKE_STATIC_LIBRARY_SUFFIX} HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) make_library_set ( MYGUI_LIBRARIES ) - make_library_set ( MYGUI_PLATFORM_LIBRARIES ) MESSAGE ("${MYGUI_LIBRARIES}") - MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") ENDIF(MINGW) SET(MYGUISDK $ENV{MYGUI_HOME}) From 0cc9b1bb40c17d9bf4517905436cecf21b1e7139 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 18:49:52 +0200 Subject: [PATCH 0380/1812] Remove dependency on OgrePlatform.h --- apps/openmw/main.cpp | 27 +++++++++++++-------------- components/files/lowlevelfile.hpp | 6 ++---- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 901d9ad429..dc58daed9a 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -12,8 +12,6 @@ #include #include -#include - #if defined(_WIN32) // For OutputDebugString #define WIN32_LEAN_AND_MEAN @@ -23,17 +21,18 @@ #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) + #define USE_CRASH_CATCHER 1 +#else + #define USE_CRASH_CATCHER 0 +#endif + +#if USE_CRASH_CATCHER #include extern int cc_install_handlers(int argc, char **argv, int num_signals, int *sigs, const char *logfile, int (*user_info)(char*, char*)); extern int is_debugger_attached(void); #endif -// for Ogre::macBundlePath -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include -#endif - #include /** * Workaround for problems with whitespaces in paths in older versions of Boost library @@ -364,7 +363,7 @@ int main(int argc, char**argv) #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if USE_CRASH_CATCHER // Unix crash catcher if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached()) { @@ -376,10 +375,10 @@ int main(int argc, char**argv) std::cout << "Running in a debugger, not installing crash catcher" << std::endl; #endif -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - // set current dir to bundle path - boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); - boost::filesystem::current_path(bundlePath); +#ifdef __APPLE__ + // FIXME: set current dir to bundle path + //boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); + //boost::filesystem::current_path(bundlePath); #endif engine.reset(new OMW::Engine(cfgMgr)); @@ -391,7 +390,7 @@ int main(int argc, char**argv) } catch (std::exception &e) { -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); diff --git a/components/files/lowlevelfile.hpp b/components/files/lowlevelfile.hpp index d94238ad6e..b2634d8c76 100644 --- a/components/files/lowlevelfile.hpp +++ b/components/files/lowlevelfile.hpp @@ -1,17 +1,15 @@ #ifndef COMPONENTS_FILES_LOWLEVELFILE_HPP #define COMPONENTS_FILES_LOWLEVELFILE_HPP -#include - #include #define FILE_API_STDIO 0 #define FILE_API_POSIX 1 #define FILE_API_WIN32 2 -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#if defined(__linux) || defined(__unix) || defined(__posix) #define FILE_API FILE_API_POSIX -#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32 +#elif defined(_WIN32) #define FILE_API FILE_API_WIN32 #else #define FILE_API FILE_API_STDIO From 7bacb9418de53838d5d453094921a04a190b9a37 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:41:19 +0200 Subject: [PATCH 0381/1812] Various math code ported to osg --- apps/openmw/mwbase/world.hpp | 12 +--- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwmechanics/actors.cpp | 8 +-- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 91 ++++++++++++++----------- apps/openmw/mwmechanics/aifollow.cpp | 4 +- apps/openmw/mwmechanics/aipackage.cpp | 4 +- apps/openmw/mwmechanics/aisequence.cpp | 6 +- apps/openmw/mwmechanics/aitravel.cpp | 10 +-- apps/openmw/mwmechanics/aiwander.cpp | 58 ++++++++-------- apps/openmw/mwmechanics/aiwander.hpp | 6 +- apps/openmw/mwmechanics/character.cpp | 16 ++--- apps/openmw/mwmechanics/pathfinding.cpp | 14 ++-- apps/openmw/mwmechanics/pathfinding.hpp | 7 ++ apps/openmw/mwmechanics/steering.cpp | 28 ++++---- apps/openmw/mwmechanics/steering.hpp | 12 ++-- apps/openmw/mwworld/class.cpp | 4 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/player.cpp | 12 ++-- apps/openmw/mwworld/player.hpp | 7 +- apps/openmw/mwworld/worldimp.cpp | 27 ++++---- apps/openmw/mwworld/worldimp.hpp | 6 +- 28 files changed, 180 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index bb48afc9d6..95553de76d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -11,14 +11,6 @@ #include "../mwrender/rendermode.hpp" -namespace Ogre -{ - class Vector2; - class Vector3; - class Quaternion; - class Image; -} - namespace osg { class Vec3f; @@ -423,7 +415,7 @@ namespace MWBase virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0; + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0; virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; @@ -497,7 +489,7 @@ namespace MWBase // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const = 0; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0; + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) = 0; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ea67884d35..c886915151 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -580,10 +580,10 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const + osg::Vec3f Creature::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mRotation); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); movement.mRotation[0] = 0.0f; movement.mRotation[1] = 0.0f; movement.mRotation[2] = 0.0f; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index f5a2402f38..93ef3959c3 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -113,7 +113,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. float getSpeed (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4307fe9be0..c9de1f6ff2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -961,10 +961,10 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const + osg::Vec3f Npc::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mRotation); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); movement.mRotation[0] = 0.0f; movement.mRotation[1] = 0.0f; movement.mRotation[2] = 0.0f; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f72a9bb2c0..b786286f7b 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -105,7 +105,7 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0fab66a254..44f944c3bd 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -394,7 +394,7 @@ namespace MWGui } if (mIsDrowning) - mDrowningFlashTheta += dt * Ogre::Math::TWO_PI; + mDrowningFlashTheta += dt * osg::PI*2; } void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index ba6fc2a786..7985e7eda0 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -169,8 +169,7 @@ namespace MWGui if (!interior) { ESM::Position playerPos = player.getRefData().getPosition(); - float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance( - Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0)); + float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length(); int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); for(int i = 0;i < hours;i++) { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1182de1515..1ae5cabed0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -992,12 +992,12 @@ namespace MWGui mMap->setCellPrefix (cell->getCell()->mName ); mHud->setCellPrefix (cell->getCell()->mName ); - Ogre::Vector3 worldPos; + osg::Vec3f worldPos; if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition(); else MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); - mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); + mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y()); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 81dbca58ab..03ab3d0201 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -316,7 +316,7 @@ namespace MWMechanics const ESM::Position& actor1Pos = actor1.getRefData().getPosition(); const ESM::Position& actor2Pos = actor2.getRefData().getPosition(); - float sqrDist = Ogre::Vector3(actor1Pos.pos).squaredDistance(Ogre::Vector3(actor2Pos.pos)); + float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2(); if (sqrDist > 7168*7168) return; @@ -1081,7 +1081,7 @@ namespace MWMechanics // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { - bool inProcessingRange = Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrProcessingDistance; iter->second->getCharacterController()->setActive(inProcessingRange); @@ -1151,7 +1151,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first != player && - Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() > sqrProcessingDistance) continue; @@ -1236,7 +1236,7 @@ namespace MWMechanics continue; // is the player in range and can they be detected - if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(player.getRefData().getPosition().pos)) <= radius*radius + if ((iter->first.getRefData().getPosition().asVec3() - player.getRefData().getPosition().asVec3()).length2() <= radius*radius && MWBase::Environment::get().getWorld()->getLOS(player, iter->first)) { if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, iter->first)) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 83f9dffb47..9d32aa97b3 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -56,7 +56,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); // Turn away from the door and move when turn completed - if (zTurn(actor, Ogre::Radian(std::atan2(x,y) + mAdjAngle), Ogre::Degree(5))) + if (zTurn(actor, std::atan2(x,y) + mAdjAngle, osg::DegreesToRadians(5.f))) actor.getClass().getMovementSettings(actor).mPosition[1] = 1; else actor.getClass().getMovementSettings(actor).mPosition[1] = 0; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 36ff927d80..495aaf82be 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -35,18 +35,18 @@ namespace void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]); - Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, + osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength); - float getZAngleToDir(const Ogre::Vector3& dir) + float getZAngleToDir(const osg::Vec3f& dir) { - return Ogre::Math::ATan2(dir.x,dir.y).valueDegrees(); + return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y())); } - float getXAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) + float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) { float len = (dirLen > 0.0f)? dirLen : dir.length(); - return -Ogre::Math::ASin(dir.z / len).valueDegrees(); + return osg::RadiansToDegrees(-std::asin(dir.z() / len)); } @@ -58,20 +58,20 @@ namespace // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; // magnitude of pits/obstacles is defined by PATHFIND_Z_REACH - bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offsetXY) + bool checkWayIsClear(const osg::Vec3f& from, const osg::Vec3f& to, float offsetXY) { - if((to - from).length() >= PATHFIND_CAUTION_DIST || std::abs(from.z - to.z) <= PATHFIND_Z_REACH) + if((to - from).length() >= PATHFIND_CAUTION_DIST || std::abs(from.z() - to.z()) <= PATHFIND_Z_REACH) { - Ogre::Vector3 dir = to - from; - dir.z = 0; - dir.normalise(); + osg::Vec3f dir = to - from; + dir.z() = 0; + dir.normalize(); float verticalOffset = 200; // instead of '200' here we want the height of the actor - Ogre::Vector3 _from = from + dir*offsetXY + Ogre::Vector3::UNIT_Z * verticalOffset; + osg::Vec3f _from = from + dir*offsetXY + osg::Vec3f(0,0,1) * verticalOffset; // cast up-down ray and find height in world space of hit - float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1); + float h = _from.z() - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, osg::Vec3f(0,0,-1), verticalOffset + PATHFIND_Z_REACH + 1); - if(std::abs(from.z - h) <= PATHFIND_Z_REACH) + if(std::abs(from.z() - h) <= PATHFIND_Z_REACH) return true; } @@ -95,7 +95,7 @@ namespace MWMechanics bool mAttack; bool mFollowTarget; bool mCombatMove; - Ogre::Vector3 mLastTargetPos; + osg::Vec3f mLastTargetPos; const MWWorld::CellStore* mCell; boost::shared_ptr mCurrentAction; float mActionCooldown; @@ -104,7 +104,7 @@ namespace MWMechanics bool mMinMaxAttackDurationInitialised; bool mForceNoShortcut; ESM::Position mShortcutFailPos; - Ogre::Vector3 mLastActorPos; + osg::Vec3f mLastActorPos; MWMechanics::Movement mMovement; AiCombatStorage(): @@ -231,12 +231,12 @@ namespace MWMechanics if(movement.mRotation[2] != 0) { - if(zTurn(actor, Ogre::Degree(movement.mRotation[2]))) movement.mRotation[2] = 0; + if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0; } if(movement.mRotation[0] != 0) { - if(smoothTurn(actor, Ogre::Degree(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; + if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } float attacksPeriod = 1.0f; @@ -450,12 +450,12 @@ namespace MWMechanics */ ESM::Position pos = actor.getRefData().getPosition(); - Ogre::Vector3 vActorPos(pos.pos); - Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos); - Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vActorPos(pos.asVec3()); + osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); + osg::Vec3f vDirToTarget = vTargetPos - vActorPos; float distToTarget = vDirToTarget.length(); - Ogre::Vector3& lastActorPos = storage.mLastActorPos; + osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; bool isStuck = false; @@ -496,8 +496,8 @@ namespace MWMechanics // note: in getZAngleToDir if we preserve dir.z then horizontal angle can be inaccurate if (distantCombat) { - Ogre::Vector3& lastTargetPos = storage.mLastTargetPos; - Ogre::Vector3 vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f& lastTargetPos = storage.mLastTargetPos; + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -553,12 +553,12 @@ namespace MWMechanics ESM::Position& shortcutFailPos = storage.mShortcutFailPos; if(inLOS && (!isStuck || readyToAttack) - && (!forceNoShortcut || (Ogre::Vector3(shortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) + && (!forceNoShortcut || (shortcutFailPos.asVec3() - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; // *2 - for reliability - preferShortcut = checkWayIsClear(vActorPos, vTargetPos, Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } // don't use pathgrid when actor can move in 3 dimensions @@ -594,7 +594,7 @@ namespace MWMechanics // get point just before target std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget(PathFinder::MakeOgreVector3(*pntIter)); + osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) @@ -668,7 +668,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too if(mPathFinder.isPathConstructed()) - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); if(followTarget) followTarget = false; @@ -680,14 +680,14 @@ namespace MWMechanics void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { - Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos); + osg::Vec3f newPathTarget = target.getRefData().getPosition().asVec3(); float dist; if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); + osg::Vec3f currPathTarget(PathFinder::MakeOsgVec3(lastPt)); dist = (newPathTarget - currPathTarget).length(); } else dist = 1e+38F; // necessarily construct a new path @@ -876,7 +876,7 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations } } -Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, +osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength) { float projSpeed; @@ -905,28 +905,37 @@ Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same - Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); - Ogre::Vector3 vTargetPos = Ogre::Vector3(target.getRefData().getPosition().pos); - Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); + osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3(); + osg::Vec3f vDirToTarget = vTargetPos - vActorPos; float distToTarget = vDirToTarget.length(); - Ogre::Vector3 vTargetMoveDir = vTargetPos - vLastTargetPos; + osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos; vTargetMoveDir /= duration; // |vTargetMoveDir| is target real speed in units/sec now - Ogre::Vector3 vPerpToDir = vDirToTarget.crossProduct(Ogre::Vector3::UNIT_Z); + osg::Vec3f vPerpToDir = vDirToTarget ^ osg::Vec3f(0,0,1); // cross product - float velPerp = vTargetMoveDir.dotProduct(vPerpToDir.normalisedCopy()); - float velDir = vTargetMoveDir.dotProduct(vDirToTarget.normalisedCopy()); + vPerpToDir.normalize(); + osg::Vec3f vDirToTargetNormalized = vDirToTarget; + vDirToTargetNormalized.normalize(); + + // dot product + float velPerp = vTargetMoveDir * vPerpToDir; + float velDir = vTargetMoveDir * vDirToTargetNormalized; // time to collision between target and projectile float t_collision; float projVelDirSquared = projSpeed * projSpeed - velPerp * velPerp; - float projDistDiff = vDirToTarget.dotProduct(vTargetMoveDir.normalisedCopy()); - projDistDiff = sqrt(distToTarget * distToTarget - projDistDiff * projDistDiff); + + osg::Vec3f vTargetMoveDirNormalized = vTargetMoveDir; + vTargetMoveDirNormalized.normalize(); + + float projDistDiff = vDirToTarget * vTargetMoveDirNormalized; // dot product + projDistDiff = std::sqrt(distToTarget * distToTarget - projDistDiff * projDistDiff); if (projVelDirSquared > 0) - t_collision = projDistDiff / (sqrt(projVelDirSquared) - velDir); + t_collision = projDistDiff / (std::sqrt(projVelDirSquared) - velDir); else t_collision = 0; // speed of projectile is not enough to reach moving target return vTargetPos + vTargetMoveDir * t_collision - vActorPos; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index ddfc145812..24a50cbd64 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -76,7 +76,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duratio if (storage.mTimer < 0) { - if (Ogre::Vector3(actor.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(target.getRefData().getPosition().pos)) + if ((actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length2() < 500*500 && MWBase::Environment::get().getWorld()->getLOS(actor, target)) mActive = true; @@ -137,7 +137,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duratio // turn towards target anyway float directionX = target.getRefData().getPosition().pos[0] - actor.getRefData().getPosition().pos[0]; float directionY = target.getRefData().getPosition().pos[1] - actor.getRefData().getPosition().pos[1]; - zTurn(actor, Ogre::Math::ATan2(directionX,directionY), Ogre::Degree(5)); + zTurn(actor, std::atan2(directionX,directionY), osg::DegreesToRadians(5.f)); } else { diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 52a975320d..8db62dea81 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -106,7 +106,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // change the angle a bit, too - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } } else { //Not stuck, so reset things @@ -119,7 +119,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); return false; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index bb078f8834..0606e5146e 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -165,7 +165,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati std::list::iterator itActualCombat; float nearestDist = std::numeric_limits::max(); - Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); + osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) { @@ -183,7 +183,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati { const ESM::Position &targetPos = target.getRefData().getPosition(); - float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); + float distTo = (targetPos.asVec3() - vActorPos).length(); if (distTo < nearestDist) { nearestDist = distTo; @@ -258,7 +258,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) return; // already in combat with this actor } else if ((*iter)->getTypeId() == AiPackage::TypeIdWander) - static_cast(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos)); + static_cast(*iter)->setReturnPosition(actor.getRefData().getPosition().asVec3()); } } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2824e2c6ce..f9fddf5754 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -17,12 +17,12 @@ namespace { -bool isWithinMaxRange(const Ogre::Vector3& pos1, const Ogre::Vector3& pos2) +bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) { // Maximum travel distance for vanilla compatibility. // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - return (pos1.squaredDistance(pos2) <= 7168*7168); + return (pos1 - pos2).length2() <= 7168*7168; } } @@ -84,7 +84,7 @@ namespace MWMechanics } } - if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos))) + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), pos.asVec3())) return false; bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; @@ -106,7 +106,7 @@ namespace MWMechanics return true; } - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); movement.mPosition[1] = 1; return false; @@ -119,7 +119,7 @@ namespace MWMechanics void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) { - if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(actor.getRefData().getPosition().pos))) + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) return; // does not do any validation on the travel target (whether it's in air, inside collision geometry, etc), // that is the user's responsibility diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6593bbf89b..71508ac511 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -48,7 +48,7 @@ namespace MWMechanics { // the z rotation angle (degrees) we want to reach // used every frame when mRotate is true - Ogre::Radian mTargetAngle; + float mTargetAngleRadians; bool mRotate; float mReaction; // update some actions infrequently @@ -69,7 +69,7 @@ namespace MWMechanics PathFinder mPathFinder; AiWanderStorage(): - mTargetAngle(0), + mTargetAngleRadians(0), mRotate(false), mReaction(0), mSaidGreeting(AiWander::Greet_None), @@ -101,7 +101,7 @@ namespace MWMechanics mTrimCurrentNode = false; mHasReturnPosition = false; - mReturnPosition = Ogre::Vector3(0,0,0); + mReturnPosition = osg::Vec3f(0,0,0); if(mDistance < 0) mDistance = 0; @@ -231,7 +231,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // Returns true if evasive action needs to be taken @@ -255,7 +255,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too - zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } mStuckCount++; // TODO: maybe no longer needed } @@ -275,14 +275,14 @@ namespace MWMechanics } - Ogre::Radian& targetAngle = storage.mTargetAngle; + float& targetAngleRadians = storage.mTargetAngleRadians; bool& rotate = storage.mRotate; if (rotate) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, targetAngle, Ogre::Degree(5))) + if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f))) rotate = false; } @@ -340,7 +340,7 @@ namespace MWMechanics // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of // voices going through walls? - if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) + if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead && MWBase::Environment::get().getWorld()->getLOS(player, actor)) MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); @@ -400,7 +400,7 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && Ogre::Vector3(pos.pos).squaredDistance(mReturnPosition) > 20*20) + if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) { chooseAction = false; idleNow = false; @@ -435,9 +435,9 @@ namespace MWMechanics helloDistance *= iGreetDistanceMultiplier; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - Ogre::Vector3 playerPos(player.getRefData().getPosition().pos); - Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); - float playerDistSqr = playerPos.squaredDistance(actorPos); + osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + float playerDistSqr = (playerPos - actorPos).length2(); int& greetingTimer = storage.mGreetingTimer; if (greetingState == Greet_None) @@ -471,10 +471,10 @@ namespace MWMechanics if(!rotate) { - Ogre::Vector3 dir = playerPos - actorPos; + osg::Vec3f dir = playerPos - actorPos; - float faceAngleRadians = std::atan2(dir.x, dir.y); - targetAngle = faceAngleRadians; + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + targetAngleRadians = faceAngleRadians; rotate = true; } @@ -501,10 +501,8 @@ namespace MWMechanics assert(mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates - Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); - // convert dest to use world co-ordinates - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(destNodePos)); + ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); if (currentCell->getCell()->isExterior()) { dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; @@ -607,7 +605,7 @@ namespace MWMechanics } } - void AiWander::setReturnPosition(const Ogre::Vector3& position) + void AiWander::setReturnPosition(const osg::Vec3f& position) { if (!mHasReturnPosition) { @@ -652,8 +650,8 @@ namespace MWMechanics ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding - dest.mX += static_cast(Ogre::Math::RangeRandom(-64, 64)); - dest.mY += static_cast(Ogre::Math::RangeRandom(-64, 64)); + dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); + dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); if (actor.getCell()->isExterior()) { @@ -670,7 +668,7 @@ namespace MWMechanics { if (!mStoredInitialActorPosition) { - mInitialActorPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); + mInitialActorPosition = actor.getRefData().getPosition().asVec3(); mStoredInitialActorPosition = true; } @@ -700,7 +698,7 @@ namespace MWMechanics } // convert npcPos to local (i.e. cell) co-ordinates - Ogre::Vector3 npcPos(mInitialActorPosition); + osg::Vec3f npcPos(mInitialActorPosition); npcPos[0] = npcPos[0] - cellXOffset; npcPos[1] = npcPos[1] - cellYOffset; @@ -708,19 +706,19 @@ namespace MWMechanics // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); - if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); + if((npcPos - nodePos).length2() <= mDistance * mDistance) mAllowedNodes.push_back(pathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { - Ogre::Vector3 firstNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[0])); - float closestNode = npcPos.squaredDistance(firstNodePos); + osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0])); + float closestNode = (npcPos - firstNodePos).length2(); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { - Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(mAllowedNodes[counterThree])); - float tempDist = npcPos.squaredDistance(nodePos); + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); + float tempDist = (npcPos - nodePos).length2(); if(tempDist < closestNode) index = counterThree; } @@ -737,7 +735,7 @@ namespace MWMechanics std::vector nodeDistances; for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - float distance = npcPos.squaredDistance(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); + float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2(); nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); } std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 7f8fc5088a..b4eb3d21c1 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -54,7 +54,7 @@ namespace MWMechanics /// Set the position to return to for a stationary (non-wandering) actor /** In case another AI package moved the actor elsewhere **/ - void setReturnPosition (const Ogre::Vector3& position); + void setReturnPosition (const osg::Vec3f& position); virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; @@ -83,9 +83,9 @@ namespace MWMechanics bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position, // if we had the actor in the AiWander constructor... - Ogre::Vector3 mReturnPosition; + osg::Vec3f mReturnPosition; - Ogre::Vector3 mInitialActorPosition; + osg::Vec3f mInitialActorPosition; bool mStoredInitialActorPosition; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3843df132b..f17f2331f4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1531,7 +1531,7 @@ void CharacterController::update(float duration) if(mHitState != CharState_None && mJumpState == JumpState_None) vec = osg::Vec3f(0.f, 0.f, 0.f); - Ogre::Vector3 rot = cls.getRotationVector(mPtr); + osg::Vec3f rot = cls.getRotationVector(mPtr); mMovementSpeed = cls.getSpeed(mPtr); @@ -1728,11 +1728,11 @@ void CharacterController::update(float duration) // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot. // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon, // but I don't think we need to go as far as that. - else if(rot.z != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) + else if(rot.z() != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) { - if(rot.z > 0.0f) + if(rot.z() > 0.0f) movestate = CharState_TurnRight; - else if(rot.z < 0.0f) + else if(rot.z() < 0.0f) movestate = CharState_TurnLeft; } } @@ -1782,18 +1782,18 @@ void CharacterController::update(float duration) if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) { if (duration > 0) - mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z) / duration / Ogre::Math::PI)); + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / Ogre::Math::PI)); } if (!mSkipAnim) { - rot *= Ogre::Math::RadiansToDegrees(1.0f); + rot *= osg::RadiansToDegrees(1.0f); if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) { - world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); + world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); } else //avoid z-rotating for knockdown - world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); + world->rotateObject(mPtr, rot.x(), rot.y(), 0.0f, true); if (!mMovementAnimationControlled) world->queueMovement(mPtr, vec); diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 5795f818af..d338cf01a5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -15,9 +15,9 @@ namespace // Caller needs to be careful for very short distances (i.e. less than 1) // or when accumuating the results i.e. (a + b)^2 != a^2 + b^2 // - float distanceSquared(ESM::Pathgrid::Point point, Ogre::Vector3 pos) + float distanceSquared(ESM::Pathgrid::Point point, const osg::Vec3f& pos) { - return MWMechanics::PathFinder::MakeOgreVector3(point).squaredDistance(pos); + return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2(); } // Return the closest pathgrid point index from the specified position co @@ -26,7 +26,7 @@ namespace // // NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints // - int getClosestPoint(const ESM::Pathgrid* grid, Ogre::Vector3 pos) + int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { if(!grid || grid->mPoints.empty()) return -1; @@ -52,7 +52,7 @@ namespace // Chooses a reachable end pathgrid point. start is assumed reachable. std::pair getClosestReachablePoint(const ESM::Pathgrid* grid, const MWWorld::CellStore *cell, - Ogre::Vector3 pos, int start) + const osg::Vec3f pos, int start) { if(!grid || grid->mPoints.empty()) return std::pair (-1, false); @@ -216,12 +216,12 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall int startNode = getClosestPoint(mPathgrid, - Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); + osg::Vec3f(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); // Some cells don't have any pathgrids at all if(startNode != -1) { std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), + osg::Vec3f(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), startNode); // this shouldn't really happen, but just in case @@ -279,7 +279,7 @@ namespace MWMechanics float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; - return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); + return osg::RadiansToDegrees(std::atan2(directionX, directionY)); } bool PathFinder::checkPathCompleted(float x, float y, float tolerance) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 0f4d42775c..8386de70f7 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -44,6 +44,7 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. + /// In degrees float getZAngleToNext(float x, float y) const; bool isPathConstructed() const @@ -82,6 +83,12 @@ namespace MWMechanics return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); } + /// utility function to convert a osg::Vec3f to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const osg::Vec3f& v) + { + return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); + } + /// utility function to convert an ESM::Position to a Pathgrid::Point static ESM::Pathgrid::Point MakePathgridPoint(const ESM::Position& p) { diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 9f887f5ca8..219a236554 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -10,37 +10,37 @@ namespace MWMechanics { -bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis, Ogre::Degree epsilon) +bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, float epsilonRadians) { - Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[axis]); - Ogre::Radian diff (targetAngle - currentAngle); - if (diff >= Ogre::Degree(180)) + float currentAngle (actor.getRefData().getPosition().rot[axis]); + float diff (targetAngleRadians - currentAngle); + if (diff >= osg::DegreesToRadians(180.f)) { // Turning the other way would be a better idea - diff = diff-Ogre::Degree(360); + diff = diff-osg::DegreesToRadians(360.f); } - else if (diff <= Ogre::Degree(-180)) + else if (diff <= osg::DegreesToRadians(-180.f)) { - diff = Ogre::Degree(360)-diff; + diff = osg::DegreesToRadians(360.f)-diff; } - Ogre::Radian absDiff = Ogre::Math::Abs(diff); + float absDiff = std::abs(diff); // The turning animation actually moves you slightly, so the angle will be wrong again. // Use epsilon to prevent jerkiness. - if (absDiff < epsilon) + if (absDiff < epsilonRadians) return true; - Ogre::Radian limit = MAX_VEL_ANGULAR * MWBase::Environment::get().getFrameDuration(); + float limit = MAX_VEL_ANGULAR_RADIANS * MWBase::Environment::get().getFrameDuration(); if (absDiff > limit) - diff = Ogre::Math::Sign(diff) * limit; + diff = osg::sign(diff) * limit; - actor.getClass().getMovementSettings(actor).mRotation[axis] = diff.valueRadians(); + actor.getClass().getMovementSettings(actor).mRotation[axis] = diff; return false; } -bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, Ogre::Degree epsilon) +bool zTurn(const MWWorld::Ptr& actor, float targetAngleRadians, float epsilonRadians) { - return smoothTurn(actor, targetAngle, 2, epsilon); + return smoothTurn(actor, targetAngleRadians, 2, epsilonRadians); } } diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 91df49f0dd..4b29dc1d93 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -1,6 +1,6 @@ #ifndef OPENMW_MECHANICS_STEERING_H -#include +#include namespace MWWorld { @@ -11,15 +11,15 @@ namespace MWMechanics { // Max rotating speed, radian/sec -const Ogre::Radian MAX_VEL_ANGULAR(10); +const float MAX_VEL_ANGULAR_RADIANS(10); /// configure rotation settings for an actor to reach this target angle (eventually) /// @return have we reached the target angle? -bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, - Ogre::Degree epsilon = Ogre::Degree(0.5)); +bool zTurn(const MWWorld::Ptr& actor, float targetAngleRadians, + float epsilonRadians = osg::DegreesToRadians(0.5)); -bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis, - Ogre::Degree epsilon = Ogre::Degree(0.5)); +bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, + float epsilonRadians = osg::DegreesToRadians(0.5)); } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5999979dec..b757b1c91b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -186,9 +186,9 @@ namespace MWWorld throw std::runtime_error ("movement settings not supported by class"); } - Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const + osg::Vec3f Class::getRotationVector (const Ptr& ptr) const { - return Ogre::Vector3 (0, 0, 0); + return osg::Vec3f (0, 0, 0); } std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 02afd8960b..9357183480 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -192,7 +192,7 @@ namespace MWWorld virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; + virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 09f6de072d..a612ff80b2 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -206,9 +206,9 @@ namespace MWWorld player.mBirthsign = mSign; - player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x; - player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y; - player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z; + player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x(); + player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y(); + player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z(); if (mMarkedCell) { @@ -279,9 +279,9 @@ namespace MWWorld mSign = player.mBirthsign; - mLastKnownExteriorPosition.x = player.mLastKnownExteriorPosition[0]; - mLastKnownExteriorPosition.y = player.mLastKnownExteriorPosition[1]; - mLastKnownExteriorPosition.z = player.mLastKnownExteriorPosition[2]; + mLastKnownExteriorPosition.x() = player.mLastKnownExteriorPosition[0]; + mLastKnownExteriorPosition.y() = player.mLastKnownExteriorPosition[1]; + mLastKnownExteriorPosition.z() = player.mLastKnownExteriorPosition[2]; if (player.mHasMark && !player.mMarkedCell.mPaged) { diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 25d8981cde..8d29163e64 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -37,7 +37,7 @@ namespace MWWorld MWWorld::CellStore *mCellStore; std::string mSign; - Ogre::Vector3 mLastKnownExteriorPosition; + osg::Vec3f mLastKnownExteriorPosition; ESM::Position mMarkedPosition; // If no position was marked, this is NULL @@ -61,9 +61,8 @@ namespace MWWorld /// Interiors can not always be mapped to a world position. However /// world position is still required for divine / almsivi magic effects /// and the player arrow on the global map. - /// TODO: This should be stored in the savegame, too. - void setLastKnownExteriorPosition (const Ogre::Vector3& position) { mLastKnownExteriorPosition = position; } - Ogre::Vector3 getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; } + void setLastKnownExteriorPosition (const osg::Vec3f& position) { mLastKnownExteriorPosition = position; } + osg::Vec3f getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; } void set (const ESM::NPC *player); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7bc46c0780..a5f15da8ef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1585,7 +1585,7 @@ namespace MWWorld if (player.getCell()->isExterior()) { ESM::Position pos = player.getRefData().getPosition(); - mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); + mPlayer->setLastKnownExteriorPosition(pos.asVec3()); } if (player.getClass().getNpcStats(player).isWerewolf()) @@ -2324,20 +2324,19 @@ namespace MWWorld return mPhysics->getLineOfSight(actor, targetActor); } - float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) + float World::getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) { - osg::Vec3f from_ (from.x, from.y, from.z); - osg::Vec3f to_ (dir.x, dir.y, dir.z); - to_.normalize(); - to_ = from_ + (to_ * maxDist); + osg::Vec3f to (dir); + to.normalize(); + to = from + (to * maxDist); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from_, to_, MWWorld::Ptr(), + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); if (!result.mHit) return maxDist; else - return (result.mHitPos - from_).length(); + return (result.mHitPos - from).length(); } void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) @@ -2731,7 +2730,7 @@ namespace MWWorld } } - bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) + bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { if (cell->isExterior()) return false; @@ -2762,7 +2761,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); + result = pos.asVec3(); return true; } else @@ -2822,7 +2821,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { - Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + osg::Vec3f worldPos = ref.mRef.getDoorDest().asVec3(); return getClosestMarkerFromExteriorPosition(worldPos, id); } else @@ -2838,7 +2837,7 @@ namespace MWWorld return MWWorld::Ptr(); } - MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; float closestDistance = FLT_MAX; @@ -2847,8 +2846,8 @@ namespace MWWorld for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) { ESM::Position pos = it2->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); + osg::Vec3f markerPos = pos.asVec3(); + float distance = (worldPos - markerPos).length2(); if (distance < closestDistance) { closestDistance = distance; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 20d6bf9a1c..c70a102c3d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -156,7 +156,7 @@ namespace MWWorld float feetToGameUnits(float feet); MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); - MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); public: @@ -508,7 +508,7 @@ namespace MWWorld virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist); + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist); virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); @@ -583,7 +583,7 @@ namespace MWWorld // Are we in an exterior or pseudo-exterior cell and it's night? virtual bool isDark() const; - virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result); + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result); /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case From cc6d5a3ba0ee906db10d4482a7ae7b8e94a80a08 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:44:21 +0200 Subject: [PATCH 0382/1812] Fix player setup bug --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a5f15da8ef..1ac92cf16b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2092,6 +2092,7 @@ namespace MWWorld scaleObject(getPlayerPtr(), 1.f); // apply race height MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); + MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); From 2eec0caca0abae3a94cc3a83a9ac9943a5c4e306 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 19:59:54 +0200 Subject: [PATCH 0383/1812] Remove dependency on Ogre::StringConverter --- apps/openmw/mwmechanics/character.cpp | 25 +++++++++--- components/settings/settings.cpp | 57 +++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f17f2331f4..c5282bdf80 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,6 +56,13 @@ void wrap(float& rad) rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI; } +std::string toString(int num) +{ + std::ostringstream stream; + stream << num; + return stream.str(); +} + std::string getBestAttack (const ESM::Weapon* weapon) { int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; @@ -220,13 +227,13 @@ public: std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) { int numAnims=0; - while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) + while (mAnimation->hasAnimation(prefix + toString(numAnims+1))) ++numAnims; int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; - return prefix + Ogre::StringConverter::toString(roll); + return prefix + toString(roll); } void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) @@ -569,7 +576,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mCurrentDeath = "deathknockout"; break; default: - mCurrentDeath = "death" + Ogre::StringConverter::toString(death - CharState_Death1 + 1); + mCurrentDeath = "death" + toString(death - CharState_Death1 + 1); } mDeathState = death; @@ -736,9 +743,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: split(soundgen, ' ', tokens); soundgen = tokens[0]; if (tokens.size() >= 2) - volume = Ogre::StringConverter::parseReal(tokens[1]); + { + std::stringstream stream; + stream << tokens[1]; + stream >> volume; + } if (tokens.size() >= 3) - pitch = Ogre::StringConverter::parseReal(tokens[2]); + { + std::stringstream stream; + stream << tokens[2]; + stream >> pitch; + } } std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index a9a78d0351..90fd300ecf 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,13 +1,56 @@ #include "settings.hpp" #include +#include -#include +#include #include #include #include +namespace +{ + + bool parseBool(const std::string& string) + { + return (Misc::StringUtils::ciEqual(string, "true")); + } + + float parseFloat(const std::string& string) + { + std::stringstream stream; + stream << string; + float ret = 0.f; + stream >> ret; + return ret; + } + + int parseInt(const std::string& string) + { + std::stringstream stream; + stream << string; + int ret = 0; + stream >> ret; + return ret; + } + + template + std::string toString(T val) + { + std::ostringstream stream; + stream << val; + return stream.str(); + } + + template <> + std::string toString(bool val) + { + return val ? "true" : "false"; + } + +} + namespace Settings { @@ -143,17 +186,17 @@ std::string Manager::getString(const std::string &setting, const std::string &ca float Manager::getFloat (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseReal( getString(setting, category) ); + return parseFloat( getString(setting, category) ); } int Manager::getInt (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseInt( getString(setting, category) ); + return parseInt( getString(setting, category) ); } bool Manager::getBool (const std::string& setting, const std::string& category) { - return Ogre::StringConverter::parseBool( getString(setting, category) ); + return parseBool( getString(setting, category) ); } void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) @@ -174,17 +217,17 @@ void Manager::setString(const std::string &setting, const std::string &category, void Manager::setInt (const std::string& setting, const std::string& category, const int value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { - setString(setting, category, Ogre::StringConverter::toString(value)); + setString(setting, category, toString(value)); } const CategorySettingVector Manager::apply() From 364b785e8f37a3c8c197c7ba0986b03d9b926178 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 21:36:46 +0200 Subject: [PATCH 0384/1812] ESSImporter image conversions port to osg::Image --- apps/essimporter/converter.cpp | 69 +++++++++++++++++++++++----------- apps/essimporter/converter.hpp | 5 ++- apps/essimporter/importer.cpp | 56 +++++++++++++++++++++------ 3 files changed, 95 insertions(+), 35 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 91d290f331..ec396761c5 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -15,12 +17,14 @@ namespace { - void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out) + void convertImage(char* data, int size, int width, int height, GLenum pf, const std::string& out) { - Ogre::Image screenshot; - Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size)); - screenshot.loadRawData(stream, width, height, 1, pf); - screenshot.save(out); + osg::ref_ptr image (new osg::Image); + image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE); + memcpy(image->data(), data, size); + image->flipVertical(); + + osgDB::writeImageFile(*image, out); } @@ -71,17 +75,20 @@ namespace ESSImport data.resize(esm.getSubSize()); esm.getExact(&data[0], data.size()); - Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size())); - mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB); + mGlobalMapImage = new osg::Image; + mGlobalMapImage->allocateImage(maph.size, maph.size, 1, GL_RGB, GL_UNSIGNED_BYTE); + memcpy(mGlobalMapImage->data(), &data[0], data.size()); + // to match openmw size - mGlobalMapImage.resize(maph.size*2, maph.size*2, Ogre::Image::FILTER_BILINEAR); + // FIXME: filtering? + mGlobalMapImage->scaleImage(maph.size*2, maph.size*2, 1, GL_UNSIGNED_BYTE); } void ConvertFMAP::write(ESM::ESMWriter &esm) { - int numcells = mGlobalMapImage.getWidth() / 18; // NB truncating, doesn't divide perfectly + int numcells = mGlobalMapImage->s() / 18; // NB truncating, doesn't divide perfectly // with the 512x512 map the game has by default - int cellSize = mGlobalMapImage.getWidth()/numcells; + int cellSize = mGlobalMapImage->s()/numcells; // Note the upper left corner of the (0,0) cell should be at (width/2, height/2) @@ -90,12 +97,14 @@ namespace ESSImport mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2; mContext->mGlobalMapState.mBounds.mMaxY = numcells/2; - Ogre::Image image2; - std::vector data; + osg::ref_ptr image2 (new osg::Image); int width = cellSize*numcells; int height = cellSize*numcells; + std::vector data; data.resize(width*height*4, 0); - image2.loadDynamicImage(&data[0], width, height, Ogre::PF_BYTE_RGBA); + + image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE); + memcpy(image2->data(), &data[0], data.size()); for (std::set >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it) { @@ -108,8 +117,8 @@ namespace ESSImport continue; } - int imageLeftSrc = mGlobalMapImage.getWidth()/2; - int imageTopSrc = mGlobalMapImage.getHeight()/2; + int imageLeftSrc = mGlobalMapImage->s()/2; + int imageTopSrc = mGlobalMapImage->t()/2; imageLeftSrc += it->first * cellSize; imageTopSrc -= it->second * cellSize; int imageLeftDst = width/2; @@ -118,13 +127,31 @@ namespace ESSImport imageTopDst -= it->second * cellSize; for (int x=0; xdata(imageLeftSrc+x, imageTopSrc+y, 0); + *(unsigned int*)image2->data(imageLeftDst+x, imageTopDst+y, 0) = col; + } } - Ogre::DataStreamPtr encoded = image2.encode("png"); - mContext->mGlobalMapState.mImageData.resize(encoded->size()); - encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size()); + std::stringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "can't write global map image, no png readerwriter found" << std::endl; + return; + } + + image2->flipVertical(); + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream); + if (!result.success()) + { + std::cerr << "can't write global map image: " << result.message() << std::endl; + return; + } + + std::string outData = ostream.str(); + mContext->mGlobalMapState.mImageData = std::vector(outData.begin(), outData.end()); esm.startRecord(ESM::REC_GMAP); mContext->mGlobalMapState.save(esm); @@ -194,7 +221,7 @@ namespace ESSImport std::ostringstream filename; filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; - convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, GL_RGBA, filename.str()); } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5711e6754b..f00b254385 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -1,7 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CONVERTER_H #define OPENMW_ESSIMPORT_CONVERTER_H -#include +#include +#include #include #include @@ -311,7 +312,7 @@ public: virtual void write(ESM::ESMWriter &esm); private: - Ogre::Image mGlobalMapImage; + osg::ref_ptr mGlobalMapImage; }; class ConvertCell : public Converter diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index d5ed43b8a0..3959a8f5cc 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,7 +1,8 @@ #include "importer.hpp" #include -#include +#include +#include #include #include @@ -32,13 +33,48 @@ namespace void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out) { - Ogre::Image screenshot; - std::vector screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :( - Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size())); - screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA); - Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); - out.mScreenshot.resize(encoded->size()); - encoded->read(&out.mScreenshot[0], encoded->size()); + if (fileHeader.mSCRS.size() != 128*128*4) + { + std::cerr << "unexpected screenshot size " << std::endl; + return; + } + + osg::ref_ptr image (new osg::Image); + image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE); + + // need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise + std::vector::const_iterator it = fileHeader.mSCRS.begin(); + for (int y=0; y<128; ++y) + { + for (int x=0; x<128; ++x) + { + *(image->data(x,y)+2) = *it++; + *(image->data(x,y)+1) = *it++; + *image->data(x,y) = *it++; + it++; // skip alpha + } + } + + image->flipVertical(); + + std::stringstream ostream; + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); + if (!readerwriter) + { + std::cerr << "can't write screenshot: no jpg readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image, ostream); + if (!result.success()) + { + std::cerr << "can't write screenshot: " << result.message() << " code " << result.status() << std::endl; + return; + } + + std::string data = ostream.str(); + out.mScreenshot = std::vector(data.begin(), data.end()); } } @@ -203,10 +239,6 @@ namespace ESSImport void Importer::run() { - // construct Ogre::Root to gain access to image codecs - Ogre::LogManager logman; - Ogre::Root root; - ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding)); ESM::ESMReader esm; esm.open(mEssFile); From b70383d12762cd6b4cc8fb7d4254f10db7c8fdce Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 21:37:21 +0200 Subject: [PATCH 0385/1812] Remove last remains of Ogre math --- apps/openmw/mwmechanics/character.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 6 +-- apps/openmw/mwmechanics/obstacle.cpp | 4 +- apps/openmw/mwmechanics/pathfinding.hpp | 16 +----- apps/openmw/mwmechanics/summoning.cpp | 13 ++--- apps/openmw/mwrender/npcanimation.cpp | 22 -------- apps/openmw/mwrender/npcanimation.hpp | 9 ---- apps/openmw/mwrender/weaponanimation.hpp | 5 -- apps/openmw/mwscript/miscextensions.cpp | 4 +- .../mwscript/transformationextensions.cpp | 38 +++++++------- apps/openmw/mwworld/actionteleport.cpp | 3 +- apps/openmw/mwworld/scene.cpp | 12 ++--- apps/openmw/mwworld/worldimp.cpp | 52 +++++++++---------- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/util.hpp | 25 +-------- 15 files changed, 72 insertions(+), 141 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c5282bdf80..b0db1dfa04 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1797,7 +1797,7 @@ void CharacterController::update(float duration) if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) { if (duration > 0) - mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / Ogre::Math::PI)); + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); } if (!mSkipAnim) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8fbb31fb7b..b89b8c94a2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -31,10 +31,10 @@ namespace float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) { - Ogre::Vector3 pos1 (actor1.getRefData().getPosition().pos); - Ogre::Vector3 pos2 (actor2.getRefData().getPosition().pos); + osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); + osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - float d = pos1.distance(pos2); + float d = (pos1 - pos2).length(); static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( "iFightDistanceBase")->getInt(); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 7cfa6fcd5f..ae2cbcafe1 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -37,7 +37,7 @@ namespace MWMechanics MWWorld::CellRefList& doors = cell->get(); MWWorld::CellRefList::List& refList = doors.mList; MWWorld::CellRefList::List::iterator it = refList.begin(); - Ogre::Vector3 pos(actor.getRefData().getPosition().pos); + osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); /// TODO: How to check whether the actor is facing a door? Below code is for /// the player, perhaps it can be adapted. @@ -50,7 +50,7 @@ namespace MWMechanics for (; it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if(pos.squaredDistance(Ogre::Vector3(ref.mData.getPosition().pos)) < minSqr) + if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr) if((closed && ref.mData.getLocalRotation().rot[2] == 0) || (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 8386de70f7..ce0b541921 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -22,9 +22,9 @@ namespace MWMechanics public: PathFinder(); - static float sgn(Ogre::Radian a) + static float sgn(float val) { - if(a.valueRadians() > 0) + if(val > 0) return 1.0; return -1.0; } @@ -77,12 +77,6 @@ namespace MWMechanics mPath.push_back(point); } - /// utility function to convert a Ogre::Vector3 to a Pathgrid::Point - static ESM::Pathgrid::Point MakePathgridPoint(const Ogre::Vector3& v) - { - return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); - } - /// utility function to convert a osg::Vec3f to a Pathgrid::Point static ESM::Pathgrid::Point MakePathgridPoint(const osg::Vec3f& v) { @@ -100,12 +94,6 @@ namespace MWMechanics return osg::Vec3f(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); } - /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 - static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) - { - return Ogre::Vector3(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); - } - private: bool mIsPathConstructed; diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 4140fd3c0f..768afc35a0 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -115,13 +115,14 @@ namespace MWMechanics if (!found) { ESM::Position ipos = mActor.getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + osg::Vec3f pos(ipos.asVec3()); + + osg::Quat rot (-ipos.rot[2], osg::Vec3f(0,0,1)); const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; + pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; + ipos.pos[0] = pos.x(); + ipos.pos[1] = pos.y(); + ipos.pos[2] = pos.z(); ipos.rot[0] = 0; ipos.rot[1] = 0; ipos.rot[2] = 0; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1f05d93b6b..71c48a4897 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1062,26 +1062,4 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } -/* -void NpcAnimation::setHeadPitch(Ogre::Radian pitch) -{ - mHeadPitch = pitch; -} - -void NpcAnimation::setHeadYaw(Ogre::Radian yaw) -{ - mHeadYaw = yaw; -} - -Ogre::Radian NpcAnimation::getHeadPitch() const -{ - return mHeadPitch; -} - -Ogre::Radian NpcAnimation::getHeadYaw() const -{ - return mHeadYaw; -} -*/ - } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index db0b4ea0ce..23b663565a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -120,8 +120,6 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); - //void applyAlpha(float alpha, Ogre::Entity* ent, NifOgre::ObjectScenePtr scene); - osg::ref_ptr mFirstPersonNeckController; osg::ref_ptr mHeadController; @@ -171,19 +169,12 @@ public: virtual Resource::ResourceSystem* getResourceSystem(); // WeaponAnimation - //virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } virtual void showWeapon(bool show) { showWeapons(show); } - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); void setViewMode(ViewMode viewMode); void updateParts(); - /// \brief Applies a translation to the arms and hands. - /// This may be called multiple times before the animation - /// is updated to add additional offsets. - //void addFirstPersonOffset(const Ogre::Vector3 &offset); - /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 9336afd4ca..226d59c530 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -56,16 +56,11 @@ namespace MWRender virtual osg::Node* getWeaponNode() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0; - - //virtual NifOgre::ObjectScenePtr getWeapon() = 0; virtual void showWeapon(bool show) = 0; - //virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0; /// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// to indicate the facing orientation of the character, for ranged weapon aiming. float mPitchFactor; - - //void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel); }; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8580eb8f88..e706140fbe 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1045,8 +1045,8 @@ namespace MWScript msg << "Cell: " << MWBase::Environment::get().getWorld()->getCellName(cell) << std::endl; if (cell->getCell()->isExterior()) msg << "Grid: " << cell->getCell()->getGridX() << " " << cell->getCell()->getGridY() << std::endl; - Ogre::Vector3 pos (ptr.getRefData().getPosition().pos); - msg << "Coordinates: " << pos << std::endl; + osg::Vec3f pos (ptr.getRefData().getPosition().asVec3()); + msg << "Coordinates: " << pos.x() << " " << pos.y() << " " << pos.z() << std::endl; msg << "Model: " << ptr.getClass().getModel(ptr) << std::endl; if (!ptr.getClass().getScript(ptr).empty()) msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6ede67932d..0935061138 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -84,9 +84,9 @@ namespace MWScript 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(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); + float az = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]); MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); @@ -127,15 +127,15 @@ namespace MWScript if (axis == "x") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[0]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[0])); } else if (axis == "y") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[1]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[1])); } else if (axis == "z") { - runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[2]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[2])); } else throw std::runtime_error ("invalid rotation axis: " + axis); @@ -156,15 +156,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0])); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1])); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2])); } else throw std::runtime_error ("invalid rotation axis: " + axis); @@ -326,8 +326,8 @@ namespace MWScript ptr = MWWorld::Ptr(ptr.getBase(), store); dynamic_cast(runtime.getContext()).updatePtr(ptr); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. @@ -382,8 +382,8 @@ namespace MWScript } dynamic_cast(runtime.getContext()).updatePtr(ptr); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. @@ -567,9 +567,9 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); + float ax = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[0]); + float ay = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[1]); + float az = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[2]); if (axis == "x") { @@ -604,9 +604,9 @@ namespace MWScript const float *objRot = ptr.getRefData().getPosition().rot; - float ax = Ogre::Radian(objRot[0]).valueDegrees(); - float ay = Ogre::Radian(objRot[1]).valueDegrees(); - float az = Ogre::Radian(objRot[2]).valueDegrees(); + float ax = osg::RadiansToDegrees(objRot[0]); + float ay = osg::RadiansToDegrees(objRot[1]); + float az = osg::RadiansToDegrees(objRot[2]); if (axis == "x") { diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index fccd176a85..cd6698c985 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -40,8 +40,7 @@ namespace MWWorld for(std::set::iterator it = followers.begin();it != followers.end();++it) { MWWorld::Ptr follower = *it; - if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( - Ogre::Vector3( actor.getRefData().getPosition().pos)) + if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2() <= 800*800) teleport(*it); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1a9ae34943..78d093104e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -418,9 +418,9 @@ namespace MWWorld 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(); + float x = osg::RadiansToDegrees(pos.rot[0]); + float y = osg::RadiansToDegrees(pos.rot[1]); + float z = osg::RadiansToDegrees(pos.rot[2]); world->rotateObject(player, x, y, z); player.getClass().adjustPosition(player, true); @@ -475,9 +475,9 @@ namespace MWWorld MWBase::World *world = MWBase::Environment::get().getWorld(); world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]); - float x = Ogre::Radian(position.rot[0]).valueDegrees(); - float y = Ogre::Radian(position.rot[1]).valueDegrees(); - float z = Ogre::Radian(position.rot[2]).valueDegrees(); + float x = osg::RadiansToDegrees(position.rot[0]); + float y = osg::RadiansToDegrees(position.rot[1]); + float z = osg::RadiansToDegrees(position.rot[2]); world->rotateObject(world->getPlayerPtr(), x, y, z); world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr(), true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1ac92cf16b..9a42d45874 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -66,10 +66,11 @@ namespace // Wraps a value to (-PI, PI] void wrap(float& rad) { + const float pi = static_cast(osg::PI); if (rad>0) - rad = std::fmod(rad+Ogre::Math::PI, 2.0f*Ogre::Math::PI)-Ogre::Math::PI; + rad = std::fmod(rad+pi, 2.0f*pi)-pi; else - rad = std::fmod(rad-Ogre::Math::PI, 2.0f*Ogre::Math::PI)+Ogre::Math::PI; + rad = std::fmod(rad-pi, 2.0f*pi)+pi; } } @@ -1220,24 +1221,24 @@ namespace MWWorld mWorldScene->updateObjectScale(ptr); } - void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) + void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) { - const float two_pi = Ogre::Math::TWO_PI; - const float pi = Ogre::Math::PI; + const float pi = static_cast(osg::PI); + const float two_pi = pi*2.f; ESM::Position pos = ptr.getRefData().getPosition(); float *objRot = pos.rot; if(adjust) { - objRot[0] += rot.x; - objRot[1] += rot.y; - objRot[2] += rot.z; + objRot[0] += rot.x(); + objRot[1] += rot.y(); + objRot[2] += rot.z(); } else { - objRot[0] = rot.x; - objRot[1] = rot.y; - objRot[2] = rot.z; + objRot[0] = rot.x(); + objRot[1] = rot.y(); + objRot[2] = rot.z(); } if(ptr.getClass().isActor()) @@ -1246,7 +1247,7 @@ namespace MWWorld * currently it's done so for rotating the camera, which needs * clamping. */ - const float half_pi = Ogre::Math::HALF_PI; + const float half_pi = pi/2.f; if(objRot[0] < -half_pi) objRot[0] = -half_pi; else if(objRot[0] > half_pi) objRot[0] = half_pi; @@ -1272,9 +1273,9 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float x, float y, float z) { LocalRotation rot = ptr.getRefData().getLocalRotation(); - rot.rot[0]=Ogre::Degree(x).valueRadians(); - rot.rot[1]=Ogre::Degree(y).valueRadians(); - rot.rot[2]=Ogre::Degree(z).valueRadians(); + rot.rot[0]=osg::DegreesToRadians(x); + rot.rot[1]=osg::DegreesToRadians(y); + rot.rot[2]=osg::DegreesToRadians(z); wrap(rot.rot[0]); wrap(rot.rot[1]); @@ -1332,9 +1333,9 @@ namespace MWWorld void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { - rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), - Ogre::Degree(y).valueRadians(), - Ogre::Degree(z).valueRadians()), + rotateObjectImp(ptr, osg::Vec3f(osg::DegreesToRadians(x), + osg::DegreesToRadians(y), + osg::DegreesToRadians(z)), adjust); } @@ -2904,8 +2905,7 @@ namespace MWWorld World::DetectionType mType; bool operator() (MWWorld::Ptr ptr) { - if (Ogre::Vector3(ptr.getRefData().getPosition().pos).squaredDistance( - Ogre::Vector3(mDetector.getRefData().getPosition().pos)) >= mSquaredDist) + if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist) return true; if (!ptr.getRefData().isEnabled() || ptr.getRefData().isDeleted()) @@ -3096,13 +3096,13 @@ namespace MWWorld return; ESM::Position ipos = mPlayer->getPlayer().getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + osg::Vec3f pos(ipos.asVec3()); + osg::Quat rot(-ipos.rot[2], osg::Vec3f(0,0,1)); const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; + pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; + ipos.pos[0] = pos.x(); + ipos.pos[1] = pos.y(); + ipos.pos[2] = pos.z(); ipos.rot[0] = 0; ipos.rot[1] = 0; ipos.rot[2] = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c70a102c3d..bbc04ffdce 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,7 +111,7 @@ namespace MWWorld void updateWeather(float duration, bool paused = false); int getDaysPerMonth (int month) const; - void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); + void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust); Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 07a7655c74..3ab2ef049c 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -17,13 +17,7 @@ struct Quaternion float mValues[4]; Quaternion() {} - Quaternion (Ogre::Quaternion q) - { - mValues[0] = q.w; - mValues[1] = q.x; - mValues[2] = q.y; - mValues[3] = q.z; - } + Quaternion(const osg::Quat& q) { mValues[0] = q.w(); @@ -32,11 +26,6 @@ struct Quaternion mValues[3] = q.z(); } - operator Ogre::Quaternion () const - { - return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]); - } - operator osg::Quat () const { return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); @@ -48,12 +37,7 @@ struct Vector3 float mValues[3]; Vector3() {} - Vector3 (Ogre::Vector3 v) - { - mValues[0] = v.x; - mValues[1] = v.y; - mValues[2] = v.z; - } + Vector3(const osg::Vec3f& v) { mValues[0] = v.x(); @@ -61,11 +45,6 @@ struct Vector3 mValues[2] = v.z(); } - operator Ogre::Vector3 () const - { - return Ogre::Vector3(&mValues[0]); - } - operator osg::Vec3f () const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); From 4bb3cbf0fb29a60e223407e9875f9e8d9b2f7c61 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:04:35 +0200 Subject: [PATCH 0386/1812] Remove last remains of Ogre --- CMakeLists.txt | 8 +- apps/essimporter/converter.cpp | 3 - apps/essimporter/converter.hpp | 2 + apps/essimporter/importer.cpp | 3 + apps/opencs/CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwgui/hud.cpp | 2 - apps/openmw/mwgui/mapwindow.cpp | 2 - apps/openmw/mwgui/settingswindow.cpp | 2 - apps/openmw/mwgui/travelwindow.cpp | 2 - apps/openmw/mwmechanics/actors.hpp | 5 - apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 - apps/openmw/mwmechanics/aicombat.cpp | 2 - apps/openmw/mwmechanics/aicombat.hpp | 2 - apps/openmw/mwmechanics/aifollow.cpp | 3 - apps/openmw/mwmechanics/aipackage.cpp | 2 - apps/openmw/mwmechanics/aitravel.cpp | 2 - apps/openmw/mwmechanics/aiwander.cpp | 3 - apps/openmw/mwmechanics/aiwander.hpp | 2 - apps/openmw/mwmechanics/character.cpp | 2 - apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/combat.hpp | 1 - .../mwmechanics/mechanicsmanagerimp.hpp | 5 - apps/openmw/mwmechanics/objects.cpp | 2 - apps/openmw/mwmechanics/obstacle.cpp | 2 - apps/openmw/mwmechanics/pathfinding.cpp | 3 - apps/openmw/mwmechanics/pathfinding.hpp | 3 - apps/openmw/mwmechanics/spellcasting.hpp | 2 - apps/openmw/mwmechanics/summoning.cpp | 2 - apps/openmw/mwphysics/physicssystem.hpp | 6 +- apps/openmw/mwscript/cellextensions.cpp | 3 +- apps/openmw/mwscript/statsextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 2 + apps/openmw/mwsound/sound.hpp | 2 - apps/openmw/mwworld/class.cpp | 2 - apps/openmw/mwworld/class.hpp | 5 - apps/openmw/mwworld/player.hpp | 2 - apps/openmw/mwworld/refdata.cpp | 2 - apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/scene.hpp | 5 - apps/openmw/mwworld/weather.hpp | 3 +- apps/openmw/mwworld/worldimp.hpp | 5 - cmake/FindMyGUI.cmake | 2 +- cmake/FindOGRE.cmake | 568 ------------------ components/CMakeLists.txt | 1 - components/esm/util.hpp | 3 - 46 files changed, 17 insertions(+), 671 deletions(-) delete mode 100644 cmake/FindOGRE.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 487d07aa57..8dbad2924d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,11 +171,6 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OGRE REQUIRED) -if (${OGRE_VERSION} VERSION_LESS "1.9") - message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") -endif() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) @@ -191,7 +186,6 @@ find_package(Bullet REQUIRED) include_directories("." SYSTEM - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} @@ -200,7 +194,7 @@ include_directories("." ${BULLET_INCLUDE_DIRS} ) -link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) +link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${MYGUI_LIB_DIR}) if(MYGUI_STATIC) add_definitions(-DMYGUI_STATIC) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index ec396761c5..2ef10ee34b 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -2,9 +2,6 @@ #include -#include -#include - #include #include diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index f00b254385..fb8fb8c9fd 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CONVERTER_H #define OPENMW_ESSIMPORT_CONVERTER_H +#include + #include #include diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 3959a8f5cc..65f318297b 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,4 +1,7 @@ #include "importer.hpp" + +#include + #include #include diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7c539fb14c..4ade2df446 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -200,7 +200,6 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b238282544..8e17f2f31d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -126,7 +126,6 @@ endif () include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 44f944c3bd..56a4b08074 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,7 +1,5 @@ #include "hud.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d748bef6c2..34a9db1e1b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include #include diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 8ba46339ac..a50c305070 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,7 +1,5 @@ #include "settingswindow.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7985e7eda0..6ea6301adf 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f9e58ab4fe..4baaea28dd 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -10,11 +10,6 @@ #include "movement.hpp" #include "../mwbase/world.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 9d32aa97b3..29bf19942c 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -9,8 +9,6 @@ #include "movement.hpp" -#include - #include "steering.hpp" MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 495aaf82be..f31e0ff77f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -1,7 +1,5 @@ #include "aicombat.hpp" -#include - #include #include diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 307df3872c..e5454dc05e 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -8,8 +8,6 @@ #include "movement.hpp" #include "obstacle.hpp" -#include - #include "../mwworld/cellstore.hpp" // for Doors #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 24a50cbd64..524a7f904f 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -12,9 +12,6 @@ #include "creaturestats.hpp" #include "movement.hpp" -#include -#include - #include "steering.hpp" namespace MWMechanics diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 8db62dea81..b5d62ee31e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -10,8 +10,6 @@ #include "movement.hpp" #include "../mwworld/action.hpp" -#include - #include "steering.hpp" MWMechanics::AiPackage::~AiPackage() {} diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index f9fddf5754..6da5614d23 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,7 +1,5 @@ #include "aitravel.hpp" -#include - #include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 71508ac511..51b169ebab 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,8 +1,5 @@ #include "aiwander.hpp" -#include -#include - #include #include diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b4eb3d21c1..4b83179d54 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -5,8 +5,6 @@ #include -#include - #include "pathfinding.hpp" #include "obstacle.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b0db1dfa04..d4ba561edb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,8 +19,6 @@ #include "character.hpp" -#include - #include #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2b21310616..797c2e6237 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP -#include +#include #include diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 0a31a1a7e3..9412f62e79 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -2,7 +2,6 @@ #define OPENMW_MECHANICS_COMBAT_H #include "../mwworld/ptr.hpp" -#include namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f695ec57a8..5cc2ce2543 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -10,11 +10,6 @@ #include "objects.hpp" #include "actors.hpp" -namespace Ogre -{ - class Vector3; -} - namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index d6f5da88d2..4949d9b12f 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -1,7 +1,5 @@ #include "objects.hpp" -#include - #include "movement.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index ae2cbcafe1..3d2ab7d3d7 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,7 +1,5 @@ #include "obstacle.hpp" -#include - #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d338cf01a5..584bf84a08 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,8 +1,5 @@ #include "pathfinding.hpp" -#include "OgreMath.h" -#include "OgreVector3.h" - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index ce0b541921..4867c4c210 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -5,9 +5,6 @@ #include #include -#include -#include - namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 4241c9e3e3..2540b87db4 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -3,8 +3,6 @@ #include "../mwworld/ptr.hpp" -#include - #include namespace ESM diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 768afc35a0..541026ee18 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -1,7 +1,5 @@ #include "summoning.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7e3c279515..8cb31ed259 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -2,15 +2,13 @@ #define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H #include +#include -#include - +#include #include #include "../mwworld/ptr.hpp" -#include - #include "collisiontype.hpp" namespace osg diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 43d213c5af..8af2e5ef36 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -1,6 +1,7 @@ - #include "cellextensions.hpp" +#include + #include "../mwworld/esmstore.hpp" #include diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 80f46e4573..61a31e115d 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1,6 +1,6 @@ - #include "statsextensions.hpp" +#include #include #include diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 0935061138..0f9faa11a5 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,3 +1,5 @@ +#include + #include #include diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index bdc8cf459e..96f59cea00 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -1,8 +1,6 @@ #ifndef GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H -#include - #include "soundmanagerimp.hpp" namespace MWSound diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index b757b1c91b..f6170da7f1 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 9357183480..87325144af 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -14,11 +14,6 @@ namespace ESM struct ObjectState; } -namespace Ogre -{ - class Vector3; -} - namespace MWRender { class RenderingInterface; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 8d29163e64..2327b4dd5f 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -6,8 +6,6 @@ #include "../mwmechanics/drawstate.hpp" -#include - namespace ESM { struct NPC; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 54860fc313..c4f63137a7 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,8 +1,6 @@ #include "refdata.hpp" -#include - #include #include "customdata.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 78d093104e..62bc1f47e3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,6 @@ #include "scene.hpp" -#include +#include #include #include diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index af0b82fc38..ca6ed83b91 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -13,11 +13,6 @@ namespace osg class Vec3f; } -namespace Ogre -{ - class Vector3; -} - namespace ESM { struct Position; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 77d9610575..d7dfee99b9 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,9 +3,8 @@ #include #include +#include -#include -#include #include #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index bbc04ffdce..6b09fbb659 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -35,11 +35,6 @@ namespace Resource class ResourceSystem; } -namespace Ogre -{ - class Vector3; -} - namespace ESM { struct Position; diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index eccfb54ed9..320765b537 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -84,7 +84,7 @@ ELSE (WIN32) #Unix STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") ENDIF (MYGUI_INCLUDE_DIRS) ELSE (NOT APPLE) - SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR} ${OGRE_DEPENDENCIES_DIR}) + SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR}) FIND_PACKAGE(freetype) FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake deleted file mode 100644 index f2acf9d337..0000000000 --- a/cmake/FindOGRE.cmake +++ /dev/null @@ -1,568 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OGRE -# If you have multiple versions of Ogre installed, use the CMake or -# the environment variable OGRE_HOME to point to the path where the -# desired Ogre version can be found. -# By default this script will look for a dynamic Ogre build. If you -# need to link against static Ogre libraries, set the CMake variable -# OGRE_STATIC to TRUE. -# -# Once done, this will define -# -# OGRE_FOUND - system has OGRE -# OGRE_INCLUDE_DIRS - the OGRE include directories -# OGRE_LIBRARIES - link these to use the OGRE core -# OGRE_BINARY_REL - location of the main Ogre binary (win32 non-static only, release) -# OGRE_BINARY_DBG - location of the main Ogre binaries (win32 non-static only, debug) -# -# Additionally this script searches for the following optional -# parts of the Ogre package: -# Plugin_BSPSceneManager, Plugin_CgProgramManager, -# Plugin_OctreeSceneManager, Plugin_OctreeZone, -# Plugin_ParticleFX, Plugin_PCZSceneManager, -# RenderSystem_GL, RenderSystem_Direct3D9, RenderSystem_Direct3D10, -# Paging, Terrain -# -# For each of these components, the following variables are defined: -# -# OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available -# OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT} -# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT} -# OGRE_${COMPONENT}_BINARY_REL - location of the component binary (win32 non-static only, release) -# OGRE_${COMPONENT}_BINARY_DBG - location of the component binary (win32 non-static only, debug) -# -# Finally, the following variables are defined: -# -# OGRE_PLUGIN_DIR_REL - The directory where the release versions of -# the OGRE plugins are located -# OGRE_PLUGIN_DIR_DBG - The directory where the debug versions of -# the OGRE plugins are located -# OGRE_MEDIA_DIR - The directory where the OGRE sample media is -# located, if available - -include(FindPkgMacros) -include(PreprocessorUtils) -findpkg_begin(OGRE) - - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(OGRE_HOME) -getenv_path(OGRE_SDK) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_BUILD) -getenv_path(OGRE_DEPENDENCIES_DIR) -getenv_path(PROGRAMFILES) - -# Determine whether to search for a dynamic or static build -if (OGRE_STATIC) - set(OGRE_LIB_SUFFIX "Static") -else () - set(OGRE_LIB_SUFFIX "") -endif () - - -set(OGRE_LIBRARY_NAMES "OgreMain${OGRE_LIB_SUFFIX}") -get_debug_names(OGRE_LIBRARY_NAMES) - -# construct search paths from environmental hints and -# OS specific guesses -if (WIN32) - set(OGRE_PREFIX_GUESSES - ${ENV_PROGRAMFILES}/OGRE - C:/OgreSDK - ) -elseif (UNIX) - set(OGRE_PREFIX_GUESSES - /opt/ogre - /opt/OGRE - /usr/lib${LIB_SUFFIX}/ogre - /usr/lib${LIB_SUFFIX}/OGRE - /usr/local/lib${LIB_SUFFIX}/ogre - /usr/local/lib${LIB_SUFFIX}/OGRE - $ENV{HOME}/ogre - $ENV{HOME}/OGRE - ) -endif () -set(OGRE_PREFIX_PATH - ${OGRE_HOME} ${OGRE_SDK} ${ENV_OGRE_HOME} ${ENV_OGRE_SDK} - ${OGRE_PREFIX_GUESSES} -) -create_search_paths(OGRE) -# If both OGRE_BUILD and OGRE_SOURCE are set, prepare to find Ogre in a build dir -set(OGRE_PREFIX_SOURCE ${OGRE_SOURCE} ${ENV_OGRE_SOURCE}) -set(OGRE_PREFIX_BUILD ${OGRE_BUILD} ${ENV_OGRE_BUILD}) -set(OGRE_PREFIX_DEPENDENCIES_DIR ${OGRE_DEPENDENCIES_DIR} ${ENV_OGRE_DEPENDENCIES_DIR}) -if (OGRE_PREFIX_SOURCE AND OGRE_PREFIX_BUILD) - foreach(dir ${OGRE_PREFIX_SOURCE}) - set(OGRE_INC_SEARCH_PATH ${dir}/OgreMain/include ${dir}/Dependencies/include ${dir}/iPhoneDependencies/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${dir}/Dependencies/lib ${dir}/iPhoneDependencies/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - foreach(dir ${OGRE_PREFIX_BUILD}) - set(OGRE_INC_SEARCH_PATH ${dir}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/bin ${OGRE_BIN_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - - if (OGRE_PREFIX_DEPENDENCIES_DIR) - set(OGRE_INC_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/bin ${OGRE_BIN_SEARCH_PATH}) - endif() -else() - set(OGRE_PREFIX_SOURCE "NOTFOUND") - set(OGRE_PREFIX_BUILD "NOTFOUND") -endif () - -# redo search if any of the environmental hints changed -set(OGRE_COMPONENTS Paging Terrain Overlay - Plugin_BSPSceneManager Plugin_CgProgramManager Plugin_OctreeSceneManager - Plugin_OctreeZone Plugin_PCZSceneManager Plugin_ParticleFX - RenderSystem_Direct3D10 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES2) -set(OGRE_RESET_VARS - OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR - OGRE_LIBRARY_FWK OGRE_LIBRARY_REL OGRE_LIBRARY_DBG - OGRE_PLUGIN_DIR_DBG OGRE_PLUGIN_DIR_REL OGRE_MEDIA_DIR) -foreach (comp ${OGRE_COMPONENTS}) - set(OGRE_RESET_VARS ${OGRE_RESET_VARS} - OGRE_${comp}_INCLUDE_DIR OGRE_${comp}_LIBRARY_FWK - OGRE_${comp}_LIBRARY_DBG OGRE_${comp}_LIBRARY_REL - ) -endforeach (comp) -set(OGRE_PREFIX_WATCH ${OGRE_PREFIX_PATH} ${OGRE_PREFIX_SOURCE} ${OGRE_PREFIX_BUILD}) -clear_if_changed(OGRE_PREFIX_WATCH ${OGRE_RESET_VARS}) - -# try to locate Ogre via pkg-config -use_pkgconfig(OGRE_PKGC "OGRE${OGRE_LIB_SUFFIX}") - -if(NOT OGRE_BUILD_PLATFORM_IPHONE AND APPLE) - # try to find framework on OSX - findpkg_framework(OGRE) -else() - set(OGRE_LIBRARY_FWK "") -endif() - -# locate Ogre include files -find_path(OGRE_CONFIG_INCLUDE_DIR NAMES OgreBuildSettings.h HINTS ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -find_path(OGRE_INCLUDE_DIR NAMES OgreRoot.h HINTS ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -set(OGRE_INCOMPATIBLE FALSE) - -if (OGRE_INCLUDE_DIR) - if (NOT OGRE_CONFIG_INCLUDE_DIR) - set(OGRE_CONFIG_INCLUDE_DIR ${OGRE_INCLUDE_DIR}) - endif () - # determine Ogre version - file(READ ${OGRE_INCLUDE_DIR}/OgrePrerequisites.h OGRE_TEMP_VERSION_CONTENT) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MAJOR OGRE_VERSION_MAJOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MINOR OGRE_VERSION_MINOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_PATCH OGRE_VERSION_PATCH) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_NAME OGRE_VERSION_NAME) - set(OGRE_VERSION "${OGRE_VERSION_MAJOR}.${OGRE_VERSION_MINOR}.${OGRE_VERSION_PATCH}") - pkg_message(OGRE "Found Ogre ${OGRE_VERSION_NAME} (${OGRE_VERSION})") - - # determine configuration settings - set(OGRE_CONFIG_HEADERS - ${OGRE_CONFIG_INCLUDE_DIR}/OgreBuildSettings.h - ${OGRE_CONFIG_INCLUDE_DIR}/OgreConfig.h - ) - foreach(CFG_FILE ${OGRE_CONFIG_HEADERS}) - if (EXISTS ${CFG_FILE}) - set(OGRE_CONFIG_HEADER ${CFG_FILE}) - break() - endif() - endforeach() - if (OGRE_CONFIG_HEADER) - file(READ ${OGRE_CONFIG_HEADER} OGRE_TEMP_CONFIG_CONTENT) - has_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_STATIC_LIB OGRE_CONFIG_STATIC) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_SUPPORT OGRE_CONFIG_THREADS) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_PROVIDER OGRE_CONFIG_THREAD_PROVIDER) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_NO_FREEIMAGE OGRE_CONFIG_FREEIMAGE) - if (OGRE_CONFIG_STATIC AND OGRE_STATIC) - elseif (OGRE_CONFIG_STATIC OR OGRE_STATIC) - pkg_message(OGRE "Build type (static, dynamic) does not match the requested one.") - set(OGRE_INCOMPATIBLE TRUE) - endif () - else () - pkg_message(OGRE "Could not determine Ogre build configuration.") - set(OGRE_INCOMPATIBLE TRUE) - endif () -else () - set(OGRE_INCOMPATIBLE FALSE) -endif () - -find_library(OGRE_LIBRARY_REL NAMES ${OGRE_LIBRARY_NAMES} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") -find_library(OGRE_LIBRARY_DBG NAMES ${OGRE_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "debug") -make_library_set(OGRE_LIBRARY) - -if(APPLE) - set(OGRE_LIBRARY_DBG ${OGRE_LIB_SEARCH_PATH}) -endif() -if (OGRE_INCOMPATIBLE) - set(OGRE_LIBRARY "NOTFOUND") -endif () - -set(OGRE_INCLUDE_DIR ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}) -list(REMOVE_DUPLICATES OGRE_INCLUDE_DIR) -findpkg_finish(OGRE) -add_parent_dir(OGRE_INCLUDE_DIRS OGRE_INCLUDE_DIR) -if (OGRE_SOURCE) - # If working from source rather than SDK, add samples include - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} "${OGRE_SOURCE}/Samples/Common/include") -endif() - -mark_as_advanced(OGRE_CONFIG_INCLUDE_DIR OGRE_MEDIA_DIR OGRE_PLUGIN_DIR_REL OGRE_PLUGIN_DIR_DBG) - -if (NOT OGRE_FOUND) - return() -endif () - - -# look for required Ogre dependencies in case of static build and/or threading -if (OGRE_STATIC) - set(OGRE_DEPS_FOUND TRUE) - find_package(Cg QUIET) - find_package(DirectX QUIET) - find_package(FreeImage QUIET) - find_package(Freetype QUIET) - find_package(OpenGL QUIET) - find_package(OpenGLES2 QUIET) - find_package(ZLIB QUIET) - find_package(ZZip QUIET) - if (UNIX AND (NOT APPLE AND NOT ANDROID)) - find_package(X11 QUIET) - find_library(XAW_LIBRARY NAMES Xaw Xaw7 PATHS ${DEP_LIB_SEARCH_DIR} ${X11_LIB_SEARCH_PATH}) - if (NOT XAW_LIBRARY OR NOT X11_Xt_FOUND) - set(X11_FOUND FALSE) - endif () - endif () - if (APPLE AND NOT OGRE_BUILD_PLATFORM_IPHONE) - find_package(Cocoa QUIET) - find_package(Carbon QUIET) - if (NOT Cocoa_FOUND OR NOT Carbon_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - if (APPLE AND OGRE_BUILD_PLATFORM_IPHONE) - find_package(iPhoneSDK QUIET) - if (NOT iPhoneSDK_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - -if (ANDROID) - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${OGRE_LIBRARY_FWK} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} - ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} - ${Cocoa_LIBRARIES} ${Carbon_LIBRARIES}) -else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${OGRE_LIBRARY_FWK} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} - ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} - ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} - ${Cocoa_LIBRARIES} ${Carbon_LIBRARIES}) -endif() - - if (NOT ZLIB_FOUND OR NOT ZZip_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FreeImage_FOUND AND NOT OGRE_CONFIG_FREEIMAGE) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FREETYPE_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (UNIX AND NOT APPLE AND NOT ANDROID) - if (NOT X11_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - - if (OGRE_CONFIG_THREADS) - if (OGRE_CONFIG_THREAD_PROVIDER EQUAL 1) - find_package(Boost COMPONENTS thread QUIET) - if (NOT Boost_THREAD_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${Boost_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 2) - find_package(POCO QUIET) - if (NOT POCO_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${POCO_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${POCO_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 3) - find_package(TBB QUIET) - if (NOT TBB_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${TBB_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}) - endif () - endif () - endif () - - if (NOT OGRE_DEPS_FOUND) - pkg_message(OGRE "Could not find all required dependencies for the Ogre package.") - set(OGRE_FOUND FALSE) - endif () -endif () - -if (NOT OGRE_FOUND) - return() -endif () - - -get_filename_component(OGRE_LIBRARY_DIR_REL "${OGRE_LIBRARY_REL}" PATH) -get_filename_component(OGRE_LIBRARY_DIR_DBG "${OGRE_LIBRARY_DBG}" PATH) -set(OGRE_LIBRARY_DIRS ${OGRE_LIBRARY_DIR_REL} ${OGRE_LIBRARY_DIR_DBG}) - -# find binaries -if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_BINARY_REL NAMES "OgreMain.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - find_file(OGRE_BINARY_DBG NAMES "OgreMain_d.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" debug ) - endif() - mark_as_advanced(OGRE_BINARY_REL OGRE_BINARY_DBG) -endif() - - -######################################################### -# Find Ogre components -######################################################### - -set(OGRE_COMPONENT_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} -) -set(OGRE_COMPONENT_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} -) - -macro(ogre_find_component COMPONENT HEADER) - findpkg_begin(OGRE_${COMPONENT}) - find_path(OGRE_${COMPONENT}_INCLUDE_DIR NAMES ${HEADER} HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR}/OGRE/${COMPONENT} ${OGRE_PREFIX_SOURCE} PATH_SUFFIXES ${COMPONENT} OGRE/${COMPONENT} Components/${COMPONENT}/include) - set(OGRE_${COMPONENT}_LIBRARY_NAMES "Ogre${COMPONENT}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${COMPONENT}_LIBRARY_NAMES) - find_library(OGRE_${COMPONENT}_LIBRARY_REL NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES} HINTS ${OGRE_LIBRARY_DIR_REL} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") - find_library(OGRE_${COMPONENT}_LIBRARY_DBG NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIBRARY_DIR_DBG} PATH_SUFFIXES "" "debug") - make_library_set(OGRE_${COMPONENT}_LIBRARY) - findpkg_finish(OGRE_${COMPONENT}) - if (OGRE_${COMPONENT}_FOUND) - if (APPLE) - include_directories("${OGRE_INCLUDE_DIR}/OGRE/${COMPONENT}") - endif() - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${COMPONENT}_BINARY_REL NAMES "Ogre${COMPONENT}.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_REL} PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_file(OGRE_${COMPONENT}_BINARY_DBG NAMES "Ogre${COMPONENT}_d.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_DBG} PATH_SUFFIXES "" bin bin/debug debug) - endif() - mark_as_advanced(OGRE_${COMPONENT}_BINARY_REL OGRE_${COMPONENT}_BINARY_DBG) - endif() - endif() -endmacro() - -# look for Paging component -ogre_find_component(Paging OgrePaging.h) -# look for Overlay component -ogre_find_component(Overlay OgreOverlaySystem.h) -# look for Terrain component -ogre_find_component(Terrain OgreTerrain.h) -# look for Property component -ogre_find_component(Property OgreProperty.h) -# look for RTShaderSystem component -ogre_find_component(RTShaderSystem OgreRTShaderSystem.h) - - -######################################################### -# Find Ogre plugins -######################################################### - -macro(ogre_find_plugin PLUGIN HEADER) - # On Unix, the plugins might have no prefix - if (CMAKE_FIND_LIBRARY_PREFIXES) - set(TMP_CMAKE_LIB_PREFIX ${CMAKE_FIND_LIBRARY_PREFIXES}) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "") - endif() - - # strip RenderSystem_ or Plugin_ prefix from plugin name - string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) - string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - - # header files for plugins are not usually needed, but find them anyway if they are present - set(OGRE_PLUGIN_PATH_SUFFIXES - PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} - RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN}) - find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER} - HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} - PATH_SUFFIXES ${OGRE_PLUGIN_PATH_SUFFIXES}) - # find link libraries for plugins - set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${PLUGIN}_LIBRARY_NAMES) - set(OGRE_${PLUGIN}_LIBRARY_FWK ${OGRE_LIBRARY_FWK}) - # Search for release plugins in OGRE dir with version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) - if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_REL}") - # Search for release plugins in OGRE dir without version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) - endif() - # Search for debug plugins in OGRE dir with version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt debug debug/opt) - if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_DBG}") - # Search for debug plugins in OGRE dir without version suffix - find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) - endif() - make_library_set(OGRE_${PLUGIN}_LIBRARY) - - if (OGRE_${PLUGIN}_LIBRARY OR OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_FOUND TRUE) - if (OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIR}) - endif() - set(OGRE_${PLUGIN}_LIBRARIES ${OGRE_${PLUGIN}_LIBRARY}) - endif () - - mark_as_advanced(OGRE_${PLUGIN}_INCLUDE_DIR OGRE_${PLUGIN}_LIBRARY_REL OGRE_${PLUGIN}_LIBRARY_DBG OGRE_${PLUGIN}_LIBRARY_FWK) - - # look for plugin dirs - if (OGRE_${PLUGIN}_FOUND) - if (NOT OGRE_PLUGIN_DIR_REL OR NOT OGRE_PLUGIN_DIR_DBG) - if (WIN32) - set(OGRE_PLUGIN_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - set(OGRE_PLUGIN_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - find_path(OGRE_PLUGIN_DIR_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_REL} - PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_path(OGRE_PLUGIN_DIR_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_DBG} - PATH_SUFFIXES "" bin bin/debug debug) - elseif (UNIX) - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_REL} PATH) - # For some reason this fails - #set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") - set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP}) - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_DBG} PATH) - # Same here - #set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") - set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP}) - endif () - endif () - - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${PLUGIN}_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_DIR_REL}) - find_file(OGRE_${PLUGIN}_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_DIR_DBG}) - endif() - mark_as_advanced(OGRE_${PLUGIN}_REL OGRE_${PLUGIN}_DBG) - endif() - - endif () - - if (TMP_CMAKE_LIB_PREFIX) - set(CMAKE_FIND_LIBRARY_PREFIXES ${TMP_CMAKE_LIB_PREFIX}) - endif () -endmacro(ogre_find_plugin) - -ogre_find_plugin(Plugin_PCZSceneManager OgrePCZSceneManager.h PCZ PlugIns/PCZSceneManager/include) -ogre_find_plugin(Plugin_OctreeZone OgreOctreeZone.h PCZ PlugIns/OctreeZone/include) -ogre_find_plugin(Plugin_BSPSceneManager OgreBspSceneManager.h PlugIns/BSPSceneManager/include) -ogre_find_plugin(Plugin_CgProgramManager OgreCgProgram.h PlugIns/CgProgramManager/include) -ogre_find_plugin(Plugin_OctreeSceneManager OgreOctreeSceneManager.h PlugIns/OctreeSceneManager/include) -ogre_find_plugin(Plugin_ParticleFX OgreParticleFXPrerequisites.h PlugIns/ParticleFX/include) -ogre_find_plugin(RenderSystem_GL OgreGLRenderSystem.h RenderSystems/GL/include) -ogre_find_plugin(RenderSystem_GLES2 OgreGLES2RenderSystem.h RenderSystems/GLES2/include) -ogre_find_plugin(RenderSystem_Direct3D9 OgreD3D9RenderSystem.h RenderSystems/Direct3D9/include) -ogre_find_plugin(RenderSystem_Direct3D10 OgreD3D10RenderSystem.h RenderSystems/Direct3D10/include) -ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/Direct3D11/include) - -if (OGRE_STATIC) - # check if dependencies for plugins are met - if (NOT DirectX9_FOUND) - set(OGRE_RenderSystem_Direct3D9_FOUND FALSE) - else () - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX9_INCLUDE_DIR}) - endif () - if (NOT DirectX_D3D10_FOUND) - set(OGRE_RenderSystem_Direct3D10_FOUND FALSE) - endif () - if (NOT DirectX_D3D11_FOUND) - set(OGRE_RenderSystem_Direct3D11_FOUND FALSE) - else () - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX_D3D11_INCLUDE_DIR}) - endif () - if (NOT OPENGL_FOUND) - set(OGRE_RenderSystem_GL_FOUND FALSE) - endif () - if (NOT OPENGLES_FOUND AND NOT OPENGLES2_FOUND) - set(OGRE_RenderSystem_GLES_FOUND FALSE) - endif () - if (NOT Cg_FOUND) - set(OGRE_Plugin_CgProgramManager_FOUND FALSE) - endif () - - set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES} - ${DirectX9_LIBRARIES} - ) - set(OGRE_RenderSystem_Direct3D10_LIBRARIES ${OGRE_RenderSystem_Direct3D10_LIBRARIES} - ${DirectX_D3D10_LIBRARIES} - ) - set(OGRE_RenderSystem_Direct3D11_LIBRARIES ${OGRE_RenderSystem_Direct3D11_LIBRARIES} - ${DirectX_D3D11_LIBRARIES} - ) - set(OGRE_RenderSystem_GL_LIBRARIES ${OGRE_RenderSystem_GL_LIBRARIES} - ${OPENGL_LIBRARIES} - ) - set(OGRE_RenderSystem_GLES2_LIBRARIES ${OGRE_RenderSystem_GLES2_LIBRARIES} - ${OPENGLES2_LIBRARIES} - ) - set(OGRE_Plugin_CgProgramManager_LIBRARIES ${OGRE_Plugin_CgProgramManager_LIBRARIES} - ${Cg_LIBRARIES} - ) -endif () - -# look for the media directory -set(OGRE_MEDIA_SEARCH_PATH - ${OGRE_SOURCE} - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_PREFIX_SOURCE} -) -set(OGRE_MEDIA_SEARCH_SUFFIX - Samples/Media - Media - media - share/OGRE/media -) - -clear_if_changed(OGRE_PREFIX_WATCH OGRE_MEDIA_DIR) -find_path(OGRE_MEDIA_DIR NAMES packs/cubemapsJS.zip HINTS ${OGRE_MEDIA_SEARCH_PATH} - PATHS ${OGRE_PREFIX_PATH} PATH_SUFFIXES ${OGRE_MEDIA_SEARCH_SUFFIX}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7b0094b3f8..5a4ec605b3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -174,7 +174,6 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} - ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${BULLET_LIBRARIES} ${SDL2_LIBRARY} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 3ab2ef049c..a80df2456f 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,9 +1,6 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H -#include -#include - #include #include From 7991ea25c07b1f19163950e686bff41039be9edb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:32:49 +0200 Subject: [PATCH 0387/1812] Potentially missing includes --- extern/osg-ffmpeg-videoplayer/videoplayer.cpp | 2 ++ extern/osg-ffmpeg-videoplayer/videostate.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp index 9bd4a2df3f..9ec8151300 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,7 @@ #include "videoplayer.hpp" +#include + #include #include "audiofactory.hpp" diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 4a4f2fc6b3..72a2aab186 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,6 +1,8 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H +#include + #include #include From 60ad5680049d4670a89148b0fb3b06a6a2cc5de0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Jun 2015 23:46:04 +0200 Subject: [PATCH 0388/1812] Another missing include --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 1b02e13bef..8a9cce1b77 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -1,5 +1,7 @@ #include "videostate.hpp" +#include + #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif From 7fe86a7fe090b3b1418868d0fb073f44f0c76af3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 00:08:28 +0200 Subject: [PATCH 0389/1812] Adjust travis config -ogre, -boost_wave, +osg --- CI/before_install.linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 27cb714638..5823825ae4 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -12,9 +12,9 @@ echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_ echo "yes" | sudo apt-add-repository ppa:openmw/openmw sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev +sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev -sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build From 58917bcca61e8346450045443719fff518b66ecb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 00:28:09 +0200 Subject: [PATCH 0390/1812] Minor cleanup --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dbad2924d..9f47b5faec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,7 +188,6 @@ include_directories("." SYSTEM ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} - ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} From 7ac4b2bb66e8915e335c5e3ef21fb100e8c1bdb9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 01:16:52 +0200 Subject: [PATCH 0391/1812] Fix for travis build issue --- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index b886257e75..79f9edb1c6 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -1,6 +1,14 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H +// FIXME: This can't be right? The ffmpeg headers refuse to build without UINT64_C, +// which only gets defined in stdint.h in either C99 mode or with this macro +// defined... +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +#include + #include #include From 91eea1258c67c314fbe24bb158eee3306d3bee5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 01:30:16 +0200 Subject: [PATCH 0392/1812] doc.hpp fix --- apps/openmw/doc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/doc.hpp b/apps/openmw/doc.hpp index 978f0f5fb2..ffeef94e1e 100644 --- a/apps/openmw/doc.hpp +++ b/apps/openmw/doc.hpp @@ -25,7 +25,7 @@ /// \namespace MWRender /// \ingroup openmw -/// \brief Rendering via Ogre +/// \brief Rendering /// \namespace MWWorld /// \ingroup openmw From a2e211675d622a139142613b2671d2c32a35e75c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 02:35:52 +0200 Subject: [PATCH 0393/1812] Update openmw_layers.xml to newer version --- files/mygui/openmw_layers.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 50f83aaa2c..cf577aec52 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + From b6aed649824c355f81440d7fd0e3a2eea7c9a311 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 15:41:49 +0200 Subject: [PATCH 0394/1812] Asking travis for a test run now that OSG 3.2 is in our PPA --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1fc85dca38..7b5155137d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: cpp branches: only: - master + - osg - coverity_scan - /openmw-.*$/ env: From 71509d249732688cec57266ec2574ba373ace208 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 15:59:24 +0200 Subject: [PATCH 0395/1812] Remove cmake script Ogre leftovers --- cmake/COPYING-CMAKE-SCRIPTS | 2 +- cmake/FindCg.cmake | 53 ----------------- cmake/FindDirectX.cmake | 72 ----------------------- cmake/FindDirectX11.cmake | 114 ------------------------------------ cmake/FindFreeImage.cmake | 47 --------------- cmake/FindZZip.cmake | 48 --------------- 6 files changed, 1 insertion(+), 335 deletions(-) delete mode 100644 cmake/FindCg.cmake delete mode 100644 cmake/FindDirectX.cmake delete mode 100644 cmake/FindDirectX11.cmake delete mode 100644 cmake/FindFreeImage.cmake delete mode 100644 cmake/FindZZip.cmake diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index 8ee3ea36b2..d33c6f33bd 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -1,7 +1,7 @@ The following files are derived from the Thermite project (http://www.thermite3d.org) and are covered under the license below. -FindMYGUI.cmake, FindOGRE.cmake, FindOIS.cmake, FindBullet.cmake +FindMYGUI.cmake, FindBullet.cmake Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/cmake/FindCg.cmake b/cmake/FindCg.cmake deleted file mode 100644 index 4bd348c46f..0000000000 --- a/cmake/FindCg.cmake +++ /dev/null @@ -1,53 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find Cg -# Once done, this will define -# -# Cg_FOUND - system has Cg -# Cg_INCLUDE_DIRS - the Cg include directories -# Cg_LIBRARIES - link these to use Cg - -include(FindPkgMacros) -findpkg_begin(Cg) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(Cg_HOME) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_HOME) - -# construct search paths -set(Cg_PREFIX_PATH ${Cg_HOME} ${ENV_Cg_HOME} - ${OGRE_SOURCE}/Dependencies - ${ENV_OGRE_SOURCE}/Dependencies - ${OGRE_HOME} ${ENV_OGRE_HOME} - /opt/nvidia-cg-toolkit) -create_search_paths(Cg) -# redo search if prefix path changed -clear_if_changed(Cg_PREFIX_PATH - Cg_LIBRARY_FWK - Cg_LIBRARY_REL - Cg_LIBRARY_DBG - Cg_INCLUDE_DIR -) - -set(Cg_LIBRARY_NAMES Cg) -get_debug_names(Cg_LIBRARY_NAMES) - -use_pkgconfig(Cg_PKGC Cg) - -findpkg_framework(Cg) - -find_path(Cg_INCLUDE_DIR NAMES cg.h HINTS ${Cg_FRAMEWORK_INCLUDES} ${Cg_INC_SEARCH_PATH} ${Cg_PKGC_INCLUDE_DIRS} PATH_SUFFIXES Cg) -find_library(Cg_LIBRARY_REL NAMES ${Cg_LIBRARY_NAMES} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(Cg_LIBRARY_DBG NAMES ${Cg_LIBRARY_NAMES_DBG} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(Cg_LIBRARY) - -findpkg_finish(Cg) -add_parent_dir(Cg_INCLUDE_DIRS Cg_INCLUDE_DIR) diff --git a/cmake/FindDirectX.cmake b/cmake/FindDirectX.cmake deleted file mode 100644 index 4641b55a3d..0000000000 --- a/cmake/FindDirectX.cmake +++ /dev/null @@ -1,72 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# Find DirectX9 SDK -# Define: -# DirectX9_FOUND -# DirectX9_INCLUDE_DIR -# DirectX9_LIBRARY -# DirectX9_ROOT_DIR - -if(WIN32) # The only platform it makes sense to check for DirectX9 SDK - include(FindPkgMacros) - findpkg_begin(DirectX9) - - # Get path, convert backslashes as ${ENV_DXSDK_DIR} - getenv_path(DXSDK_DIR) - getenv_path(DirectX_HOME) - getenv_path(DirectX_ROOT) - getenv_path(DirectX_BASE) - - # construct search paths - set(DirectX9_PREFIX_PATH - "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" - "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" - "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" - "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" - "C:/apps_x86/Microsoft DirectX SDK*" - "C:/Program Files (x86)/Microsoft DirectX SDK*" - "C:/apps/Microsoft DirectX SDK*" - "C:/Program Files/Microsoft DirectX SDK*" - "$ENV{ProgramFiles}/Microsoft DirectX SDK*" - ) - - create_search_paths(DirectX9) - # redo search if prefix path changed - clear_if_changed(DirectX9_PREFIX_PATH - DirectX9_LIBRARY - DirectX9_INCLUDE_DIR - ) - - find_path(DirectX9_INCLUDE_DIR NAMES d3d9.h D3DCommon.h HINTS ${DirectX9_INC_SEARCH_PATH}) - # dlls are in DirectX9_ROOT_DIR/Developer Runtime/x64|x86 - # lib files are in DirectX9_ROOT_DIR/Lib/x64|x86 - if(CMAKE_CL_64) - set(DirectX9_LIBPATH_SUFFIX "x64") - else(CMAKE_CL_64) - set(DirectX9_LIBPATH_SUFFIX "x86") - endif(CMAKE_CL_64) - find_library(DirectX9_LIBRARY NAMES d3d9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - find_library(DirectX9_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) - - findpkg_finish(DirectX9) - set(DirectX9_LIBRARIES ${DirectX9_LIBRARIES} - ${DirectX9_D3DX9_LIBRARY} - ${DirectX9_DXERR_LIBRARY} - ${DirectX9_DXGUID_LIBRARY} - ) - - mark_as_advanced(DirectX9_D3DX9_LIBRARY DirectX9_DXERR_LIBRARY DirectX9_DXGUID_LIBRARY - DirectX9_DXGI_LIBRARY DirectX9_D3DCOMPILER_LIBRARY) - - -endif(WIN32) diff --git a/cmake/FindDirectX11.cmake b/cmake/FindDirectX11.cmake deleted file mode 100644 index 22d5b5441f..0000000000 --- a/cmake/FindDirectX11.cmake +++ /dev/null @@ -1,114 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# ----------------------------------------------------------------------------- -# Find DirectX11 SDK -# Define: -# DirectX11_FOUND -# DirectX11_INCLUDE_DIR -# DirectX11_LIBRARY -# DirectX11_ROOT_DIR - -if(WIN32) # The only platform it makes sense to check for DirectX11 SDK - include(FindPkgMacros) - findpkg_begin(DirectX11) - - # Get path, convert backslashes as ${ENV_DXSDK_DIR} - getenv_path(DXSDK_DIR) - getenv_path(DIRECTX_HOME) - getenv_path(DIRECTX_ROOT) - getenv_path(DIRECTX_BASE) - - # construct search paths - set(DirectX11_PREFIX_PATH - "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" - "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" - "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" - "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" - "C:/apps_x86/Microsoft DirectX SDK*" - "C:/Program Files (x86)/Microsoft DirectX SDK*" - "C:/apps/Microsoft DirectX SDK*" - "C:/Program Files/Microsoft DirectX SDK*" - "$ENV{ProgramFiles}/Microsoft DirectX SDK*" - ) - - if(OGRE_BUILD_PLATFORM_WINRT) - # Windows 8 SDK has custom layout - set(DirectX11_INC_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Include/shared" - "C:/Program Files (x86)/Windows Kits/8.0/Include/um" - ) - set(DirectX11_LIB_SEARCH_PATH - "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um" - ) - endif() - - create_search_paths(DirectX11) - # redo search if prefix path changed - clear_if_changed(DirectX11_PREFIX_PATH - DirectX11_LIBRARY - DirectX11_INCLUDE_DIR - ) - - # dlls are in DirectX11_ROOT_DIR/Developer Runtime/x64|x86 - # lib files are in DirectX11_ROOT_DIR/Lib/x64|x86 - if(CMAKE_CL_64) - set(DirectX11_LIBPATH_SUFFIX "x64") - else(CMAKE_CL_64) - set(DirectX11_LIBPATH_SUFFIX "x86") - endif(CMAKE_CL_64) - - # look for D3D11 components - find_path(DirectX11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX11_INC_SEARCH_PATH}) - find_library(DirectX11_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - - find_library(DirectX11_LIBRARY NAMES d3d11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - find_library(DirectX11_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) - if (DirectX11_INCLUDE_DIR AND DirectX11_LIBRARY) - set(DirectX11_D3D11_FOUND TRUE) - set(DirectX11_INCLUDE_DIR ${DirectX11_INCLUDE_DIR}) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} - ${DirectX11_LIBRARY} - ${DirectX11_DXGI_LIBRARY} - ${DirectX11_DXGUID_LIBRARY} - ${DirectX11_D3DCOMPILER_LIBRARY} - ) - endif () - if (DirectX11_D3DX11_LIBRARY) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_D3DX11_LIBRARY}) - endif () - if (DirectX11_DXERR_LIBRARY) - set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_DXERR_LIBRARY}) - endif () - - findpkg_finish(DirectX11) - - set(DirectX11_LIBRARIES - ${DirectX11_D3D11_LIBRARIES} - ) - - if (OGRE_BUILD_PLATFORM_WINDOWS_PHONE) - set(DirectX11_FOUND TRUE) - set(DirectX11_INCLUDE_DIR "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/include" CACHE STRING "" FORCE) - set(DirectX11_LIBRARY "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/lib" CACHE STRING "" FORCE) - set(DirectX11_LIBRARIES ${DirectX11_LIBRARY}) - set(CMAKE_CXX_FLAGS "/EHsc" CACHE STRING "" FORCE) - endif () - - mark_as_advanced(DirectX11_INCLUDE_DIR - DirectX11_D3D11_LIBRARIES - DirectX11_D3DX11_LIBRARY - DirectX11_DXERR_LIBRARY - DirectX11_DXGUID_LIBRARY - DirectX11_DXGI_LIBRARY - DirectX11_D3DCOMPILER_LIBRARY) -endif(WIN32) \ No newline at end of file diff --git a/cmake/FindFreeImage.cmake b/cmake/FindFreeImage.cmake deleted file mode 100644 index 3b21a17d64..0000000000 --- a/cmake/FindFreeImage.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find FreeImage -# Once done, this will define -# -# FreeImage_FOUND - system has FreeImage -# FreeImage_INCLUDE_DIRS - the FreeImage include directories -# FreeImage_LIBRARIES - link these to use FreeImage - -include(FindPkgMacros) -findpkg_begin(FreeImage) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(FREEIMAGE_HOME) - -# construct search paths -set(FreeImage_PREFIX_PATH ${FREEIMAGE_HOME} ${ENV_FREEIMAGE_HOME}) -create_search_paths(FreeImage) -# redo search if prefix path changed -clear_if_changed(FreeImage_PREFIX_PATH - FreeImage_LIBRARY_FWK - FreeImage_LIBRARY_REL - FreeImage_LIBRARY_DBG - FreeImage_INCLUDE_DIR -) - -set(FreeImage_LIBRARY_NAMES freeimage) -get_debug_names(FreeImage_LIBRARY_NAMES) - -use_pkgconfig(FreeImage_PKGC freeimage) - -findpkg_framework(FreeImage) - -find_path(FreeImage_INCLUDE_DIR NAMES FreeImage.h HINTS ${FreeImage_INC_SEARCH_PATH} ${FreeImage_PKGC_INCLUDE_DIRS}) -find_library(FreeImage_LIBRARY_REL NAMES ${FreeImage_LIBRARY_NAMES} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(FreeImage_LIBRARY_DBG NAMES ${FreeImage_LIBRARY_NAMES_DBG} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(FreeImage_LIBRARY) - -findpkg_finish(FreeImage) - diff --git a/cmake/FindZZip.cmake b/cmake/FindZZip.cmake deleted file mode 100644 index 68fe043f36..0000000000 --- a/cmake/FindZZip.cmake +++ /dev/null @@ -1,48 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find zziplib -# Once done, this will define -# -# ZZip_FOUND - system has ZZip -# ZZip_INCLUDE_DIRS - the ZZip include directories -# ZZip_LIBRARIES - link these to use ZZip - -include(FindPkgMacros) -findpkg_begin(ZZip) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(ZZIP_HOME) - - -# construct search paths -set(ZZip_PREFIX_PATH ${ZZIP_HOME} ${ENV_ZZIP_HOME}) -create_search_paths(ZZip) -# redo search if prefix path changed -clear_if_changed(ZZip_PREFIX_PATH - ZZip_LIBRARY_FWK - ZZip_LIBRARY_REL - ZZip_LIBRARY_DBG - ZZip_INCLUDE_DIR -) - -set(ZZip_LIBRARY_NAMES zzip zziplib) -get_debug_names(ZZip_LIBRARY_NAMES) - -use_pkgconfig(ZZip_PKGC zziplib) - -findpkg_framework(ZZip) - -find_path(ZZip_INCLUDE_DIR NAMES zzip/zzip.h HINTS ${ZZip_INC_SEARCH_PATH} ${ZZip_PKGC_INCLUDE_DIRS}) -find_library(ZZip_LIBRARY_REL NAMES ${ZZip_LIBRARY_NAMES} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(ZZip_LIBRARY_DBG NAMES ${ZZip_LIBRARY_NAMES_DBG} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(ZZip_LIBRARY) - -findpkg_finish(ZZip) - From e04611948789a99e7da6f44740049218fe1686a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:15:26 +0200 Subject: [PATCH 0396/1812] Fix for unnecessary terrain texture coordinate arrays --- components/terrain/terraingrid.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 7ae4d85116..322c15196d 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -162,7 +162,8 @@ void TerrainGrid::loadCell(int x, int y) textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); } - for (unsigned int i=0; isetTexCoordArray(i, mCache.getUVBuffer()); osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); From ce0d93caed5d2c49e30e3b57fc037e210e5fe91d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:32:21 +0200 Subject: [PATCH 0397/1812] Fix for "GlobalMap trying to erase an inactive camera" spam in main menu --- apps/openmw/mwrender/globalmap.cpp | 18 ++++++++++++++++-- apps/openmw/mwrender/localmap.cpp | 14 ++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index bcf9e74bf8..9109be799a 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -63,17 +63,31 @@ namespace { public: CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) - : mCamera(cam), mParent(parent) + : mRendered(false) + , mCamera(cam) + , mParent(parent) { } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - mParent->markForRemoval(mCamera); + if (mRendered) + { + mCamera->setNodeMask(0); + return; + } + traverse(node, nv); + + if (!mRendered) + { + mRendered = true; + mParent->markForRemoval(mCamera); + } } private: + bool mRendered; osg::ref_ptr mCamera; MWRender::GlobalMap* mParent; }; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 77138a124b..6ce54a4baa 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,13 +30,22 @@ namespace { public: CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) - : mCamera(cam), mParent(parent) + : mRendered(false) + , mCamera(cam) + , mParent(parent) { } virtual void operator()(osg::Node*, osg::NodeVisitor*) { - mParent->markForRemoval(mCamera); + if (mRendered) + mCamera->setNodeMask(0); + + if (!mRendered) + { + mRendered = true; + mParent->markForRemoval(mCamera); + } // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, // so it has been updated already. @@ -44,6 +53,7 @@ namespace } private: + bool mRendered; osg::ref_ptr mCamera; MWRender::LocalMap* mParent; }; From 30053140a108dd31204efeddbc8401f12a26c238 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 16:55:14 +0200 Subject: [PATCH 0398/1812] Add cmake-data workaround to travis script --- .travis.yml | 12 ++++++------ CI/before_install.linux.sh | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b5155137d..d2b2ad0799 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,9 +49,9 @@ notifications: email: on_success: change on_failure: always - irc: - channels: - - "chat.freenode.net#openmw" - on_success: change - on_failure: always - use_notice: true + #irc: + # channels: + # - "chat.freenode.net#openmw" + # on_success: change + # on_failure: always + # use_notice: true diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 5823825ae4..2408a58221 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -15,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build From 231b217664993843c7ae8df82d6abb394b6addc7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 17:13:42 +0200 Subject: [PATCH 0399/1812] Build fix for MyGUI 3.2.1 --- components/fontloader/fontloader.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 1313366834..b66fbbb204 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -274,8 +274,6 @@ namespace Gui else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) resourceName = "Daedric"; - std::string textureName = name; - if (exportToFile) { osg::ref_ptr image = new osg::Image; @@ -298,8 +296,6 @@ namespace Gui memcpy(texData, &textureData[0], textureData.size()); tex->unlock(); - font->setSource(bitmapFilename); - // Using ResourceManualFont::setTexture, enable for MyGUI 3.2.3 /* osg::ref_ptr texture = new osg::Texture2D; @@ -319,7 +315,7 @@ namespace Gui defaultHeight->addAttribute("value", fontSize); MyGUI::xml::ElementPtr source = root->createChild("Property"); source->addAttribute("key", "Source"); - source->addAttribute("value", std::string(textureName)); + source->addAttribute("value", std::string(bitmapFilename)); MyGUI::xml::ElementPtr codes = root->createChild("Codes"); for(int i = 0; i < 256; i++) From 869f8a329aac928db30ba14f677cb2a2b86d9943 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:08:44 +0200 Subject: [PATCH 0400/1812] Cloud scrolling fix --- apps/openmw/mwrender/sky.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5b01edb164..c742d1c902 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -119,7 +119,10 @@ private: class CloudUpdater : public SceneUtil::StateSetUpdater { public: - void setAnimationTimer(float timer); + void setAnimationTimer(float timer) + { + mAnimationTimer = timer; + } void setTexture(osg::ref_ptr texture) { @@ -143,9 +146,8 @@ protected: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { - mAnimationTimer = nv->getFrameStamp()->getSimulationTime()*0.05; osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); - texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(mAnimationTimer, mAnimationTimer, 0.f))); + texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(0, mAnimationTimer, 0.f))); stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -604,7 +606,8 @@ void SkyManager::update(float duration) updateRain(duration); // UV Scroll the clouds - mCloudAnimationTimer += duration * mCloudSpeed; + mCloudAnimationTimer += duration * mCloudSpeed * 0.003; + mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); From 93656aa6cfa5dd73e4025ffe56083c21e9ce1da8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:10:07 +0200 Subject: [PATCH 0401/1812] Add a header missing from CMakeLists --- apps/openmw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8e17f2f31d..19889ad13e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects + character actors objects aistate ) add_openmw_dir (mwstate From 78ac37b52a1cb54cb24091f16c6bfd533ae736e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:11:40 +0200 Subject: [PATCH 0402/1812] Remove BOOST_STATIC_ASSERT to fix clang warnings --- apps/openmw/mwmechanics/aistate.hpp | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index 581f45d078..19f0ecf994 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -4,15 +4,11 @@ #include #include -// c++11 replacement -#include -#include - namespace MWMechanics { /** \brief stores one object of any class derived from Base. - * Requesting a certain dereived class via get() either returns + * Requesting a certain derived class via get() either returns * the stored object if it has the correct type or otherwise replaces * it with an object of the requested type. */ @@ -22,17 +18,6 @@ namespace MWMechanics private: Base* mStorage; - // assert that Derived is derived from Base. - template< class Derived > - void assert_derived() - { - // c++11: - // static_assert( std::is_base_of , "DerivedClassStorage may only store derived classes" ); - - // boost: - BOOST_STATIC_ASSERT((boost::is_base_of::value));//,"DerivedClassStorage may only store derived classes"); - } - //if needed you have to provide a clone member function DerivedClassStorage( const DerivedClassStorage& other ); DerivedClassStorage& operator=( const DerivedClassStorage& ); @@ -42,8 +27,6 @@ namespace MWMechanics template< class Derived > Derived& get() { - assert_derived(); - Derived* result = dynamic_cast(mStorage); if(!result) @@ -60,7 +43,6 @@ namespace MWMechanics template< class Derived > void store( const Derived& payload ) { - assert_derived(); if(mStorage) delete mStorage; mStorage = new Derived(payload); @@ -70,7 +52,6 @@ namespace MWMechanics template< class Derived > void moveIn( Derived* p ) { - assert_derived(); if(mStorage) delete mStorage; mStorage = p; @@ -87,12 +68,12 @@ namespace MWMechanics } - DerivedClassStorage():mStorage(NULL){}; + DerivedClassStorage():mStorage(NULL){} ~DerivedClassStorage() { if(mStorage) delete mStorage; - }; + } @@ -108,7 +89,7 @@ namespace MWMechanics * */ struct AiTemporaryBase { - virtual ~AiTemporaryBase(){}; + virtual ~AiTemporaryBase(){} }; /// \brief Container for AI package status. From 141e9d36a45719e35078d3ed29d6cb8253c48686 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:12:39 +0200 Subject: [PATCH 0403/1812] Get rid of unused DialogueManager::mScriptVerbose --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 -- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1785575fcf..139862a5a2 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -55,8 +55,6 @@ namespace MWDialogue , mTalkedTo(false) , mTemporaryDispositionChange(0.f) , mPermanentDispositionChange(0.f) - , mScriptVerbose (scriptVerbose) - { mChoice = -1; mIsInChoice = false; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index aec503e87d..086b5ef2f7 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -45,7 +45,6 @@ namespace MWDialogue float mTemporaryDispositionChange; float mPermanentDispositionChange; - bool mScriptVerbose; void parseText (const std::string& text); From e23775e33842f60a4d15b89af6ac8025a54a796f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:31:28 +0200 Subject: [PATCH 0404/1812] Fix -Woverloaded-virtual clang warnings --- apps/openmw/mwgui/bookwindow.cpp | 2 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 4 ++-- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 2 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.cpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/itemview.cpp | 6 +++--- apps/openmw/mwgui/itemview.hpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/scrollwindow.cpp | 2 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 4 ++-- apps/openmw/mwgui/spellview.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++---- components/widgets/list.cpp | 4 ++-- components/widgets/list.hpp | 2 +- 26 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 6863994b8a..44a9885232 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -73,7 +73,7 @@ namespace MWGui mPages.clear(); } - void BookWindow::open (MWWorld::Ptr book, bool showTakeButton) + void BookWindow::openBook (MWWorld::Ptr book, bool showTakeButton) { mBook = book; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 8ad4f68300..881b9997ce 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void exit(); - void open(MWWorld::Ptr book, bool showTakeButton); + void openBook(MWWorld::Ptr book, bool showTakeButton); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 4433f9ef8c..4b3bab5d04 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -84,7 +84,7 @@ void CompanionWindow::onItemSelected(int index) if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(object.getClass().getName(object), "#{sTake}", count); + dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } @@ -106,7 +106,7 @@ void CompanionWindow::onBackgroundSelected() } } -void CompanionWindow::open(const MWWorld::Ptr& npc) +void CompanionWindow::openCompanion(const MWWorld::Ptr& npc) { mPtr = npc; updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index dc460e2fc2..d37f0c4e43 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -22,7 +22,7 @@ namespace MWGui virtual void resetReference(); - void open(const MWWorld::Ptr& npc); + void openCompanion(const MWWorld::Ptr& npc); void onFrame (); private: diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 83650b1951..e4312914f8 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -16,7 +16,7 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); } - void ConfirmationDialog::open(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) + void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) { setVisible(true); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 7ff16b10ad..14caa77482 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui { public: ConfirmationDialog(); - void open(const std::string& message, const std::string& confirmMessage="#{sOk}", const std::string& cancelMessage="#{sCancel}"); + void askForConfirmation(const std::string& message, const std::string& confirmMessage="#{sOk}", const std::string& cancelMessage="#{sCancel}"); virtual void exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1317e1e253..ecf4ddcf00 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -83,7 +83,7 @@ namespace MWGui if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(object.getClass().getName(object), "#{sTake}", count); + dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } @@ -131,7 +131,7 @@ namespace MWGui dropItem(); } - void ContainerWindow::open(const MWWorld::Ptr& container, bool loot) + void ContainerWindow::openContainer(const MWWorld::Ptr& container, bool loot) { mPickpocketDetected = false; mPtr = container; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 87ae993a54..520bce9d9d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,7 +33,7 @@ namespace MWGui public: ContainerWindow(DragAndDrop* dragAndDrop); - void open(const MWWorld::Ptr& container, bool loot=false); + void openContainer(const MWWorld::Ptr& container, bool loot=false); virtual void close(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index c6f2180c92..03cf1cab65 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -29,7 +29,7 @@ namespace MWGui mItemEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &CountDialog::onEnterKeyPressed); } - void CountDialog::open(const std::string& item, const std::string& message, const int maxCount) + void CountDialog::openCountDialog(const std::string& item, const std::string& message, const int maxCount) { setVisible(true); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index a54e99cf4b..7014b5fad9 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -14,7 +14,7 @@ namespace MWGui { public: CountDialog(); - void open(const std::string& item, const std::string& message, const int maxCount); + void openCountDialog(const std::string& item, const std::string& message, const int maxCount); void cancel(); virtual void exit(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b96e79ca92..e3d87de605 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -237,7 +237,7 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}"; - dialog->open(object.getClass().getName(object), message, count); + dialog->openCountDialog(object.getClass().getName(object), message, count); dialog->eventOkClicked.clear(); if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index aade232d27..7391bb8fbd 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -103,7 +103,7 @@ void ItemView::update() MyGUI::Align::Stretch); dragArea->setNeedMouseFocus(true); dragArea->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedBackground); - dragArea->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); + dragArea->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheelMoved); for (ItemModel::ModelIndex i=0; i(mModel->getItemCount()); ++i) { @@ -122,7 +122,7 @@ void ItemView::update() itemWidget->setCount(item.mCount); itemWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedItem); - itemWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); + itemWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheelMoved); } layoutWidgets(); @@ -139,7 +139,7 @@ void ItemView::onSelectedBackground(MyGUI::Widget *sender) eventBackgroundClicked(); } -void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel) +void ItemView::onMouseWheelMoved(MyGUI::Widget *_sender, int _rel) { if (mScrollView->getViewOffset().left + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 9aeba67520..6c2dea3390 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -40,7 +40,7 @@ namespace MWGui void onSelectedItem (MyGUI::Widget* sender); void onSelectedBackground (MyGUI::Widget* sender); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); ItemModel* mModel; MyGUI::ScrollView* mScrollView; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index dbc5130491..e24894e89f 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -112,7 +112,7 @@ namespace MWGui else { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage2}"); + dialog->askForConfirmation("#{sMessage2}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onExitConfirmed); dialog->eventCancelClicked.clear(); @@ -125,7 +125,7 @@ namespace MWGui else { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage54}"); + dialog->askForConfirmation("#{sNotifyMessage54}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onNewGameConfirmed); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 34a9db1e1b..3e855c4d03 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -650,7 +650,7 @@ namespace MWGui void MapWindow::onNoteEditDelete() { ConfirmationDialog* confirmation = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - confirmation->open("#{sDeleteNote}", "#{sYes}", "#{sNo}"); + confirmation->askForConfirmation("#{sDeleteNote}", "#{sYes}", "#{sNo}"); confirmation->eventCancelClicked.clear(); confirmation->eventOkClicked.clear(); confirmation->eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditDeleteConfirm); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ab8d93a876..d490d49cdb 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -73,7 +73,7 @@ namespace MWGui void SaveGameDialog::confirmDeleteSave() { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage3}"); + dialog->askForConfirmation("#{sMessage3}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); dialog->eventCancelClicked.clear(); @@ -232,7 +232,7 @@ namespace MWGui if (mCurrentSlot != NULL && !reallySure) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage4}"); + dialog->askForConfirmation("#{sMessage4}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 85d1c8c4ee..01ce7767e3 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui center(); } - void ScrollWindow::open (MWWorld::Ptr scroll, bool showTakeButton) + void ScrollWindow::openScroll (MWWorld::Ptr scroll, bool showTakeButton) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 3c9e718b61..961f1b675f 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,7 +17,7 @@ namespace MWGui public: ScrollWindow (); - void open (MWWorld::Ptr scroll, bool showTakeButton); + void openScroll (MWWorld::Ptr scroll, bool showTakeButton); virtual void exit(); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index a50c305070..af081391c3 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -271,7 +271,7 @@ namespace MWGui return; ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage67}"); + dialog->askForConfirmation("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); dialog->eventCancelClicked.clear(); @@ -540,7 +540,7 @@ namespace MWGui void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sNotifyMessage66}"); + dialog->askForConfirmation("#{sNotifyMessage66}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindingsAccept); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 6d86b4a23a..cb7bfc4a60 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -289,7 +289,7 @@ namespace MWGui widget->setUserString(sSpellModelIndex, MyGUI::utility::toString(index)); - widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel); + widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheelMoved); widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected); } @@ -303,7 +303,7 @@ namespace MWGui eventSpellClicked(getSpellModelIndex(_sender)); } - void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) + void SpellView::onMouseWheelMoved(MyGUI::Widget* _sender, int _rel) { if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 7af1bda7a7..d40277282f 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -84,7 +84,7 @@ namespace MWGui void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); void onSpellSelected(MyGUI::Widget* _sender); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); SpellModel::ModelIndex getSpellModelIndex(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index ca5ec20bdf..d2ea67ea96 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -134,7 +134,7 @@ namespace MWGui ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); + dialog->askForConfirmation(question); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); dialog->eventCancelClicked.clear(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e6a2555b6c..581533060b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -194,7 +194,7 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = "#{sQuanityMenuMessage02}"; - dialog->open(object.getClass().getName(object), message, count); + dialog->openCountDialog(object.getClass().getName(object), message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::sellItem); mItemToSell = mSortModel->mapToSource(index); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1ae5cabed0..298d4812e3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1524,7 +1524,7 @@ namespace MWGui void WindowManager::showCompanionWindow(MWWorld::Ptr actor) { pushGuiMode(MWGui::GM_Companion); - mCompanionWindow->open(actor); + mCompanionWindow->openCompanion(actor); } void WindowManager::changePointer(const std::string &name) @@ -1927,19 +1927,19 @@ namespace MWGui void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) { pushGuiMode(GM_Container); - mContainerWindow->open(container, loot); + mContainerWindow->openContainer(container, loot); } void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) { pushGuiMode(GM_Book); - mBookWindow->open(item, showTakeButton); + mBookWindow->openBook(item, showTakeButton); } void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) { pushGuiMode(GM_Scroll); - mScrollWindow->open(item, showTakeButton); + mScrollWindow->openScroll(item, showTakeButton); } std::string WindowManager::correctIconPath(const std::string& path) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index df7e7d61d2..c5a459f22b 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -70,7 +70,7 @@ namespace Gui button->setCaption((*it)); button->getSubWidgetText()->setWordWrap(true); button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); int height = button->getTextSize().height; @@ -135,7 +135,7 @@ namespace Gui mItems.clear(); } - void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) + void MWList::onMouseWheelMoved(MyGUI::Widget* _sender, int _rel) { //NB view offset is negative if (mScrollView->getViewOffset().top + _rel*0.3f > 0) diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index aed69da792..cc7b75c2ff 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -55,7 +55,7 @@ namespace Gui void redraw(bool scrollbarShown = false); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); void onItemSelected(MyGUI::Widget* _sender); private: From 30ab15e6054179efd09dad1c06b46eed26addb43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:33:20 +0200 Subject: [PATCH 0405/1812] Fix -Wunused-private-field clang warnings --- apps/openmw/mwgui/inventorywindow.cpp | 2 -- apps/openmw/mwgui/inventorywindow.hpp | 3 --- apps/openmw/mwgui/messagebox.cpp | 1 - apps/openmw/mwgui/messagebox.hpp | 1 - apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 4 ---- apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwrender/npcanimation.hpp | 2 -- 8 files changed, 1 insertion(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e3d87de605..3ecfc64b2b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -61,8 +61,6 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) - , mResourceSystem(resourceSystem) - , mViewer(viewer) , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mTrading(false) { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fc579ae628..a8a1b15a13 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -99,9 +99,6 @@ namespace MWGui int mLastXSize; int mLastYSize; - Resource::ResourceSystem* mResourceSystem; - osgViewer::Viewer* mViewer; - std::auto_ptr mPreviewTexture; std::auto_ptr mPreview; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6e81ed6262..c647ecaf52 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -195,7 +195,6 @@ namespace MWGui InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) - , mTextButtonPadding(0) , mButtonPressed(-1) { WindowModal::open(); diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 59d1a0b064..b4121fed3b 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -88,7 +88,6 @@ namespace MWGui MyGUI::Widget* mButtonsWidget; std::vector mButtons; - int mTextButtonPadding; int mButtonPressed; }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 34a397f9a6..80877e08b0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -240,7 +240,7 @@ namespace MWRender , mTextKeyListener(NULL) { for(size_t i = 0;i < sNumGroups;i++) - mAnimationTimePtr[i].reset(new AnimationTime(this)); + mAnimationTimePtr[i].reset(new AnimationTime); } Animation::~Animation() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index bd864c9361..419ae6bc01 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,13 +95,9 @@ protected: class AnimationTime : public SceneUtil::ControllerSource { private: - Animation *mAnimation; boost::shared_ptr mTimePtr; public: - AnimationTime(Animation *anim) - : mAnimation(anim) - { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 71c48a4897..6831daa4b0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -242,7 +242,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mVisibilityFlags(visibilityFlags), mAlpha(1.f), mSoundsDisabled(disableSounds), mHeadYawRadians(0.f), diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 23b663565a..3eb4c4754b 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,8 +90,6 @@ private: }; NpcType mNpcType; - int mVisibilityFlags; - int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; From 958b34771a7f08c89b7fa04e84e3d02803844519 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:34:49 +0200 Subject: [PATCH 0406/1812] Fix clang warnings about 'typename' outside of a template --- apps/opencs/model/world/nestedcoladapterimp.cpp | 4 ++-- apps/opencs/model/world/refidadapterimp.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index b7d09777d4..dc5cd22993 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -906,7 +906,7 @@ namespace CSMWorld NestedTableWrapperBase* RaceAttributeAdapter::table(const Record& record) const { - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mData); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); @@ -983,7 +983,7 @@ namespace CSMWorld NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record& record) const { - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mData); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d31a9ceaae..2daca16f79 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -576,7 +576,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col // store the whole struct npc.mNpdt52 = - static_cast > &>(nestedTable).mNestedTable.at(0); + static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); } @@ -588,10 +588,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); // return the whole struct - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mNpdt52); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(wrap); + return new NestedTableWrapper >(wrap); } QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, @@ -694,7 +694,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, // store the whole struct npc.mNpdt52 = - static_cast > &>(nestedTable).mNestedTable.at(0); + static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); } @@ -706,10 +706,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable ( static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); // return the whole struct - std::vector wrap; + std::vector wrap; wrap.push_back(record.get().mNpdt52); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(wrap); + return new NestedTableWrapper >(wrap); } QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column, From e6ecb39d94d93ec3b1945f3fdc7a94a866d9da3c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 20:36:07 +0200 Subject: [PATCH 0407/1812] Potential include fix --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 5 ----- extern/osg-ffmpeg-videoplayer/videostate.hpp | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index 8a9cce1b77..f143088e81 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -2,11 +2,6 @@ #include -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif -#include - #include extern "C" diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 72a2aab186..247e04ec47 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,6 +1,9 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif #include #include From a0b0ae9bd1f65ddd548313decebe196f9a0d8957 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Jun 2015 21:51:24 +0200 Subject: [PATCH 0408/1812] Remove an unused variable --- apps/openmw/mwmechanics/aicombat.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f31e0ff77f..9d92423e9a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -79,9 +79,6 @@ namespace namespace MWMechanics { - static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander - // NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp - /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase From d8d43f94b94d023c441ac84ad2e0d77924bef9da Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:06:13 +0200 Subject: [PATCH 0409/1812] Fix a typo --- components/nifosg/nifloader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index bf1dbe6b58..54f067e984 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -59,7 +59,7 @@ namespace NifOsg static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. - /// These should be hidden ingame, but visible in the editior. + /// These should be hidden ingame, but visible in the editor. /// Default: false. static void setShowMarkers(bool show); From ddfed35d1ce26ea6b553cf57221b4cab2dc53ba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:26:16 +0200 Subject: [PATCH 0410/1812] Object placement raycasts should use the rendering meshes --- apps/openmw/mwrender/renderingmanager.cpp | 96 ++++++++++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 15 +++- apps/openmw/mwworld/worldimp.cpp | 36 +++------ 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7af21a5a6e..d1811ed67d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -438,21 +438,6 @@ namespace MWRender mViewer->getCamera()->setCullMask(oldCullMask); } - void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) - { - osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); - osg::Matrix invViewProj = viewProj.inverse(viewProj); - - nX = nX * 2 - 1; - nY = nY * -2 + 1; - - osg::Vec3f start (nX, nY, -1.f); - osg::Vec3f end (nX, nY, 1.f); - - origin = invViewProj.preMult(start); - dest = invViewProj.preMult(end); - } - osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) { if (!ptr.getRefData().getBaseNode()) @@ -487,7 +472,61 @@ namespace MWRender return osg::Vec4f(min_x, min_y, max_x, max_y); } - MWWorld::Ptr RenderingManager::getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer) + RenderingManager::RayResult getIntersectionResult (osgUtil::LineSegmentIntersector* intersector) + { + RenderingManager::RayResult result; + result.mHit = false; + if (intersector->containsIntersections()) + { + result.mHit = true; + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + + result.mHitPointWorld = intersection.getWorldIntersectPoint(); + result.mHitNormalWorld = intersection.getWorldIntersectNormal(); + + PtrHolder* ptrHolder = NULL; + for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); + if (!userDataContainer) + continue; + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + ptrHolder = p; + } + } + + if (ptrHolder) + result.mHitObject = ptrHolder->mPtr; + } + + return result; + + } + + RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, + origin, dest)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); + + osgUtil::IntersectionVisitor intersectionVisitor(intersector); + int mask = intersectionVisitor.getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); + if (ignorePlayer) + mask &= ~(Mask_Player); + if (ignoreActors) + mask &= ~(Mask_Actor|Mask_Player); + + intersectionVisitor.setTraversalMask(mask); + + mRootNode->accept(intersectionVisitor); + + return getIntersectionResult(intersector); + } + + RenderingManager::RayResult RenderingManager::castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, nX * 2.f - 1.f, nY * (-2.f) + 1.f)); @@ -506,33 +545,14 @@ namespace MWRender mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); if (ignorePlayer) mask &= ~(Mask_Player); + if (ignoreActors) + mask &= ~(Mask_Actor|Mask_Player); intersectionVisitor.setTraversalMask(mask); mViewer->getCamera()->accept(intersectionVisitor); - if (intersector->containsIntersections()) - { - osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); - - PtrHolder* ptrHolder = NULL; - for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) - { - osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); - if (!userDataContainer) - continue; - for (unsigned int i=0; igetNumUserObjects(); ++i) - { - if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) - ptrHolder = p; - } - } - - if (ptrHolder) - return ptrHolder->mPtr; - } - - return MWWorld::Ptr(); + return getIntersectionResult(intersector); } void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4452ae9f85..8ed590df49 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,16 +85,23 @@ namespace MWRender /// Take a screenshot of w*h onto the given image, not including the GUI. void screenshot(osg::Image* image, int w, int h); + struct RayResult + { + bool mHit; + osg::Vec3f mHitNormalWorld; + osg::Vec3f mHitPointWorld; + MWWorld::Ptr mHitObject; + }; + + RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. - MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); + RayResult castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors=false); /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being the top left corner. osg::Vec4f getScreenBounds(const MWWorld::Ptr& ptr); - /// Get a camera to viewport ray for normalized screen coordinates nX and nY, with the top left corner being at (0,0) - void getCameraToViewportRay(float nX, float nY, osg::Vec3f& origin, osg::Vec3f& dest); - void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9a42d45874..9179f94f69 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1662,11 +1662,11 @@ namespace MWWorld { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - return mRendering->getFacedObject(x, y, maxDistance, ignorePlayer); + return mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer).mHitObject; } else { - return mRendering->getFacedObject(0.5f, 0.5f, maxDistance, ignorePlayer); + return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject; } } @@ -1790,25 +1790,18 @@ namespace MWWorld MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { - osg::Vec3f origin, dest; - mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - const float maxDist = 200.f; - osg::Vec3f dir = (dest - origin); - dir.normalize(); - dest = origin + dir * maxDist; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); CellStore* cell = getPlayerPtr().getCell(); ESM::Position pos = getPlayerPtr().getRefData().getPosition(); if (result.mHit) { - pos.pos[0] = result.mHitPos.x(); - pos.pos[1] = result.mHitPos.y(); - pos.pos[2] = result.mHitPos.z(); + pos.pos[0] = result.mHitPointWorld.x(); + pos.pos[1] = result.mHitPointWorld.y(); + pos.pos[2] = result.mHitPointWorld.z(); } // We want only the Z part of the player's rotation pos.rot[0] = 0; @@ -1828,21 +1821,13 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - osg::Vec3f origin, dest; - mRendering->getCameraToViewportRay(cursorX, cursorY, origin, dest); - const float maxDist = 200.f; - osg::Vec3f dir = (dest - origin); - dir.normalize(); - dest = origin + dir * maxDist; - - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (std::acos(result.mHitNormal * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) + if (std::acos(result.mHitNormalWorld * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; return true; @@ -1925,10 +1910,9 @@ namespace MWWorld float len = 100.0; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(orig, orig+dir*len, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) - pos.pos[2] = result.mHitPos.z(); + pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count int origCount = object.getRefData().getCount(); From 89fc473fae453a9d4eeb76d5eb1a9509931b0763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:35:13 +0200 Subject: [PATCH 0411/1812] Remove Render System combo box from the launcher UI --- files/ui/graphicspage.ui | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index f9ea63efe6..2d84d9f26e 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -6,30 +6,11 @@ 0 0 - 332 - 297 + 437 + 343 - - - - Render System - - - - - - Rendering Subsystem: - - - - - - - - - From 76328677eff4e5a3e66e21110be0183834327e86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:48:51 +0200 Subject: [PATCH 0412/1812] Add some values to launcher's antialiasing combobox --- files/ui/graphicspage.ui | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index 2d84d9f26e..0afda6ac7a 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -63,7 +63,33 @@ - + + + + 0 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + From 403ce30a352e468de4a8d685ea3ce0f3ab4a4663 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:53:10 +0200 Subject: [PATCH 0413/1812] Graceful handling for failing to create SDL window --- apps/openmw/engine.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a37d84621e..f23e414ab8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -350,11 +350,28 @@ void OMW::Engine::createWindow(Settings::Manager& settings) std::cerr << "SDL error: " << SDL_GetError() << std::endl; } - mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); - if (mWindow == NULL) + while (!mWindow) { - std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; - return; + mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + if (!mWindow) + { + // Try with a lower AA + if (antialiasing > 0) + { + std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl; + antialiasing /= 2; + Settings::Manager::setInt("antialiasing", "Video", antialiasing); + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + continue; + } + else + { + std::stringstream error; + error << "Failed to create SDL window: " << SDL_GetError() << std::endl; + throw std::runtime_error(error.str()); + } + } } setWindowIcon(); From 700000cbca818fd170fb1f28abe8e37b5cfc9737 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 02:57:31 +0200 Subject: [PATCH 0414/1812] Error handling fix --- apps/openmw/engine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f23e414ab8..eda33637b7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -411,6 +411,11 @@ void OMW::Engine::setWindowIcon() if (windowIconStream.fail()) std::cerr << "Failed to open " << windowIcon << std::endl; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!reader) + { + std::cerr << "Failed to read window icon, no png readerwriter found" << std::endl; + return; + } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; From 1fd48e6f819da2c2f15bdf5cb27dca5a85e39365 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 03:35:59 +0200 Subject: [PATCH 0415/1812] Fix not being able to move during ashstorm --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f97c5fd138..c7df22aef6 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -288,7 +288,7 @@ namespace MWPhysics if (MWBase::Environment::get().getWorld()->isInStorm()) { osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity)); + float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fStromWalkMult")->getFloat(); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); From 4c09ecef72f90515d17b51881f377f88efd5d1f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 03:41:10 +0200 Subject: [PATCH 0416/1812] Normalize fixes --- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d4ba561edb..ea6b394816 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -855,7 +855,8 @@ void CharacterController::updateIdleStormState() { osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); osg::Vec3f characterDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0); - inStormDirection = std::acos(stormDirection * characterDirection) > osg::DegreesToRadians(120.f); + inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length())) + > osg::DegreesToRadians(120.f); } if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b89b8c94a2..7bc6a34ae8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1388,7 +1388,9 @@ namespace MWMechanics osg::Vec3f vec = pos1 - pos2; if (observer.getRefData().getBaseNode()) { - float angleRadians = std::acos((observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)) * vec); + osg::Vec3f observerDir = (observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)); + + float angleRadians = std::acos(observerDir * vec / (observerDir.length() * vec.length())); if (angleRadians < osg::DegreesToRadians(90.f)) y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult; else diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9179f94f69..a2e66a96fb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1827,7 +1827,7 @@ namespace MWWorld if (result.mHit) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - if (std::acos(result.mHitNormalWorld * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) + if (std::acos((result.mHitNormalWorld/result.mHitNormalWorld.length()) * osg::Vec3f(0,0,1)) >= osg::DegreesToRadians(30.f)) return false; return true; From 0afc03b6b74e4df7b348260ae13bcd9d292db06e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Jun 2015 16:56:38 +0200 Subject: [PATCH 0417/1812] Build fix --- components/esmterrain/storage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 0795a3ffc9..1811f58e60 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -28,8 +28,8 @@ namespace ESMTerrain osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x == (int) origin.x()); - assert(origin.y == (int) origin.y()); + assert(origin.x() == (int) origin.x()); + assert(origin.y() == (int) origin.y()); int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); From 68e322f969344f571a99a44b3ba99bf630363f46 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 01:47:19 +0200 Subject: [PATCH 0418/1812] Restore data directory verbose output that got lost --- components/vfs/registerarchives.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index aeda3191d1..b361e3f42f 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -35,6 +35,7 @@ namespace VFS if (useLooseFiles) for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { + std::cout << "Adding data directory " << iter->string() << std::endl; // Last data dir has the highest priority vfs->addArchive(new FileSystemArchive(iter->string())); } From 0a411cbd7cd55cacb5c8c2c1efcbf5dddf8f862e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 04:41:55 +0200 Subject: [PATCH 0419/1812] Enable particle lighting --- apps/openmw/mwrender/animation.cpp | 3 +++ components/nifosg/nifloader.cpp | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 80877e08b0..6af8a49a4b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1067,6 +1067,9 @@ namespace MWRender parentNode = found->second; } osg::ref_ptr node = mResourceSystem->getSceneManager()->createInstance(model, parentNode); + + node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + params.mObjects = PartHolderPtr(new PartHolder(node)); SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 1f089f0c40..530aa3decf 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,9 +6,6 @@ #include #include -#include -#include - // resource #include #include @@ -862,7 +859,15 @@ namespace NifOsg collectMaterialProperties(nifNode, materialProps); applyMaterialProperties(geode, materialProps, true, animflags); - partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + // Particles don't have normals, so can't be diffuse lit. + osg::Material* mat = static_cast(geode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,diffuse.a())); + mat->setColorMode(osg::Material::AMBIENT); + } + partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); // particle system updater (after the emitters and affectors in the scene graph) From b33fe8fb6242e6b0030340429ac122de883237b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 16:50:34 +0200 Subject: [PATCH 0420/1812] Fix the inventory listener bug --- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 5 +++++ apps/openmw/mwworld/inventorystore.hpp | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6831daa4b0..7de3e1d5a6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -231,7 +231,7 @@ NpcAnimation::~NpcAnimation() // No need to getInventoryStore() to reset, if none exists // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // all from within this destructor. ouch! - && mPtr.getRefData().getCustomData()) + && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 62d58f7298..3fe86a511a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -573,6 +573,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWor throw std::runtime_error ("attempt to unequip an item that is not currently equipped"); } +MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() +{ + return mListener; +} + void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) { mListener = listener; diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 6b906207e1..a60d1f464f 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -192,6 +192,8 @@ namespace MWWorld void setListener (InventoryStoreListener* listener, const Ptr& actor); ///< Set a listener for various events, see \a InventoryStoreListener + InventoryStoreListener* getListener(); + void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void rechargeItems (float duration); From 16e080e2529453fa6a42a5460639ca4a190f8bfb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 17:00:00 +0200 Subject: [PATCH 0421/1812] Fix the physics debug drawer lagging a frame behind --- apps/openmw/mwphysics/physicssystem.cpp | 3 +++ apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c7df22aef6..b7d02e1591 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1175,7 +1175,10 @@ namespace MWPhysics CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); + } + void PhysicsSystem::debugDraw() + { if (mDebugDrawer.get()) mDebugDrawer->step(); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 8cb31ed259..c3b22c3854 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -78,6 +78,7 @@ namespace MWPhysics bool toggleCollisionMode(); void stepSimulation(float dt); + void debugDraw(); std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2e66a96fb..7b4c33fd87 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1392,6 +1392,8 @@ namespace MWWorld } if(player != results.end()) moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z()); + + mPhysics->debugDraw(); } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) From 508c57d6e21f6b538579c2efa1858c701c920217 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 17:09:37 +0200 Subject: [PATCH 0422/1812] addEffect crash fix for objects with no model --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6af8a49a4b..d92e57f19f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1048,6 +1048,9 @@ namespace MWRender void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { + if (!mObjectRoot.get()) + return; + // Early out if we already have this effect for (std::vector::iterator it = mEffects.begin(); it != mEffects.end(); ++it) if (it->mLoop && loop && it->mEffectId == effectId && it->mBoneName == bonename) From ab626ca7b90fd8574fdff511e652825bfb21ca0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 18:57:26 +0200 Subject: [PATCH 0423/1812] Improve MyGUI widget creation performance --- .../myguiplatform/myguirendermanager.cpp | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e00b0221da..ece667eb22 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -209,10 +209,17 @@ class OSGVertexBuffer : public MyGUI::IVertexBuffer size_t mNeedVertexCount; + bool mQueuedForDrawing; + + void destroy(); + void create(); + public: OSGVertexBuffer(); virtual ~OSGVertexBuffer(); + void markAsQueuedForDrawing(); + virtual void setVertexCount(size_t count); virtual size_t getVertexCount(); @@ -220,8 +227,6 @@ public: virtual void unlock(); /*internal:*/ - void destroy(); - void create(); osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } osg::UByteArray *getArray() const { return mVertexArray.get(); } @@ -229,6 +234,7 @@ public: OSGVertexBuffer::OSGVertexBuffer() : mNeedVertexCount(0) + , mQueuedForDrawing(false) { } @@ -237,14 +243,17 @@ OSGVertexBuffer::~OSGVertexBuffer() destroy(); } +void OSGVertexBuffer::markAsQueuedForDrawing() +{ + mQueuedForDrawing = true; +} + void OSGVertexBuffer::setVertexCount(size_t count) { if(count == mNeedVertexCount) return; mNeedVertexCount = count; - destroy(); - create(); } size_t OSGVertexBuffer::getVertexCount() @@ -254,15 +263,22 @@ size_t OSGVertexBuffer::getVertexCount() MyGUI::Vertex *OSGVertexBuffer::lock() { - // Force recreating the buffer, to make sure we are not modifying a buffer currently - // queued for rendering in the last frame's draw thread. - // a more efficient solution might be double buffering - destroy(); - create(); + if (mQueuedForDrawing || !mVertexArray) + { + // Force recreating the buffer, to make sure we are not modifying a buffer currently + // queued for rendering in the last frame's draw thread. + // a more efficient solution might be double buffering + destroy(); + create(); + mQueuedForDrawing = false; + } + else + { + mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); + } MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); - mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); return (MyGUI::Vertex*)&(*mVertexArray)[0]; } @@ -389,6 +405,7 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text Drawable::Batch batch; batch.mVertexCount = count; batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + static_cast(buffer)->markAsQueuedForDrawing(); batch.mArray = static_cast(buffer)->getArray(); if (texture) { From bf02c7f6e4949e09adc19a7a8e043d4fa9f6e568 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 19:28:12 +0200 Subject: [PATCH 0424/1812] Sun visibility fix --- apps/openmw/mwrender/sky.cpp | 7 ------- apps/openmw/mwrender/sky.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c742d1c902..0cd1f64d2f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -506,8 +506,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) - , mMasserEnabled(true) - , mSecundaEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -642,11 +640,6 @@ void SkyManager::update(float duration) */ } - //mSunGlare->setVisible(mSunEnabled); - mSun->setVisible(mSunEnabled); - mMasser->setVisible(mMasserEnabled); - mSecunda->setVisible(mSecundaEnabled); - // rotate the stars by 360 degrees every 4 days //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 652de28b42..d7cd88de57 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -150,8 +150,6 @@ namespace MWRender bool mEnabled; bool mSunEnabled; - bool mMasserEnabled; - bool mSecundaEnabled; }; } From f3cbe7b9dac6cae14bf2f8593006e1fb8f838bf0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 19:33:48 +0200 Subject: [PATCH 0425/1812] Hide FPS widget since it currently doesn't work, use F3 instead --- apps/openmw/mwgui/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 56a4b08074..76a7248ee4 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -192,7 +192,7 @@ namespace MWGui if (visible) { getWidget(mFpsBox, "FPSBox"); - mFpsBox->setVisible(true); + //mFpsBox->setVisible(true); getWidget(mFpsCounter, "FPSCounter"); } } From 0330d3d61e911ea1b27ba72b14d4aaf41717dc02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 21:21:57 +0200 Subject: [PATCH 0426/1812] Restore the "transparent" loading screen --- apps/openmw/mwgui/loadingscreen.cpp | 69 ++++++++++++++++++++--------- apps/openmw/mwgui/loadingscreen.hpp | 11 +++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f6a9f5ccdd..774faa003f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include @@ -9,6 +11,8 @@ #include +#include + #include #include @@ -96,6 +100,28 @@ namespace MWGui mBackgroundImage->setVisible(visible); } + class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback + { + public: + CopyFramebufferToTextureCallback(osg::Texture2D* texture, int w, int h) + : mTexture(texture), mWidth(w), mHeight(h) + { + } + + virtual void operator () (osg::RenderInfo& renderInfo) const + { + mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, mWidth, mHeight); + + // Callback removes itself when done + if (renderInfo.getCurrentCamera()) + renderInfo.getCurrentCamera()->setInitialDrawCallback(NULL); + } + + private: + osg::ref_ptr mTexture; + int mWidth, mHeight; + }; + void LoadingScreen::loadingOn() { mLoadingOnTime = mTimer.time_m(); @@ -114,29 +140,30 @@ namespace MWGui if (!showWallpaper) { - // TODO - /* - mBackgroundImage->setImageTexture(""); - int width = mWindow->getWidth(); - int height = mWindow->getHeight(); - const std::string textureName = "@loading_background"; - Ogre::TexturePtr texture; - texture = Ogre::TextureManager::getSingleton().getByName(textureName); - if (texture.isNull()) + // Copy the current framebuffer onto a texture and display that texture as the background image + // Note, we could also set the camera to disable clearing and have the background image transparent, + // but then we get shaking effects on buffer swaps. + + if (!mTexture) { - texture = Ogre::TextureManager::getSingleton().createManual(textureName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - width, height, 0, mWindow->suggestPixelFormat(), Ogre::TU_DYNAMIC_WRITE_ONLY); + mTexture = new osg::Texture2D; + mTexture->setInternalFormat(GL_RGB); + mTexture->setResizeNonPowerOfTwoHint(false); } - texture->unload(); - texture->setWidth(width); - texture->setHeight(height); - texture->createInternalResources(); - mWindow->copyContentsToMemory(texture->getBuffer()->lock(Ogre::Image::Box(0,0,width,height), Ogre::HardwareBuffer::HBL_DISCARD)); - texture->getBuffer()->unlock(); - mBackgroundImage->setBackgroundImage(texture->getName(), false, false); - */ + + int width = mViewer->getCamera()->getViewport()->width(); + int height = mViewer->getCamera()->getViewport()->height(); + mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture, width, height)); + + if (!mGuiTexture.get()) + { + mGuiTexture.reset(new osgMyGUI::OSGTexture(mTexture)); + } + + mBackgroundImage->setBackgroundImage(""); + + mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); + mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } setVisible(true); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index baacc7133d..194535eeed 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -12,6 +12,12 @@ namespace osgViewer { class Viewer; } + +namespace osg +{ + class Texture2D; +} + namespace VFS { class Manager; @@ -67,6 +73,11 @@ namespace MWGui std::vector mSplashScreens; + // TODO: add releaseGLObjects() for mTexture + + osg::ref_ptr mTexture; + std::auto_ptr mGuiTexture; + void changeWallpaper(); void draw(); From 9c9b83f8e20d8b2bbdaa2ed004d21ad4b6438501 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Jun 2015 23:51:54 +0200 Subject: [PATCH 0427/1812] Changes to compile with osg-svn 3.3.8 --- components/sceneutil/controller.cpp | 12 ++++++++++++ components/sceneutil/statesetupdater.cpp | 1 + components/sdlutil/sdlgraphicswindow.cpp | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index b8b452dc3a..a2c1cdcd39 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include namespace SceneUtil { @@ -63,7 +65,11 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + osg::Callback* callback = node.getUpdateCallback(); +#else osg::NodeCallback* callback = node.getUpdateCallback(); +#endif while (callback) { if (Controller* ctrl = dynamic_cast(callback)) @@ -89,7 +95,13 @@ namespace SceneUtil for (unsigned int i=0; igetUpdateCallback(); +#else osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); +#endif + if (Controller* ctrl = dynamic_cast(callback)) visit(geode, *ctrl); } diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 66e40f3e10..36aa683dbe 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -1,6 +1,7 @@ #include "statesetupdater.hpp" #include +#include namespace SceneUtil { diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index f16c0bca4d..84aafa1004 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace SDLUtil { @@ -108,7 +109,11 @@ void GraphicsWindowSDL2::init() mValid = true; +#if OSG_MIN_VERSION_REQUIRED(3,3,4) + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#else getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#endif } @@ -125,7 +130,11 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); +#if OSG_MIN_VERSION_REQUIRED(3,3,4) + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#else getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#endif mRealized = true; From 5edf457ab7534567b8ef37ac87f044cbb9eb03ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:13:23 +0200 Subject: [PATCH 0428/1812] Build fix --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 530aa3decf..44784fd7e9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1237,12 +1237,12 @@ namespace NifOsg texEnv->setCombine_Alpha(GL_MODULATE); texEnv->setOperand0_Alpha(GL_SRC_ALPHA); texEnv->setOperand1_Alpha(GL_SRC_ALPHA); - texEnv->setSource0_Alpha(GL_PREVIOUS); + texEnv->setSource0_Alpha(GL_PREVIOUS_ARB); texEnv->setSource1_Alpha(GL_TEXTURE); texEnv->setCombine_RGB(GL_MODULATE); texEnv->setOperand0_RGB(GL_SRC_COLOR); texEnv->setOperand1_RGB(GL_SRC_COLOR); - texEnv->setSource0_RGB(GL_PREVIOUS); + texEnv->setSource0_RGB(GL_PREVIOUS_ARB); texEnv->setSource1_RGB(GL_TEXTURE); stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); } From 10457c1b28190cb55d7af29c51ee0943f8bebf4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:14:26 +0200 Subject: [PATCH 0429/1812] Include fix --- components/vfs/manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 829e089788..6be6dca9e6 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,7 @@ #include "manager.hpp" #include +#include #include "archive.hpp" From d9a00288f850dc2ba585d9db12ba45e9bad1ca34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:58:12 +0200 Subject: [PATCH 0430/1812] Make install fix --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f47b5faec..77b054ff51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,9 +316,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" ) ENDIF(BUILD_WIZARD) - if(BUILD_MYGUI_PLUGIN) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) - ENDIF(BUILD_MYGUI_PLUGIN) + #if(BUILD_MYGUI_PLUGIN) + # INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) + #ENDIF(BUILD_MYGUI_PLUGIN) # Install licenses INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) From 347c9b57b8af392aa906f7840298a2b86f676bd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 01:59:42 +0200 Subject: [PATCH 0431/1812] Copy constructor signature fix --- components/nifosg/particle.cpp | 2 +- components/nifosg/particle.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index ac304bdf31..92a849a0db 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -69,7 +69,7 @@ ParticleShooter::ParticleShooter() { } -ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) +ParticleShooter::ParticleShooter(const ParticleShooter ©, const osg::CopyOp ©op) : osgParticle::Shooter(copy, copyop) { *this = copy; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 5e463aae3d..c7d5d585d4 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -76,7 +76,7 @@ namespace NifOsg ParticleShooter(float minSpeed, float maxSpeed, float horizontalDir, float horizontalAngle, float verticalDir, float verticalAngle, float lifetime, float lifetimeRandom); ParticleShooter(); - ParticleShooter(const Shooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + ParticleShooter(const ParticleShooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Object(NifOsg, ParticleShooter) From fc8e5dde3befb5ff4e73548ff686be5e6963a634 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 03:26:36 +0200 Subject: [PATCH 0432/1812] Fix crash when OSG_STEREO is enabled --- components/myguiplatform/myguirendermanager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index ece667eb22..773c58a596 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -107,7 +107,7 @@ class Drawable : public osg::Drawable { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - mReadFrom = (mReadFrom+1)%2; + mReadFrom = (mReadFrom+1)%sNumBuffers; const std::vector& vec = mBatchVector[mReadFrom]; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { @@ -188,15 +188,18 @@ public: void clear() { - mWriteTo = (mWriteTo+1)%2; + mWriteTo = (mWriteTo+1)%sNumBuffers; mBatchVector[mWriteTo].clear(); } META_Object(osgMyGUI, Drawable) private: + // 2 would be enough in most cases, use 4 to get stereo working + static const int sNumBuffers = 4; + // double buffering approach, to avoid the need for synchronization with the draw thread - std::vector mBatchVector[2]; + std::vector mBatchVector[sNumBuffers]; int mWriteTo; mutable int mReadFrom; From cd42448cd6bb50d030070c976bc57b3b4e4548c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 8 Jun 2015 15:41:39 +0200 Subject: [PATCH 0433/1812] Windows build fixes and CMakeLists cleanup Adds some flags necessary to build and link with OSG. This also moves LTO and MP switches to user-accessible options, and actually applies the generated CXXFLAGS to the project. Since the generation happens after the subdirectories are added. --- CMakeLists.txt | 86 +++++++++++++++++++++++++++++++----------- apps/opencs/editor.cpp | 3 ++ 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77b054ff51..523145c71a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,11 @@ option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with # OS X deployment option(OPENMW_OSX_DEPLOYMENT OFF) +if (MSVC) + option(OPENMW_MP_BUILD "Build OpenMW with /MP flag" OFF) + option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) +endif() + # Location of morrowind data files if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") @@ -138,6 +143,9 @@ if (WIN32) # Suppress WinMain(), provided by SDL add_definitions(-DSDL_MAIN_HANDLED) + + # Get rid of useless crud from windows.h + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() # Dependencies @@ -268,10 +276,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") - set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + if (OPENMW_LTO_BUILD) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + endif() + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE") endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) @@ -380,6 +392,8 @@ if(WIN32) ENDIF(BUILD_MYGUI_PLUGIN) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") + FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") + INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".") SET(CPACK_GENERATOR "NSIS") SET(CPACK_PACKAGE_NAME "OpenMW") @@ -492,9 +506,9 @@ endif() if (WIN32) if (MSVC) - if (MULTITHREADED_BUILD) + if (OPENMW_MP_BUILD) set( MT_BUILD "/MP") - endif (MULTITHREADED_BUILD) + endif() foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) @@ -502,20 +516,22 @@ if (WIN32) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" ) endforeach( OUTPUTCONFIG ) - if (USE_DEBUG_CONSOLE) + if (USE_DEBUG_CONSOLE AND BUILD_OPENMW) set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else() + elseif (BUILD_OPENMW) # Turn off debug console, debug output will be written to visual studio output instead set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS") endif() - # Release builds use the debug console - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") + if (BUILD_OPENMW) + # Release builds use the debug console + set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") + set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") + set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") + endif() # Play a bit with the warning levels @@ -524,8 +540,8 @@ if (WIN32) set(WARNINGS_DISABLE # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables - # Not going to bother commenting them as they tend to warn on every standard library files - 4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 + # Not going to bother commenting them as they tend to warn on every standard library file + 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 # Warnings that are thrown on standard libraries and not OpenMW 4347 # Non-template function with same name and parameter count as template function @@ -547,6 +563,7 @@ if (WIN32) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) + 4245 # Signed/unsigned mismatch 4267 # Conversion from 'size_t' to 'int', possible loss of data 4305 # Truncating value (double to float, for example) 4309 # Variable overflow, trying to store 128 in a signed char for example @@ -562,17 +579,42 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") - + set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") # oics uses tinyxml, which has an initialized but unused variable - set(OICS_WARNINGS "${WARNINGS} /wd4189") - set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") + set_target_properties(oics PROPERTIES COMPILE_FLAGS "${WARNINGS} /wd4189 ${MT_BUILD}") + set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + + if (BUILD_BSATOOL) + set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_ESMTOOL) + set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_ESSIMPORTER) + set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_LAUNCHER) + set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_MWINIIMPORTER) + set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() if (BUILD_OPENCS) - # QT triggers an informational warning that the object layout may differ when compiled with /vd2 - set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") - set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) - endif (BUILD_OPENCS) + set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_OPENMW) + set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() + + if (BUILD_WIZARD) + set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif() endif(MSVC) # TODO: At some point release builds should not use the console but rather write to a log file diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index d6aecd7fb6..f9c527da5a 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -14,6 +14,9 @@ #include "model/doc/document.hpp" #include "model/world/data.hpp" +#ifdef _WIN32 +#include +#endif CS::Editor::Editor () : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), From f511cb08ff73917669672359703c529eb801fcbc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 20:37:01 +0200 Subject: [PATCH 0434/1812] Compatibility with bullet versions < 2.81 --- apps/openmw/mwphysics/physicssystem.cpp | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b7d02e1591..6be42affb9 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -672,16 +672,24 @@ namespace MWPhysics mLeastDistSqr(std::numeric_limits::max()) { } +#if BT_BULLET_VERSION >= 281 virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { - if (col1Wrap->m_collisionObject != mMe) + const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const btCollisionObject* collisionObject = col1; +#endif + if (collisionObject != mMe) { btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); if(!mObject || distsqr < mLeastDistSqr) { - mObject = col1Wrap->m_collisionObject; + mObject = collisionObject; mLeastDistSqr = distsqr; mContactPoint = cp.getPositionWorldOnA(); } @@ -874,11 +882,19 @@ namespace MWPhysics public: std::vector mResult; - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) +#if BT_BULLET_VERSION >= 281 + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { - const PtrHolder* holder = static_cast(colObj0Wrap->m_collisionObject->getUserPointer()); + const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const btCollisionObject* collisionObject = col1; +#endif + const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) mResult.push_back(holder->getPtr()); return 0.f; From 93ee11c5e78b045848957908006044576bff8302 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Jun 2015 21:21:09 +0200 Subject: [PATCH 0435/1812] Fix particlesystem nested RenderBin issue (Bug #2631) --- components/nifosg/nifloader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 44784fd7e9..fcba9893dd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -868,8 +868,6 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT); } - partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; From 5921e7062544ae19c1d78fd8a1e5a98ddbdb0de2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 02:29:56 +0200 Subject: [PATCH 0436/1812] Build a kdtree for terrain geometry Improves intersection testing performance, shaving off ~2ms of frame time in exteriors. Also increases terrain loading time by ~1ms per cell, so will have to look into background loading soon. --- components/terrain/terraingrid.cpp | 5 +++++ components/terrain/terraingrid.hpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 322c15196d..c8f8caef8e 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -66,6 +67,7 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) + , mKdTreeBuilder(new osg::KdTreeBuilder) { } @@ -133,6 +135,9 @@ void TerrainGrid::loadCell(int x, int y) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); + // build a kdtree to speed up intersection tests with the terrain + geode->accept(*mKdTreeBuilder); + std::vector layerList; std::vector > blendmaps; mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 3a6d717933..a697297b5a 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -25,6 +25,11 @@ #include "world.hpp" #include "material.hpp" +namespace osg +{ + class KdTreeBuilder; +} + namespace Terrain { @@ -44,6 +49,8 @@ namespace Terrain private: typedef std::map, GridElement*> Grid; Grid mGrid; + + osg::ref_ptr mKdTreeBuilder; }; } From db16cdad027e4b53bbf62a6e40dedc1277d4e560 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 03:16:41 +0200 Subject: [PATCH 0437/1812] Add a comment --- components/terrain/terraingrid.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index c8f8caef8e..570461bba8 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -136,6 +136,7 @@ void TerrainGrid::loadCell(int x, int y) geode->addDrawable(geometry); // build a kdtree to speed up intersection tests with the terrain + // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree geode->accept(*mKdTreeBuilder); std::vector layerList; From c621d0400c58e4e7cff5ec8bfc7fe5f5073d80aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Jun 2015 18:22:18 +0200 Subject: [PATCH 0438/1812] Fix error handling for out-of-range NIF roots (found in Bosmora, TR) --- components/nif/niffile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 0a6f8f505f..1db9c8ccf7 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -193,9 +193,9 @@ void NIFFile::parse() for(size_t i = 0;i < rootNum;i++) { int idx = nif.getInt(); - if (idx >= 0) + if (idx >= 0 && idx < int(records.size())) { - roots[i] = records.at(idx); + roots[i] = records[idx]; } else { From 15453e3d905fb149cd7502a9dc16ed39d190f1af Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 16:59:35 +0200 Subject: [PATCH 0439/1812] Use MyGUI::UString for unicode conversion --- apps/openmw/mwinput/inputmanagerimp.cpp | 65 ++----------------------- 1 file changed, 3 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1b5abc099f..7ef26f703c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -35,65 +35,6 @@ using namespace ICS; -namespace -{ - std::vector utf8ToUnicode(const std::string& utf8) - { - std::vector unicode; - size_t i = 0; - while (i < utf8.size()) - { - unsigned long uni; - size_t todo; - unsigned char ch = utf8[i++]; - if (ch <= 0x7F) - { - uni = ch; - todo = 0; - } - else if (ch <= 0xBF) - { - throw std::logic_error("not a UTF-8 string"); - } - else if (ch <= 0xDF) - { - uni = ch&0x1F; - todo = 1; - } - else if (ch <= 0xEF) - { - uni = ch&0x0F; - todo = 2; - } - else if (ch <= 0xF7) - { - uni = ch&0x07; - todo = 3; - } - else - { - throw std::logic_error("not a UTF-8 string"); - } - for (size_t j = 0; j < todo; ++j) - { - if (i == utf8.size()) - throw std::logic_error("not a UTF-8 string"); - unsigned char ch = utf8[i++]; - if (ch < 0x80 || ch > 0xBF) - throw std::logic_error("not a UTF-8 string"); - uni <<= 6; - uni += ch & 0x3F; - } - if (uni >= 0xD800 && uni <= 0xDFFF) - throw std::logic_error("not a UTF-8 string"); - if (uni > 0x10FFFF) - throw std::logic_error("not a UTF-8 string"); - unicode.push_back(uni); - } - return unicode; - } -} - namespace MWInput { InputManager::InputManager( @@ -723,9 +664,9 @@ namespace MWInput void InputManager::textInput(const SDL_TextInputEvent &arg) { - const char* text = &arg.text[0]; - std::vector unicode = utf8ToUnicode(std::string(text)); - for (std::vector::iterator it = unicode.begin(); it != unicode.end(); ++it) + MyGUI::UString ustring(&arg.text[0]); + MyGUI::UString::utf32string utf32string = ustring.asUTF32(); + for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it) MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); } From cc71e894e1ec30782ebe9e6ef398f5b270f9ceb9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:15:31 +0200 Subject: [PATCH 0440/1812] Add WorkQueue class --- components/CMakeLists.txt | 2 +- components/sceneutil/workqueue.cpp | 119 +++++++++++++++++++++++++++++ components/sceneutil/workqueue.hpp | 91 ++++++++++++++++++++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/workqueue.cpp create mode 100644 components/sceneutil/workqueue.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5a4ec605b3..8ce7706570 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller workqueue ) add_component_dir (nif diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp new file mode 100644 index 0000000000..a709eae85f --- /dev/null +++ b/components/sceneutil/workqueue.cpp @@ -0,0 +1,119 @@ +#include "workqueue.hpp" + +namespace SceneUtil +{ + +void WorkTicket::waitTillDone() +{ + if (mDone > 0) + return; + + OpenThreads::ScopedLock lock(mMutex); + while (mDone == 0) + { + mCondition.wait(&mMutex); + } +} + +void WorkTicket::signalDone() +{ + OpenThreads::ScopedLock lock(mMutex); + mDone.exchange(1); + mCondition.broadcast(); +} + +WorkItem::WorkItem() + : mTicket(new WorkTicket) +{ +} + +WorkItem::~WorkItem() +{ +} + +void WorkItem::doWork() +{ + mTicket->signalDone(); +} + +osg::ref_ptr WorkItem::getTicket() +{ + return mTicket; +} + +WorkQueue::WorkQueue(int workerThreads) + : mIsReleased(false) +{ + for (int i=0; istartThread(); + } +} + +WorkQueue::~WorkQueue() +{ + { + OpenThreads::ScopedLock lock(mMutex); + while (mQueue.size()) + { + WorkItem* item = mQueue.front(); + delete item; + mQueue.pop(); + } + mIsReleased = true; + mCondition.broadcast(); + } + + for (unsigned int i=0; ijoin(); + delete mThreads[i]; + } +} + +WorkTicket* WorkQueue::addWorkItem(WorkItem *item) +{ + WorkTicket* ticket = item->getTicket().get(); + OpenThreads::ScopedLock lock(mMutex); + mQueue.push(item); + mCondition.signal(); + return ticket; +} + +WorkItem *WorkQueue::removeWorkItem() +{ + OpenThreads::ScopedLock lock(mMutex); + while (!mQueue.size() && !mIsReleased) + { + mCondition.wait(&mMutex); + } + if (mQueue.size()) + { + WorkItem* item = mQueue.front(); + mQueue.pop(); + return item; + } + else + return NULL; +} + +WorkThread::WorkThread(WorkQueue *workQueue) + : mWorkQueue(workQueue) +{ +} + +void WorkThread::run() +{ + while (true) + { + WorkItem* item = mWorkQueue->removeWorkItem(); + if (!item) + return; + item->doWork(); + delete item; + } +} + +} diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp new file mode 100644 index 0000000000..720fbaa686 --- /dev/null +++ b/components/sceneutil/workqueue.hpp @@ -0,0 +1,91 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H +#define OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H + +#include +#include +#include +#include + +#include +#include + +#include + +namespace SceneUtil +{ + + class WorkTicket : public osg::Referenced + { + public: + void waitTillDone(); + + void signalDone(); + + private: + OpenThreads::Atomic mDone; + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondition; + }; + + class WorkItem + { + public: + WorkItem(); + virtual ~WorkItem(); + + /// Override in a derived WorkItem to perform actual work. + /// By default, just signals the ticket that the work is done. + virtual void doWork(); + + osg::ref_ptr getTicket(); + + protected: + osg::ref_ptr mTicket; + }; + + class WorkQueue; + + class WorkThread : public OpenThreads::Thread + { + public: + WorkThread(WorkQueue* workQueue); + + virtual void run(); + + private: + WorkQueue* mWorkQueue; + }; + + /// @brief A work queue that users can push work items onto, to be completed by one or more background threads. + class WorkQueue + { + public: + WorkQueue(int numWorkerThreads=1); + ~WorkQueue(); + + /// Add a new work item to the back of the queue. + /// @par The returned WorkTicket may be used by the caller to wait until the work is complete. + WorkTicket* addWorkItem(WorkItem* item); + + /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. + /// If the workqueue is in the process of being destroyed, may return NULL. + /// @note The caller must free the returned WorkItem + WorkItem* removeWorkItem(); + + void runThread(); + + private: + bool mIsReleased; + std::queue mQueue; + + OpenThreads::Mutex mMutex; + OpenThreads::Condition mCondition; + + std::vector mThreads; + }; + + + +} + +#endif From d52d0d96400c9babc8a52fffa2edf4f101d05d34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:16:02 +0200 Subject: [PATCH 0441/1812] Use the WorkQueue to update skinning --- components/sceneutil/riggeometry.cpp | 124 ++++++++++++++++++++++++--- components/sceneutil/riggeometry.hpp | 19 ++++ 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2a67c6ce60..50e47e2892 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include "skeleton.hpp" @@ -63,6 +65,8 @@ RigGeometry::RigGeometry() , mFirstFrame(true) , mBoundsFirstFrame(true) { + initWorkQueue(); + setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); @@ -75,9 +79,21 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { + initWorkQueue(); + setSourceGeometry(copy.mSourceGeometry); } +void RigGeometry::initWorkQueue() +{ + static int numCpu = OpenThreads::GetNumberOfProcessors(); + if (numCpu > 1) + { + static WorkQueue sWorkQueue(1); + mWorkQueue = &sWorkQueue; + } +} + void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; @@ -198,22 +214,31 @@ void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& ma ptrresult[14] += ptr[14] * weight; } -void RigGeometry::update(osg::NodeVisitor* nv) +class UpdateSkinningWorkItem : public WorkItem { - if (!mSkeleton) +public: + UpdateSkinningWorkItem(RigGeometry* rig, const osg::Matrixf& geomToSkelMatrix, RigGeometry::BoneMatrixMap boneMatrices) + : mRig(rig) + , mGeomToSkelMatrix(geomToSkelMatrix) + , mBoneMatrices(boneMatrices) { - if (!initFromParentSkeleton(nv)) - return; } - if (!mSkeleton->getActive() && !mFirstFrame) - return; - mFirstFrame = false; + virtual void doWork() + { + mRig->updateSkinning(mGeomToSkelMatrix, mBoneMatrices); - mSkeleton->updateBoneMatrices(nv); + mTicket->signalDone(); + } - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); +private: + RigGeometry* mRig; + osg::Matrixf mGeomToSkelMatrix; + RigGeometry::BoneMatrixMap mBoneMatrices; +}; +void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::BoneMatrixMap boneMatrices) +{ // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -233,7 +258,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) Bone* bone = weightIt->first.first; const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; - const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; + const osg::Matrixf& boneMatrix = boneMatrices.at(bone); accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; @@ -250,6 +275,45 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); } +void RigGeometry::update(osg::NodeVisitor* nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; + + mSkeleton->updateBoneMatrices(nv); + + BoneMatrixMap boneMatrices; + for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) + boneMatrices[it->first] = it->first->mMatrixInSkeletonSpace; + + if (mWorkQueue) + { + // shouldn't happen, unless the CullCallback was a false positive, i.e. the Drawable's parent wasn't culled, but the Drawable *is* culled + if (mWorkTicket) + mWorkTicket->waitTillDone(); + + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + + // actual skinning update moved to a background thread + WorkItem* item = new UpdateSkinningWorkItem(this, geomToSkel, boneMatrices); + // keep the work ticket so we can synchronize in drawImplementation() + mWorkTicket = item->getTicket(); + + mWorkQueue->addWorkItem(item); + } + else + { + updateSkinning(getGeomToSkelMatrix(nv), boneMatrices); + } +} + void RigGeometry::updateBounds(osg::NodeVisitor *nv) { if (!mSkeleton) @@ -279,6 +343,46 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } +void RigGeometry::drawImplementation(osg::RenderInfo &renderInfo) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::drawImplementation(renderInfo); +} + +void RigGeometry::compileGLObjects(osg::RenderInfo &renderInfo) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::compileGLObjects(renderInfo); +} + +void RigGeometry::accept(osg::PrimitiveFunctor &pf) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::accept(pf); +} + +void RigGeometry::accept(osg::PrimitiveIndexFunctor &pf) const +{ + if (mWorkTicket) + { + mWorkTicket->waitTillDone(); + mWorkTicket = NULL; + } + osg::Geometry::accept(pf); +} + osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index bd7c586c47..4dd8e80138 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -7,12 +7,16 @@ namespace SceneUtil { + class WorkQueue; + class WorkTicket; + class Skeleton; class Bone; /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. + /// @note You must use a double buffering scheme for queuing the drawing of RigGeometries, see FrameSwitch, or set their DataVariance to DYNAMIC class RigGeometry : public osg::Geometry { public: @@ -41,10 +45,23 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); + // Called by the worker thread + typedef std::map BoneMatrixMap; + void updateSkinning(const osg::Matrixf& geomToSkelMatrix, BoneMatrixMap boneMatrices); + // Called automatically by our UpdateCallback void updateBounds(osg::NodeVisitor* nv); + // Overriding a bunch of Drawable methods to synchronize access to our vertex array + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; + virtual void accept(osg::PrimitiveFunctor& pf) const; + virtual void accept(osg::PrimitiveIndexFunctor& pf) const; + private: + mutable osg::ref_ptr mWorkTicket; + WorkQueue* mWorkQueue; + osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; @@ -70,6 +87,8 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); + + void initWorkQueue(); }; } From 35b2d91fb3bd8f8cc6190c041ab5f8a3ede897ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 18:46:51 +0200 Subject: [PATCH 0442/1812] Throw error when failing to create graphics context --- components/sdlutil/sdlcursormanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 1c5008f7af..a8a48f4f8b 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -1,6 +1,7 @@ #include "sdlcursormanager.hpp" #include +#include #include #include @@ -48,6 +49,8 @@ namespace traits->pbuffer = false; _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if (!_gc) + throw std::runtime_error("Failed to create graphics context for image decompression"); } if (_gc.valid()) From 9c86d4f8bc19fa180b77fca0b21a66c64e3cbced Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 19:02:33 +0200 Subject: [PATCH 0443/1812] Race condition fix --- components/sceneutil/workqueue.cpp | 5 +++-- components/sceneutil/workqueue.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index a709eae85f..9f23fba2dd 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -25,6 +25,7 @@ void WorkTicket::signalDone() WorkItem::WorkItem() : mTicket(new WorkTicket) { + mTicket->setThreadSafeRefUnref(true); } WorkItem::~WorkItem() @@ -73,9 +74,9 @@ WorkQueue::~WorkQueue() } } -WorkTicket* WorkQueue::addWorkItem(WorkItem *item) +osg::ref_ptr WorkQueue::addWorkItem(WorkItem *item) { - WorkTicket* ticket = item->getTicket().get(); + osg::ref_ptr ticket = item->getTicket(); OpenThreads::ScopedLock lock(mMutex); mQueue.push(item); mCondition.signal(); diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 720fbaa686..492bbd090e 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -65,7 +65,7 @@ namespace SceneUtil /// Add a new work item to the back of the queue. /// @par The returned WorkTicket may be used by the caller to wait until the work is complete. - WorkTicket* addWorkItem(WorkItem* item); + osg::ref_ptr addWorkItem(WorkItem* item); /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. /// If the workqueue is in the process of being destroyed, may return NULL. From a1e74a35a279ef0d66dc8bdb9945d592f8c6a6b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 19:08:56 +0200 Subject: [PATCH 0444/1812] Revert "Use the WorkQueue to update skinning" This reverts commit d52d0d96400c9babc8a52fffa2edf4f101d05d34. Moving to branch --- components/sceneutil/riggeometry.cpp | 124 +++------------------------ components/sceneutil/riggeometry.hpp | 19 ---- 2 files changed, 10 insertions(+), 133 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 50e47e2892..2a67c6ce60 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -5,8 +5,6 @@ #include -#include - #include #include "skeleton.hpp" @@ -65,8 +63,6 @@ RigGeometry::RigGeometry() , mFirstFrame(true) , mBoundsFirstFrame(true) { - initWorkQueue(); - setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); @@ -79,21 +75,9 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mFirstFrame(copy.mFirstFrame) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { - initWorkQueue(); - setSourceGeometry(copy.mSourceGeometry); } -void RigGeometry::initWorkQueue() -{ - static int numCpu = OpenThreads::GetNumberOfProcessors(); - if (numCpu > 1) - { - static WorkQueue sWorkQueue(1); - mWorkQueue = &sWorkQueue; - } -} - void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; @@ -214,31 +198,22 @@ void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& ma ptrresult[14] += ptr[14] * weight; } -class UpdateSkinningWorkItem : public WorkItem +void RigGeometry::update(osg::NodeVisitor* nv) { -public: - UpdateSkinningWorkItem(RigGeometry* rig, const osg::Matrixf& geomToSkelMatrix, RigGeometry::BoneMatrixMap boneMatrices) - : mRig(rig) - , mGeomToSkelMatrix(geomToSkelMatrix) - , mBoneMatrices(boneMatrices) + if (!mSkeleton) { + if (!initFromParentSkeleton(nv)) + return; } - virtual void doWork() - { - mRig->updateSkinning(mGeomToSkelMatrix, mBoneMatrices); + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; - mTicket->signalDone(); - } + mSkeleton->updateBoneMatrices(nv); -private: - RigGeometry* mRig; - osg::Matrixf mGeomToSkelMatrix; - RigGeometry::BoneMatrixMap mBoneMatrices; -}; + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); -void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::BoneMatrixMap boneMatrices) -{ // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -258,7 +233,7 @@ void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::Bo Bone* bone = weightIt->first.first; const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; - const osg::Matrixf& boneMatrix = boneMatrices.at(bone); + const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; @@ -275,45 +250,6 @@ void RigGeometry::updateSkinning(const osg::Matrixf& geomToSkel, RigGeometry::Bo normalDst->dirty(); } -void RigGeometry::update(osg::NodeVisitor* nv) -{ - if (!mSkeleton) - { - if (!initFromParentSkeleton(nv)) - return; - } - - if (!mSkeleton->getActive() && !mFirstFrame) - return; - mFirstFrame = false; - - mSkeleton->updateBoneMatrices(nv); - - BoneMatrixMap boneMatrices; - for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) - boneMatrices[it->first] = it->first->mMatrixInSkeletonSpace; - - if (mWorkQueue) - { - // shouldn't happen, unless the CullCallback was a false positive, i.e. the Drawable's parent wasn't culled, but the Drawable *is* culled - if (mWorkTicket) - mWorkTicket->waitTillDone(); - - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); - - // actual skinning update moved to a background thread - WorkItem* item = new UpdateSkinningWorkItem(this, geomToSkel, boneMatrices); - // keep the work ticket so we can synchronize in drawImplementation() - mWorkTicket = item->getTicket(); - - mWorkQueue->addWorkItem(item); - } - else - { - updateSkinning(getGeomToSkelMatrix(nv), boneMatrices); - } -} - void RigGeometry::updateBounds(osg::NodeVisitor *nv) { if (!mSkeleton) @@ -343,46 +279,6 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } -void RigGeometry::drawImplementation(osg::RenderInfo &renderInfo) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::drawImplementation(renderInfo); -} - -void RigGeometry::compileGLObjects(osg::RenderInfo &renderInfo) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::compileGLObjects(renderInfo); -} - -void RigGeometry::accept(osg::PrimitiveFunctor &pf) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::accept(pf); -} - -void RigGeometry::accept(osg::PrimitiveIndexFunctor &pf) const -{ - if (mWorkTicket) - { - mWorkTicket->waitTillDone(); - mWorkTicket = NULL; - } - osg::Geometry::accept(pf); -} - osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 4dd8e80138..bd7c586c47 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -7,16 +7,12 @@ namespace SceneUtil { - class WorkQueue; - class WorkTicket; - class Skeleton; class Bone; /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. - /// @note You must use a double buffering scheme for queuing the drawing of RigGeometries, see FrameSwitch, or set their DataVariance to DYNAMIC class RigGeometry : public osg::Geometry { public: @@ -45,23 +41,10 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); - // Called by the worker thread - typedef std::map BoneMatrixMap; - void updateSkinning(const osg::Matrixf& geomToSkelMatrix, BoneMatrixMap boneMatrices); - // Called automatically by our UpdateCallback void updateBounds(osg::NodeVisitor* nv); - // Overriding a bunch of Drawable methods to synchronize access to our vertex array - virtual void drawImplementation(osg::RenderInfo& renderInfo) const; - virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; - virtual void accept(osg::PrimitiveFunctor& pf) const; - virtual void accept(osg::PrimitiveIndexFunctor& pf) const; - private: - mutable osg::ref_ptr mWorkTicket; - WorkQueue* mWorkQueue; - osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; @@ -87,8 +70,6 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); - - void initWorkQueue(); }; } From b5099324d19e79359a05bff7dacddc17f12f6dc4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Jun 2015 20:35:59 +0200 Subject: [PATCH 0445/1812] Enable ParticleSystem's FreezeOnCull, big speed-up in Vivec --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index fcba9893dd..2c409ac96f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -822,6 +822,8 @@ namespace NifOsg partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + partsys->setFreezeOnCull(true); + osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); From 8d6620b0745991a46d73077de171e9a4b51b021e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 02:37:49 +0200 Subject: [PATCH 0446/1812] Assign an initial bounding box to particle systems --- components/nifosg/nifloader.cpp | 4 ++++ components/resource/scenemanager.cpp | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2c409ac96f..b95eeebfc0 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -749,6 +749,10 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + + osg::BoundingBox box; + box.expandBy(osg::BoundingSphere(osg::Vec3(0,0,0), particledata->radius)); + partsys->setInitialBound(box); } static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 8de08bd9d6..bb4c57e4c0 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace { @@ -61,6 +62,13 @@ namespace { partsys->getParticle(i)->transformPositionVelocity(worldMat); } + + // transform initial bounds to worldspace + osg::BoundingSphere sphere(partsys->getInitialBound()); + SceneUtil::transformBoundingSphere(worldMat, sphere); + osg::BoundingBox box; + box.expandBy(sphere); + partsys->setInitialBound(box); } }; From c7493eb45c41637b623737d0c23828daff629af5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:14:51 +0200 Subject: [PATCH 0447/1812] Fix bug with invisibility effect for meshes w/ vertex colors --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7de3e1d5a6..21ec8d535c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1006,7 +1006,7 @@ void NpcAnimation::setAlpha(float alpha) // FIXME: overriding diffuse/ambient/emissive colors osg::Material* material (new osg::Material); - material->setColorMode(osg::Material::DIFFUSE); + material->setColorMode(osg::Material::OFF); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); From c94c87d40942ae63ebb5c8489019d32c823989fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:22:09 +0200 Subject: [PATCH 0448/1812] Attach effects to the insert node instead of the object root (Bug #2654) --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d92e57f19f..261ec6c5b5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1060,7 +1060,7 @@ namespace MWRender params.mModelName = model; osg::ref_ptr parentNode; if (bonename.empty()) - parentNode = mObjectRoot->asGroup(); + parentNode = mInsert; else { NodeMap::iterator found = mNodeMap.find(Misc::StringUtils::lowerCase(bonename)); From f81c3bcd6d3d7777fe1b281d3ab6cee9f2984042 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 16:40:26 +0200 Subject: [PATCH 0449/1812] Fix for broken InitWorldSpaceParticles on projectile effects --- apps/openmw/mwworld/projectilemanager.cpp | 20 +++++++------------- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 84d86fba74..d0a5de5b2d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -40,10 +40,12 @@ namespace MWWorld } - void ProjectileManager::createModel(State &state, const std::string &model) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); + state.mNode->setPosition(pos); + state.mNode->setAttitude(orient); mParent->addChild(state.mNode); mResourceSystem->getSceneManager()->createInstance(model, state.mNode); @@ -105,9 +107,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr)); - state.mNode->setPosition(pos); - state.mNode->setAttitude(orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -127,9 +127,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr)); - state.mNode->setPosition(pos); - state.mNode->setAttitude(orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient); mProjectiles.push_back(state); } @@ -342,9 +340,7 @@ namespace MWWorld return true; } - createModel(state, model); - state.mNode->setPosition(osg::Vec3f(esm.mPosition)); - state.mNode->setAttitude(osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); mProjectiles.push_back(state); return true; @@ -375,9 +371,7 @@ namespace MWWorld return true; } - createModel(state, model); - state.mNode->setPosition(osg::Vec3f(esm.mPosition)); - state.mNode->setAttitude(osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f42bc040f8..68e408149f 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -116,7 +116,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); void update (State& state, float duration); }; From cdc47fa874ec391384728fae082d822b0cd8ee09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 17:59:49 +0200 Subject: [PATCH 0450/1812] Remove BulletNifLoader dependency on keyframe manager This will make threaded loading easier. --- components/nifbullet/bulletnifloader.cpp | 23 +++++++++++++-------- components/nifbullet/bulletnifloader.hpp | 4 ---- components/nifbullet/bulletshapemanager.cpp | 13 ------------ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 33c8c449d4..495c6ba50d 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -66,11 +66,6 @@ BulletNifLoader::~BulletNifLoader() { } -void BulletNifLoader::setAnimatedNodes(const std::set &animatedNodes) -{ - mAnimatedNodes = animatedNodes; -} - osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { mShape = new BulletShape; @@ -110,7 +105,20 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) else { bool autogenerated = hasAutoGeneratedCollision(node); - handleNode(node, 0, autogenerated, false, autogenerated); + bool isAnimated = false; + + // files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource). + // assume all nodes in the file will be animated + std::string filename = nif->getFilename(); + size_t slashpos = filename.find_last_of("/\\"); + if (slashpos == std::string::npos) + slashpos = 0; + if (slashpos+1 < filename.size() && (filename[slashpos+1] == 'x' || filename[slashpos+1] == 'X')) + { + isAnimated = true; + } + + handleNode(node, 0, autogenerated, isAnimated, autogenerated); if (mCompoundShape) { @@ -192,9 +200,6 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; - if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end()) - isAnimated = true; - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); // Don't collide with AvoidNode shapes diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0865b134a5..52428cc74a 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -91,8 +91,6 @@ public: abort(); } - void setAnimatedNodes(const std::set& animatedNodes); - osg::ref_ptr load(const Nif::NIFFilePtr file); private: @@ -108,8 +106,6 @@ private: btTriangleMesh* mStaticMesh; - std::set mAnimatedNodes; - osg::ref_ptr mShape; }; diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index e53a351cf4..57848ab812 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -34,20 +34,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: // TODO: add support for non-NIF formats - std::string kfname = normalized; - if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) - kfname.replace(kfname.size()-4, 4, ".kf"); - std::set animatedNodes; - if (mVFS->exists(kfname)) - { - osg::ref_ptr keyframes = mSceneManager->getKeyframes(kfname); - for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); - it != keyframes->mKeyframeControllers.end(); ++it) - animatedNodes.insert(it->first); - } - BulletNifLoader loader; - loader.setAnimatedNodes(animatedNodes); // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); From 712cef36b0a9e920ddd203b4b1e1d94e56e49767 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 18:01:00 +0200 Subject: [PATCH 0451/1812] Minor cleanup --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/nifbullet/bulletshapemanager.cpp | 5 +---- components/nifbullet/bulletshapemanager.hpp | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6be42affb9..2709ced4f5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -594,7 +594,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) + : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 57848ab812..6acfdd4085 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -4,14 +4,11 @@ #include -#include - namespace NifBullet { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) : mVFS(vfs) - , mSceneManager(sceneManager) { } diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp index 9db674d6de..6b9ec60de1 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/nifbullet/bulletshapemanager.hpp @@ -25,15 +25,13 @@ namespace NifBullet class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager); + BulletShapeManager(const VFS::Manager* vfs); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; - // need to load keyframes to know what nodes are going to be animated - Resource::SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; From 76bdf7a5b714d859860f24d807117089ee43ec06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Jun 2015 23:16:05 +0200 Subject: [PATCH 0452/1812] Add night-eye effect --- apps/openmw/mwrender/renderingmanager.cpp | 23 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 6 ++++++ apps/openmw/mwworld/worldimp.cpp | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1811ed67d..c8080cf166 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -118,6 +118,7 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; mLightRoot = lightRoot; @@ -203,9 +204,19 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::setNightEyeFactor(float factor) + { + if (factor != mNightEyeFactor) + { + mNightEyeFactor = factor; + updateAmbient(); + } + } + void RenderingManager::setAmbientColour(const osg::Vec4f &colour) { - mStateUpdater->setAmbientColor(colour); + mAmbientColor = colour; + updateAmbient(); } void RenderingManager::configureAmbient(const ESM::Cell *cell) @@ -653,6 +664,16 @@ namespace MWRender mViewer->startThreading(); } + void RenderingManager::updateAmbient() + { + osg::Vec4f color = mAmbientColor; + + if (mNightEyeFactor > 0.f) + color += osg::Vec4f(0.7, 0.7, 0.7, 0.0) * mNightEyeFactor; + + mStateUpdater->setAmbientColor(color); + } + void RenderingManager::setFogColor(const osg::Vec4f &color) { mViewer->getCamera()->setClearColor(color); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8ed590df49..a37203cc22 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -59,6 +59,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + void setNightEyeFactor(float factor); + void setAmbientColour(const osg::Vec4f& colour); void setSunDirection(const osg::Vec3f& direction); @@ -152,6 +154,7 @@ namespace MWRender private: void updateProjectionMatrix(); void updateTextureFiltering(); + void updateAmbient(); void setFogColor(const osg::Vec4f& color); osg::ref_ptr mViewer; @@ -175,6 +178,9 @@ namespace MWRender osg::Vec4f mFogColor; + osg::Vec4f mAmbientColor; + float mNightEyeFactor; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7b4c33fd87..16dcadb231 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1608,6 +1608,8 @@ namespace MWWorld int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); + int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); + mRendering->setNightEyeFactor(std::min(1.f, (nightEye/100.f))); mRendering->getCamera()->setCameraDistance(); if(!mRendering->getCamera()->isFirstPerson()) From 800bd511f6048ff44cde28a5c4194feaa8f07636 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 00:12:12 +0200 Subject: [PATCH 0453/1812] Set a sensible value for SDL_GL_DEPTH_SIZE (Bug #2649) --- apps/openmw/engine.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index eda33637b7..aa00f5e9c4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -342,6 +342,12 @@ void OMW::Engine::createWindow(Settings::Manager& settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + if (antialiasing > 0) { if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) From 7407bbdac9dd8e354fc6626b826e4f4de69c7500 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 01:08:58 +0200 Subject: [PATCH 0454/1812] Add a function for SDL error handling --- apps/openmw/engine.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index aa00f5e9c4..01ecd3d11a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -55,6 +55,15 @@ #include "mwstate/statemanagerimp.hpp" +namespace +{ + void checkSDLError(int ret) + { + if (ret != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } +} + void OMW::Engine::executeLocalScripts() { MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); @@ -342,18 +351,16 @@ void OMW::Engine::createWindow(Settings::Manager& settings) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24)); if (antialiasing > 0) { - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1)); + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing)); } while (!mWindow) @@ -367,8 +374,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl; antialiasing /= 2; Settings::Manager::setInt("antialiasing", "Video", antialiasing); - if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) - std::cerr << "SDL error: " << SDL_GetError() << std::endl; + checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing)); continue; } else From 40eb8b65c76e0bd0e487a47d06e06cafd8b76dec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 04:35:46 +0200 Subject: [PATCH 0455/1812] Revert the travis testing changes --- .travis.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2b2ad0799..1fc85dca38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ language: cpp branches: only: - master - - osg - coverity_scan - /openmw-.*$/ env: @@ -49,9 +48,9 @@ notifications: email: on_success: change on_failure: always - #irc: - # channels: - # - "chat.freenode.net#openmw" - # on_success: change - # on_failure: always - # use_notice: true + irc: + channels: + - "chat.freenode.net#openmw" + on_success: change + on_failure: always + use_notice: true From d4c45efb2bca16b92ffc82e9c24336db003bca82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Jun 2015 04:39:44 +0200 Subject: [PATCH 0456/1812] Remove useless #undef's for windows now that we have NOMINMAX flag --- apps/openmw/mwgui/class.cpp | 3 --- apps/openmw/mwgui/review.cpp | 3 --- apps/openmw/mwgui/widgets.cpp | 3 --- apps/openmw/mwmechanics/stat.hpp | 3 --- 4 files changed, 12 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 3e8734c716..57cd9ca8eb 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -11,9 +11,6 @@ #include "tooltips.hpp" -#undef min -#undef max - namespace { diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 12957c2b01..fa07f10207 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -13,9 +13,6 @@ #include "tooltips.hpp" -#undef min -#undef max - namespace { void adjustButtonSize(MyGUI::Button *button) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 1fa5d9cbf0..158d5fd5e4 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -15,9 +15,6 @@ #include "controllers.hpp" -#undef min -#undef max - namespace MWGui { namespace Widgets diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index ffbc19e151..64cc665206 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,9 +1,6 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H -#undef min -#undef max - #include #include From 195e1a84102ab994d395001dfcf69bd6323e09ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 15:27:33 +0200 Subject: [PATCH 0457/1812] Fix the Viewer's FrameStamp not being set correctly during Engine::frame --- apps/openmw/engine.cpp | 25 +++++++++++++++---------- apps/openmw/engine.hpp | 4 +--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 01ecd3d11a..f8382f860f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -82,7 +82,7 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -double OMW::Engine::frame(float frametime) +void OMW::Engine::frame(float frametime) { try { @@ -101,17 +101,14 @@ double OMW::Engine::frame(float frametime) if (mUseSound) MWBase::Environment::get().getSoundManager()->update(frametime); - // GUI active? Most game processing will be paused, but scripts still run. - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if (!guiActive) - mSimulationTime += frametime; - // Main menu opened? Then scripts are also paused. bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state MWBase::Environment::get().getStateManager()->update (frametime); + bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) @@ -193,7 +190,6 @@ double OMW::Engine::frame(float frametime) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } - return mSimulationTime; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -214,7 +210,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFSStrict (false) , mScriptBlacklistUse (true) , mNewGame (false) - , mSimulationTime(0.0) , mCfgMgr(configurationManager) { Misc::Rng::init(); @@ -679,14 +674,24 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; + double simulationTime = 0.0; while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); dt = std::min(dt, 0.2); - double simulationTime = frame(dt); - mViewer->frame(simulationTime); + bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if (!guiActive) + simulationTime += dt; + + mViewer->advance(simulationTime); + + frame(dt); + + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); } // Save user settings diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8ac6098b8a..73de57dc4b 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -106,7 +106,6 @@ namespace OMW bool mNewGame; osg::Timer_t mStartTick; - double mSimulationTime; // not implemented Engine (const Engine&); @@ -114,8 +113,7 @@ namespace OMW void executeLocalScripts(); - /// @return The new simulationTime - double frame (float dt); + void frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From 2476cd4f9a2b0ea3ca23bbd6370284bd98015a75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 16:12:18 +0200 Subject: [PATCH 0458/1812] Error message fix --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 62bc1f47e3..76c2f6ebac 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -560,7 +560,7 @@ namespace MWWorld } catch (std::exception& e) { - std::cerr << "error during rendering: " << e.what() << std::endl; + std::cerr << "error during rendering '" << ptr.getCellRef().getRefId() << "': " << e.what() << std::endl; } } From 9fc2c2e8ee2fa7aedcd254d647e4650433e227e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 16:32:34 +0200 Subject: [PATCH 0459/1812] Don't advertise an alpha channel in GraphicsContext::traits (Bug #2677) --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f8382f860f..dc2cb8f373 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -393,7 +393,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings) traits->red = 8; traits->green = 8; traits->blue = 8; - traits->alpha = 8; + traits->alpha = 0; // set to 0 to stop ScreenCaptureHandler reading the alpha channel traits->depth = 24; traits->stencil = 8; traits->vsync = vsync; From b90fc8ad921e89059e7568523a7d15b237152ad9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 18:19:53 +0200 Subject: [PATCH 0460/1812] Fix for various Viewer::frame calls resetting the simulationTime --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 774faa003f..7e733686db 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -259,7 +259,7 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); //osg::Timer timer; - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); //std::cout << "frame took " << timer.time_m() << std::endl; //if (mViewer->getIncrementalCompileOperation()) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 298d4812e3..515265bd92 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -851,7 +851,7 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); } } } @@ -1744,7 +1744,7 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); } mVideoWidget->stop(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8080cf166..4db776783a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -432,7 +432,7 @@ namespace MWRender mRootNode->addChild(rttCamera); - mViewer->frame(); + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); // The draw needs to complete before we can copy back our image. osg::ref_ptr callback (new NotifyDrawCompletedCallback); From 412e001edbce3fcbd9a2a26eb786946d0d242279 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 19:19:23 +0200 Subject: [PATCH 0461/1812] Fix simulation time reset in OpenCS when opening a new view --- apps/opencs/view/render/scenewidget.cpp | 5 ++++- apps/opencs/view/render/scenewidget.hpp | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 6136abb40f..208a7a5b73 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -95,6 +95,7 @@ void RenderWidget::setVisibilityMask(int mask) // -------------------------------------------------- CompositeViewer::CompositeViewer() + : mSimulationTime(0.0) { #if QT_VERSION >= 0x050000 // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 @@ -124,7 +125,9 @@ CompositeViewer &CompositeViewer::get() void CompositeViewer::update() { - frame(); + mSimulationTime += mFrameTimer.time_s(); + mFrameTimer.setStartTick(); + frame(mSimulationTime); } // --------------------------------------------------- diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 58c376418c..c269f355d1 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -100,6 +100,10 @@ namespace CSVRender QTimer mTimer; + private: + osg::Timer mFrameTimer; + double mSimulationTime; + public slots: void update(); }; From 98571148b0937e22610abc17e1b37415a80a76aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 20:44:29 +0200 Subject: [PATCH 0462/1812] Remove custom license for terrain code Now that it's no longer a stand-alone component, there's not much point in custom licensing it. --- components/terrain/buffercache.cpp | 21 --------------------- components/terrain/buffercache.hpp | 21 --------------------- components/terrain/defs.hpp | 21 --------------------- components/terrain/material.cpp | 21 --------------------- components/terrain/material.hpp | 21 --------------------- components/terrain/storage.cpp | 22 ---------------------- components/terrain/storage.hpp | 21 --------------------- components/terrain/terraingrid.cpp | 22 ---------------------- components/terrain/terraingrid.hpp | 21 --------------------- components/terrain/world.cpp | 21 --------------------- components/terrain/world.hpp | 21 --------------------- 11 files changed, 233 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index dfb3eff883..a64f8ffd1d 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "buffercache.hpp" #include diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 575e9bca25..ca210f2380 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 7b40ad4792..234e05a98a 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 2af8ddcda0..2034883edd 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "material.hpp" #include diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 47c5142c94..b423aa8b0c 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 857713a82b..bdc8194812 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -1,23 +1 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "storage.hpp" diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index a302c8f8ce..bd5706b25e 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 570461bba8..5afb991768 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,25 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "terraingrid.hpp" #include diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index a697297b5a..832b952e89 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 1cfcc80acb..2250b593d2 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * 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 "world.hpp" #include diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 70ec304102..4212f2a0c2 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -1,24 +1,3 @@ -/* - * Copyright (c) 2015 scrawl - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H From b204396b576b16d5e6fe2bf8eda090a4d0c97416 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 21:04:59 +0200 Subject: [PATCH 0463/1812] Minor fix --- components/sceneutil/workqueue.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index 9f23fba2dd..b642687f0f 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -17,8 +17,10 @@ void WorkTicket::waitTillDone() void WorkTicket::signalDone() { - OpenThreads::ScopedLock lock(mMutex); - mDone.exchange(1); + { + OpenThreads::ScopedLock lock(mMutex); + mDone.exchange(1); + } mCondition.broadcast(); } From 9e049894e8e06a16d833288aae69051b7a1a7ccc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 21:22:44 +0200 Subject: [PATCH 0464/1812] Reduce the number of StateSets created for NIF scene graphs The Material state is now set on the NiTriShape's node rather than the Geode, thus merged with other state like NiTexturingProperties, etc that are typically attached to the NiTriShape. Effectively cuts in half the number of StatSets for a NIF file, resulting in big speedup (~10%) in the Cull and Draw phases. --- components/nifosg/nifloader.cpp | 38 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b95eeebfc0..63121fda23 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -525,20 +525,20 @@ namespace NifOsg { const Nif::NiTriShape* triShape = static_cast(nifNode); if (triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures, animflags); + handleTriShape(triShape, transformNode, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); + handleSkinnedTriShape(triShape, transformNode, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, composite, boundTextures, animflags); } + if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) + handleParticleSystem(nifNode, transformNode, composite, animflags, particleflags, rootNode); + if (composite->getNumControllers() > 0) transformNode->addUpdateCallback(composite); - if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode); - if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); @@ -606,9 +606,8 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { - osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -630,8 +629,6 @@ namespace NifOsg else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } - if (composite->getNumControllers() > 0) - node->addUpdateCallback(composite); } static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) @@ -789,7 +786,7 @@ namespace NifOsg return emitter; } - static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -863,10 +860,10 @@ namespace NifOsg std::vector materialProps; collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(geode, materialProps, true, animflags); + applyMaterialProperties(parentNode, materialProps, composite, true, animflags); // Particles don't have normals, so can't be diffuse lit. - osg::Material* mat = static_cast(geode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); @@ -891,7 +888,7 @@ namespace NifOsg } } - static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) + static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -928,10 +925,10 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); + applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) + static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -955,7 +952,7 @@ namespace NifOsg geometry = new osg::Geometry; osg::ref_ptr geode (new osg::Geode); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); geode->addDrawable(geometry); @@ -1029,12 +1026,13 @@ namespace NifOsg return morphGeom; } - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) + static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, + const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); @@ -1275,7 +1273,7 @@ namespace NifOsg } } - static void applyMaterialProperties(osg::Node* node, const std::vector& properties, + static void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1310,7 +1308,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, animflags); + handleMaterialControllers(matprop, node, composite, animflags); break; } From f017fd6860dffd36a051e09824671ae5bdf19a92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 23:13:26 +0200 Subject: [PATCH 0465/1812] Reduce includes in animation.hpp --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 27 ++++++-------------- apps/openmw/mwrender/camera.cpp | 1 + apps/openmw/mwrender/characterpreview.cpp | 2 ++ 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea6b394816..c48599b465 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,6 +19,8 @@ #include "character.hpp" +#include + #include #include "movement.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 261ec6c5b5..4f0cde61d1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -17,6 +17,7 @@ #include #include // KeyframeHolder +#include #include @@ -204,6 +205,17 @@ namespace namespace MWRender { + struct Animation::AnimSource + { + osg::ref_ptr mKeyframes; + + typedef std::map > ControllerMap; + + ControllerMap mControllerMap[Animation::sNumGroups]; + + const std::multimap& getTextKeys(); + }; + class ResetAccumRootCallback : public osg::NodeCallback { public: @@ -1211,4 +1223,22 @@ namespace MWRender addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); } + Animation::AnimState::~AnimState() + { + + } + + // ------------------------------ + + PartHolder::PartHolder(osg::ref_ptr node) + : mNode(node) + { + } + + PartHolder::~PartHolder() + { + if (mNode->getNumParents()) + mNode->getParent(0)->removeChild(mNode); + } + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 419ae6bc01..d80fd96a4f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,7 +3,7 @@ #include "../mwworld/ptr.hpp" -#include +#include namespace ESM { @@ -18,6 +18,7 @@ namespace Resource namespace NifOsg { class KeyframeHolder; + class KeyframeController; } namespace MWRender @@ -43,16 +44,9 @@ public: class PartHolder { public: - PartHolder(osg::ref_ptr node) - : mNode(node) - { - } + PartHolder(osg::ref_ptr node); - ~PartHolder() - { - if (mNode->getNumParents()) - mNode->getParent(0)->removeChild(mNode); - } + ~PartHolder(); osg::ref_ptr getNode() { @@ -116,16 +110,7 @@ protected: } }; - struct AnimSource - { - osg::ref_ptr mKeyframes; - - typedef std::map > ControllerMap; - - ControllerMap mControllerMap[sNumGroups]; - - const std::multimap& getTextKeys(); - }; + struct AnimSource; struct AnimState { boost::shared_ptr mSource; @@ -150,6 +135,8 @@ protected: mPriority(0), mGroups(0), mAutoDisable(true) { } + ~AnimState(); + float getTime() const { return *mTime; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 9080d31644..316c9308be 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,6 +1,7 @@ #include "camera.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cdf99f0fc9..d6c30da971 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,5 +1,7 @@ #include "characterpreview.hpp" +#include + #include #include #include From a5b72a358b6ed8a20663953027b446af499866f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Jun 2015 23:56:35 +0200 Subject: [PATCH 0466/1812] Prune empty nodes in RemoveDrawableVisitor Gets rid of 28 useless transform nodes in base_anim.1st.nif. --- apps/openmw/mwrender/animation.cpp | 7 ++++++- components/nifosg/nifloader.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4f0cde61d1..62d50df0d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -182,7 +182,12 @@ namespace virtual void apply(osg::Geode &node) { // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.push_back(&node); + osg::Group* parent = node.getParent(0); + // prune nodes that would be empty after the removal + if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC) + mToRemove.push_back(parent); + else + mToRemove.push_back(&node); traverse(node); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 63121fda23..646a77f76e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -451,6 +451,22 @@ namespace NifOsg transformNode->addCullCallback(new BillboardCallback); } + // Set a default DataVariance (used as hint by optimization routines). + switch (nifNode->recType) + { + case Nif::RC_NiTriShape: + case Nif::RC_NiAutoNormalParticles: + case Nif::RC_NiRotatingParticles: + // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. + // No support for keyframe controllers (just crashes in the original engine). + transformNode->setDataVariance(osg::Object::STATIC); + break; + default: + // could have new children attached at any time, or added external keyframe controllers from .kf files + transformNode->setDataVariance(osg::Object::DYNAMIC); + break; + } + transformNode->setName(nifNode->name); if (parentNode) From 6a788c3462784b5d266540a580f69a7b5043a194 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 01:29:32 +0200 Subject: [PATCH 0467/1812] Minor cleanup --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 646a77f76e..ed352c2516 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -622,7 +622,7 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, int animflags) + static void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -1324,7 +1324,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, node, composite, animflags); + handleMaterialControllers(matprop, composite, animflags); break; } From ab597f672e5aaeea3afa2d5526753101681fd552 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 01:49:46 +0200 Subject: [PATCH 0468/1812] State the filename in NIF loader warning messages --- components/nifosg/nifloader.cpp | 213 +++++++++++++++++--------------- 1 file changed, 111 insertions(+), 102 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ed352c2516..7aec3385e3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -57,79 +57,6 @@ namespace } } - osg::BlendFunc::BlendFuncMode getBlendMode(int mode) - { - switch(mode) - { - case 0: return osg::BlendFunc::ONE; - case 1: return osg::BlendFunc::ZERO; - case 2: return osg::BlendFunc::SRC_COLOR; - case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; - case 4: return osg::BlendFunc::DST_COLOR; - case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; - case 6: return osg::BlendFunc::SRC_ALPHA; - case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; - case 8: return osg::BlendFunc::DST_ALPHA; - case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; - case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; - default: - std::cerr<< "Unexpected blend mode: "<< mode << std::endl; - return osg::BlendFunc::SRC_ALPHA; - } - } - - osg::AlphaFunc::ComparisonFunction getTestMode(int mode) - { - switch (mode) - { - case 0: return osg::AlphaFunc::ALWAYS; - case 1: return osg::AlphaFunc::LESS; - case 2: return osg::AlphaFunc::EQUAL; - case 3: return osg::AlphaFunc::LEQUAL; - case 4: return osg::AlphaFunc::GREATER; - case 5: return osg::AlphaFunc::NOTEQUAL; - case 6: return osg::AlphaFunc::GEQUAL; - case 7: return osg::AlphaFunc::NEVER; - default: - std::cerr << "Unexpected blend mode: " << mode << std::endl; - return osg::AlphaFunc::LEQUAL; - } - } - - osg::Stencil::Function getStencilFunction(int func) - { - switch (func) - { - case 0: return osg::Stencil::NEVER; - case 1: return osg::Stencil::LESS; - case 2: return osg::Stencil::EQUAL; - case 3: return osg::Stencil::LEQUAL; - case 4: return osg::Stencil::GREATER; - case 5: return osg::Stencil::NOTEQUAL; - case 6: return osg::Stencil::GEQUAL; - case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER - default: - std::cerr << "Unexpected stencil function: " << func << std::endl; - return osg::Stencil::NEVER; - } - } - - osg::Stencil::Operation getStencilOperation(int op) - { - switch (op) - { - case 0: return osg::Stencil::KEEP; - case 1: return osg::Stencil::ZERO; - case 2: return osg::Stencil::REPLACE; - case 3: return osg::Stencil::INCR; - case 4: return osg::Stencil::DECR; - case 5: return osg::Stencil::INVERT; - default: - std::cerr << "Unexpected stencil operation: " << op << std::endl; - return osg::Stencil::KEEP; - } - } - // Collect all properties affecting the given node that should be applied to an osg::Material. void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) { @@ -341,6 +268,14 @@ namespace NifOsg class LoaderImpl { public: + /// @param filename used for warning messages. + LoaderImpl(const std::string& filename) + : mFilename(filename) + { + + } + std::string mFilename; + static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { if(nif->numRoots() < 1) @@ -396,7 +331,7 @@ namespace NifOsg } } - static osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) + osg::ref_ptr load(Nif::NIFFilePtr nif, Resource::TextureManager* textureManager) { if (nif->numRoots() < 1) nif->fail("Found no root nodes"); @@ -422,7 +357,7 @@ namespace NifOsg return created; } - static void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } - static osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -574,7 +509,7 @@ namespace NifOsg return transformNode; } - static void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -594,7 +529,7 @@ namespace NifOsg } } - static void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -622,7 +557,7 @@ namespace NifOsg } } - static void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -643,11 +578,11 @@ namespace NifOsg composite->addController(ctrl); } else - std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + std::cerr << "Unexpected material controller " << ctrl->recType << " in " << mFilename << std::endl; } } - static void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) + void handleTextureControllers(const Nif::Property *texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -682,11 +617,11 @@ namespace NifOsg composite->addController(callback); } else - std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + std::cerr << "Unexpected texture controller " << ctrl->recName << " in " << mFilename << std::endl; } } - static void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); @@ -715,7 +650,7 @@ namespace NifOsg // unused } else - std::cerr << "Unhandled particle modifier " << affectors->recName << std::endl; + std::cerr << "Unhandled particle modifier " << affectors->recName << " in " << mFilename << std::endl; } for (; !colliders.empty(); colliders = colliders->extra) { @@ -728,7 +663,7 @@ namespace NifOsg } // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. - static void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -768,7 +703,7 @@ namespace NifOsg partsys->setInitialBound(box); } - static osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) { std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController) @@ -802,7 +737,7 @@ namespace NifOsg return emitter; } - static void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode) { osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); @@ -817,7 +752,7 @@ namespace NifOsg } if (!partctrl) { - std::cerr << "No particle controller found " << std::endl; + std::cerr << "No particle controller found in " << mFilename << std::endl; return; } @@ -853,7 +788,7 @@ namespace NifOsg rootNode->accept(find); if (!find.mFound) { - std::cerr << "can't find emitter node, wrong node order?" << std::endl; + std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; return; } osg::Group* emitterNode = find.mFound; @@ -904,7 +839,7 @@ namespace NifOsg } } - static void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -944,7 +879,7 @@ namespace NifOsg applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - static void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -987,7 +922,7 @@ namespace NifOsg parentNode->addChild(geode); } - static osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) { osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); @@ -1042,7 +977,7 @@ namespace NifOsg return morphGeom; } - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, + void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1094,8 +1029,80 @@ namespace NifOsg parentNode->addChild(frameswitch); } + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) + { + switch(mode) + { + case 0: return osg::BlendFunc::ONE; + case 1: return osg::BlendFunc::ZERO; + case 2: return osg::BlendFunc::SRC_COLOR; + case 3: return osg::BlendFunc::ONE_MINUS_SRC_COLOR; + case 4: return osg::BlendFunc::DST_COLOR; + case 5: return osg::BlendFunc::ONE_MINUS_DST_COLOR; + case 6: return osg::BlendFunc::SRC_ALPHA; + case 7: return osg::BlendFunc::ONE_MINUS_SRC_ALPHA; + case 8: return osg::BlendFunc::DST_ALPHA; + case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; + case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; + default: + std::cerr<< "Unexpected blend mode: "<< mode << " in " << mFilename << std::endl; + return osg::BlendFunc::SRC_ALPHA; + } + } - static void handleProperty(const Nif::Property *property, + osg::AlphaFunc::ComparisonFunction getTestMode(int mode) + { + switch (mode) + { + case 0: return osg::AlphaFunc::ALWAYS; + case 1: return osg::AlphaFunc::LESS; + case 2: return osg::AlphaFunc::EQUAL; + case 3: return osg::AlphaFunc::LEQUAL; + case 4: return osg::AlphaFunc::GREATER; + case 5: return osg::AlphaFunc::NOTEQUAL; + case 6: return osg::AlphaFunc::GEQUAL; + case 7: return osg::AlphaFunc::NEVER; + default: + std::cerr << "Unexpected blend mode: " << mode << " in " << mFilename << std::endl; + return osg::AlphaFunc::LEQUAL; + } + } + + osg::Stencil::Function getStencilFunction(int func) + { + switch (func) + { + case 0: return osg::Stencil::NEVER; + case 1: return osg::Stencil::LESS; + case 2: return osg::Stencil::EQUAL; + case 3: return osg::Stencil::LEQUAL; + case 4: return osg::Stencil::GREATER; + case 5: return osg::Stencil::NOTEQUAL; + case 6: return osg::Stencil::GEQUAL; + case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER + default: + std::cerr << "Unexpected stencil function: " << func << " in " << mFilename << std::endl; + return osg::Stencil::NEVER; + } + } + + osg::Stencil::Operation getStencilOperation(int op) + { + switch (op) + { + case 0: return osg::Stencil::KEEP; + case 1: return osg::Stencil::ZERO; + case 2: return osg::Stencil::REPLACE; + case 3: return osg::Stencil::INCR; + case 4: return osg::Stencil::DECR; + case 5: return osg::Stencil::INVERT; + default: + std::cerr << "Unexpected stencil operation: " << op << " in " << mFilename << std::endl; + return osg::Stencil::KEEP; + } + } + + void handleProperty(const Nif::Property *property, osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) { switch (property->recType) @@ -1207,20 +1214,20 @@ namespace NifOsg && i != Nif::NiTexturingProperty::DarkTexture && i != Nif::NiTexturingProperty::DetailTexture) { - std::cerr << "Warning: unhandled texture stage " << i << std::endl; + std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; continue; } const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; if(tex.texture.empty()) { - std::cerr << "Warning: texture layer " << i << " is in use but empty " << std::endl; + std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl; continue; } const Nif::NiSourceTexture *st = tex.texture.getPtr(); if (!st->external) { - std::cerr << "Warning: unhandled internal texture " << std::endl; + std::cerr << "Warning: unhandled internal texture in " << mFilename << std::endl; continue; } @@ -1284,12 +1291,12 @@ namespace NifOsg break; } default: - std::cerr << "Unhandled " << property->recName << std::endl; + std::cerr << "Unhandled " << property->recName << " in " << mFilename << std::endl; break; } } - static void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, + void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1359,12 +1366,14 @@ namespace NifOsg osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::TextureManager* textureManager) { - return LoaderImpl::load(file, textureManager); + LoaderImpl impl(file->getFilename()); + return impl.load(file, textureManager); } void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl::loadKf(kf, target); + LoaderImpl impl(kf->getFilename()); + impl.loadKf(kf, target); } } From ad46ff7a98fb2bd201e9309b76400f3a7fe61d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:06:04 +0200 Subject: [PATCH 0469/1812] Remove redundant Transform nodes for TriShapes/ParticleSystems with an identity transform --- components/nif/niftypes.hpp | 15 +++++++++++++++ components/nifosg/nifloader.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index d951801452..5827448fdf 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -42,6 +42,15 @@ struct Matrix3 for (int j=0;j<3;++j) mValues[i][j] = (i==j) ? 1.f : 0.f; } + + bool isIdentity() const + { + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + if ((i==j) != (mValues[i][j] == 1)) + return false; + return true; + } }; struct Transformation @@ -62,6 +71,12 @@ struct Transformation return transform; } + bool isIdentity() const + { + return pos == osg::Vec3f(0,0,0) + && rotation.isIdentity() && scale == 1.f; + } + static const Transformation& getIdentity() { static const Transformation identity = { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7aec3385e3..7139bbcef8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -376,6 +376,32 @@ namespace NifOsg toSetup->setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } + void optimize (const Nif::Node* nifNode, osg::Group* node, bool skipMeshes) + { + // For nodes with an identity transform, remove the redundant Transform node + if (node->getDataVariance() == osg::Object::STATIC + // For TriShapes, we can only collapse the node, but not completely remove it, + // if the link to animated collision shapes is supposed to stay intact. + && (nifNode->recType != Nif::RC_NiTriShape || !skipMeshes)) + { + if (node->getNumParents() && nifNode->trafo.isIdentity()) + { + osg::Group* parent = node->getParent(0); + osg::Node* child = node->getChild(0); + child->setUpdateCallback(node->getUpdateCallback()); + child->setStateSet(node->getStateSet()); + child->setName(node->getName()); + // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break + child->setUserDataContainer(node->getUserDataContainer()); + parent->addChild(child); + node->removeChild(child); + parent->removeChild(node); + } + } + // For NiTriShapes *with* a valid transform, perhaps we could apply the transform to the vertices. + // Need to make sure that won't break transparency sorting. Check what the original engine is doing? + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -490,9 +516,15 @@ namespace NifOsg if (composite->getNumControllers() > 0) transformNode->addUpdateCallback(composite); + + // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). + // We can take advantage of this constraint for optimizations later. if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Optimization pass + optimize(nifNode, transformNode, skipMeshes); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { From ec25f1da95d0ce1879c1f165e6329bc0be8a70ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:17:57 +0200 Subject: [PATCH 0470/1812] Fix ParticleSystem bug introduced by last commit --- components/nifosg/nifloader.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7139bbcef8..69e71cce44 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -387,14 +387,23 @@ namespace NifOsg if (node->getNumParents() && nifNode->trafo.isIdentity()) { osg::Group* parent = node->getParent(0); - osg::Node* child = node->getChild(0); - child->setUpdateCallback(node->getUpdateCallback()); - child->setStateSet(node->getStateSet()); - child->setName(node->getName()); - // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break - child->setUserDataContainer(node->getUserDataContainer()); - parent->addChild(child); - node->removeChild(child); + + // can be multiple children in case of ParticleSystems, with the extra ParticleSystemUpdater node + for (unsigned int i=0; igetNumChildren(); ++i) + { + osg::Node* child = node->getChild(i); + if (i == node->getNumChildren()-1) // FIXME: some nicer way to determine where our actual Drawable resides... + { + child->setUpdateCallback(node->getUpdateCallback()); + child->setStateSet(node->getStateSet()); + child->setName(node->getName()); + // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break + child->setUserDataContainer(node->getUserDataContainer()); + } + parent->addChild(child); + } + + node->removeChildren(0, node->getNumChildren()); parent->removeChild(node); } } From b79ab1a3b847e3f457b6c32c81f81f8f1fc0502b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:22:52 +0200 Subject: [PATCH 0471/1812] Fix InverseWorldMatrix bug introduced by last commit --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 69e71cce44..40eedad515 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -394,7 +394,7 @@ namespace NifOsg osg::Node* child = node->getChild(i); if (i == node->getNumChildren()-1) // FIXME: some nicer way to determine where our actual Drawable resides... { - child->setUpdateCallback(node->getUpdateCallback()); + child->addUpdateCallback(node->getUpdateCallback()); child->setStateSet(node->getStateSet()); child->setName(node->getName()); // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break From d7a4a9fd66f2eaf03da816692a07b6b621f7c86a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 15:25:45 +0200 Subject: [PATCH 0472/1812] Create NIF root nodes as Group instead of Transform when possible --- components/nifosg/nifloader.cpp | 56 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 40eedad515..91dea6ef2d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -414,12 +414,7 @@ namespace NifOsg osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { - osg::ref_ptr transformNode = new osg::MatrixTransform(nifNode->trafo.toMatrix()); - - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode->addCullCallback(new BillboardCallback); - } + osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); // Set a default DataVariance (used as hint by optimization routines). switch (nifNode->recType) @@ -429,21 +424,34 @@ namespace NifOsg case Nif::RC_NiRotatingParticles: // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. // No support for keyframe controllers (just crashes in the original engine). - transformNode->setDataVariance(osg::Object::STATIC); + node->setDataVariance(osg::Object::STATIC); break; default: // could have new children attached at any time, or added external keyframe controllers from .kf files - transformNode->setDataVariance(osg::Object::DYNAMIC); + node->setDataVariance(osg::Object::DYNAMIC); break; } - transformNode->setName(nifNode->name); + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + node->addCullCallback(new BillboardCallback); + } + else if (!rootNode && nifNode->controller.empty() && nifNode->trafo.isIdentity()) + { + // The Root node can be created as a Group if no transformation is required. + // This takes advantage of the fact root nodes can't have additional controllers + // loaded from an external .kf file (original engine just throws "can't find node" errors if you try). + node = new osg::Group; + node->setDataVariance(osg::Object::STATIC); + } + + node->setName(nifNode->name); if (parentNode) - parentNode->addChild(transformNode); + parentNode->addChild(node); if (!rootNode) - rootNode = transformNode; + rootNode = node; // UserData used for a variety of features: // - finding the correct emitter node for a particle system @@ -451,7 +459,7 @@ namespace NifOsg // - finding a random child NiNode in NiBspArrayController // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to // change only certain elements of the 4x4 transform - transformNode->getOrCreateUserDataContainer()->addUserObject( + node->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) @@ -485,7 +493,7 @@ namespace NifOsg { skipMeshes = true; // Leave mask for UpdateVisitor enabled - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } // We can skip creating meshes for hidden nodes if they don't have a VisController that @@ -500,39 +508,39 @@ namespace NifOsg skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating collision shapes // now hide this node, but leave the mask for UpdateVisitor enabled so that KeyframeController works - transformNode->setNodeMask(0x1); + node->setNodeMask(0x1); } osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, transformNode, composite, textureManager, boundTextures, animflags); + applyNodeProperties(nifNode, node, composite, textureManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (triShape->skin.empty()) - handleTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleTriShape(triShape, node, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, composite, boundTextures, animflags); + handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) - handleParticleSystem(nifNode, transformNode, composite, animflags, particleflags, rootNode); + handleParticleSystem(nifNode, node, composite, animflags, particleflags, rootNode); if (composite->getNumControllers() > 0) - transformNode->addUpdateCallback(composite); + node->addUpdateCallback(composite); // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). // We can take advantage of this constraint for optimizations later. - if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode, animflags); + if (!nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) + handleNodeControllers(nifNode, static_cast(node.get()), animflags); // Optimization pass - optimize(nifNode, transformNode, skipMeshes); + optimize(nifNode, node, skipMeshes); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -542,12 +550,12 @@ namespace NifOsg { if(!children[i].empty()) { - handleNode(children[i].getPtr(), transformNode, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); + handleNode(children[i].getPtr(), node, textureManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); } } } - return transformNode; + return node; } void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) From 07937c741a4321f57668d3a61701336fbfe77f7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 16:19:05 +0200 Subject: [PATCH 0473/1812] Improve exception handling when starting a new game from the main menu --- apps/openmw/mwstate/statemanagerimp.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index ce4d8f9581..7c111a090c 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -139,11 +139,28 @@ void MWState::StateManager::newGame (bool bypass) if (!bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); - MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); + try + { + MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); - MWBase::Environment::get().getWorld()->startNewGame (bypass); + MWBase::Environment::get().getWorld()->startNewGame (bypass); - mState = State_Running; + mState = State_Running; + } + catch (std::exception& e) + { + std::stringstream error; + error << "Failed to start new game: " << e.what(); + + std::cerr << error.str() << std::endl; + cleanup (true); + + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); + } } void MWState::StateManager::endGame() From 1d198a5592e0d4d6f3a4d0b7388d87f5e29b3482 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:09:01 +0200 Subject: [PATCH 0474/1812] Keep the light list StateSet cache for more than one frame --- components/sceneutil/lightmanager.cpp | 23 +++++++++++++++-------- components/sceneutil/lightmanager.hpp | 17 +++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 6040f95364..65955d9afc 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -145,7 +145,6 @@ namespace SceneUtil { mLightsInViewSpace = false; mLights.clear(); - mStateSetCache.clear(); } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -180,7 +179,7 @@ namespace SceneUtil // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; igetId()); LightStateSetMap::iterator found = mStateSetCache.find(hash); if (found != mStateSetCache.end()) @@ -190,10 +189,7 @@ namespace SceneUtil std::vector > lights; for (unsigned int i=0; igetLight()); - } + lights.push_back(lightList[i]->getLight()); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -223,11 +219,22 @@ namespace SceneUtil return mStartLight; } + static int sLightId = 0; + LightSource::LightSource() : mRadius(0.f) { setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); + mId = sLightId++; + } + + LightSource::LightSource(const LightSource ©, const osg::CopyOp ©op) + : osg::Node(copy, copyop) + , mLight(copy.mLight) + , mRadius(copy.mRadius) + { + mId = sLightId++; } void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) @@ -282,12 +289,12 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + std::vector lightList; for (unsigned int i=0; i& getLights() const; - // Stores indices into the mLights vector - typedef std::vector LightList; + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); From acf9fc2d370ef2b782937295def48c17a685ba8e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:15:26 +0200 Subject: [PATCH 0475/1812] Enable per-frame light list updates (Bug #2638, Bug #2654) The performance impact isn't so big anymore since the last commit. --- components/sceneutil/lightmanager.cpp | 77 +++++++++++---------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 65955d9afc..713524a418 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -274,59 +274,44 @@ namespace SceneUtil if (lights.size()) { + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) + std::vector lightList; + for (unsigned int i=0; isecond; - } - else{ - - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; - - // TODO: sort lights by certain criteria - - while (lightList.size() > maxLights) - lightList.pop_back(); - } - - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; + const LightManager::LightSourceTransform& l = lights[i]; + if (l.mViewBound.intersects(nodeBound)) + lightList.push_back(l.mLightSource); } - if (stateset) - cv->pushStateSet(stateset); + if (lightList.empty()) + { + traverse(node, nv); + return; + } + + unsigned int maxLights = static_cast (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > maxLights) + lightList.pop_back(); + } + + osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); + + cv->pushStateSet(stateset); traverse(node, nv); - if (stateset) - cv->popStateSet(); + cv->popStateSet(); } else traverse(node, nv); From 18f4eaa8dcb188d7f9399352542326455c5ca577 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 18:56:40 +0200 Subject: [PATCH 0476/1812] Preliminary handling for overflowing light lists --- components/sceneutil/lightmanager.cpp | 37 +++++++++++++++++++++------ components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 713524a418..444530dbe0 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -179,7 +179,7 @@ namespace SceneUtil // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; igetId()); + boost::hash_combine(hash, lightList[i]->mLightSource->getId()); LightStateSetMap::iterator found = mStateSetCache.find(hash); if (found != mStateSetCache.end()) @@ -189,7 +189,7 @@ namespace SceneUtil std::vector > lights; for (unsigned int i=0; igetLight()); + lights.push_back(lightList[i]->mLightSource->getLight()); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -237,6 +237,12 @@ namespace SceneUtil mId = sLightId++; } + + bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) + { + return left->mViewBound.center().length2() < right->mViewBound.center().length2(); + } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) { osgUtil::CullVisitor* cv = static_cast(nv); @@ -279,12 +285,12 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + std::vector lightList; for (unsigned int i=0; i maxLights) { - //std::cerr << "More than 8 lights!" << std::endl; + // remove lights culled by this camera + for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end();) + { + osg::CullStack::CullingStack& stack = cv->getProjectionCullingStack(); - // TODO: sort lights by certain criteria + if (stack.back().isCulled(osg::BoundingSphere((*it)->mViewBound.center(), (*it)->mViewBound.radius()*2))) + { + it = lightList.erase(it); + continue; + } + else + ++it; + } - while (lightList.size() > maxLights) - lightList.pop_back(); + if (lightList.size() > maxLights) + { + // sort by proximity to camera, then get rid of furthest away lights + std::sort(lightList.begin(), lightList.end(), sortLights); + while (lightList.size() > maxLights) + lightList.pop_back(); + } } osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ac819958f7..f338e42ecb 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -85,7 +85,7 @@ namespace SceneUtil const std::vector& getLights() const; - typedef std::vector LightList; + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); From aad8e7b6d0a832e5aa9f874f65aa85a4dd133de7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 19:37:44 +0200 Subject: [PATCH 0477/1812] Light culling fix --- components/sceneutil/lightmanager.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 444530dbe0..bcdb4af88e 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -145,6 +145,10 @@ namespace SceneUtil { mLightsInViewSpace = false; mLights.clear(); + + // do an occasional cleanup for orphaned lights + if (mStateSetCache.size() > 5000) + mStateSetCache.clear(); } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -304,11 +308,14 @@ namespace SceneUtil if (lightList.size() > maxLights) { // remove lights culled by this camera - for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end();) + for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; ) { - osg::CullStack::CullingStack& stack = cv->getProjectionCullingStack(); + osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack(); - if (stack.back().isCulled(osg::BoundingSphere((*it)->mViewBound.center(), (*it)->mViewBound.radius()*2))) + osg::BoundingSphere bs = (*it)->mViewBound; + bs._radius = bs._radius*2; + osg::CullingSet& cullingSet = stack.front(); + if (cullingSet.isCulled(bs)) { it = lightList.erase(it); continue; From 2d072aab2dee052e1657b9648d72d72c019c54c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 22:42:14 +0200 Subject: [PATCH 0478/1812] Broken bone references from .kf files are no longer a fatal error (Bug #2687) --- apps/openmw/mwrender/animation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 62d50df0d6..9337b5a511 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -347,7 +347,10 @@ namespace MWRender std::string bonename = Misc::StringUtils::lowerCase(it->first); NodeMap::const_iterator found = mNodeMap.find(bonename); if (found == mNodeMap.end()) - throw std::runtime_error("addAnimSource: can't find bone " + bonename); + { + std::cerr << "addAnimSource: can't find bone '" + bonename << "' in " << model << " (referenced by " << kfname << ")" << std::endl; + continue; + } osg::Node* node = found->second; From b73947033d2ca0494da5d4b56c8b592b4b02bc2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 16:33:31 +0200 Subject: [PATCH 0479/1812] Rotate sky meshes --- apps/openmw/mwrender/sky.cpp | 75 +++++++++++++++++++----------------- apps/openmw/mwrender/sky.hpp | 6 ++- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0cd1f64d2f..07e4332085 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -204,20 +204,6 @@ public: } }; -class DisableCullingVisitor : public osg::NodeVisitor -{ -public: - DisableCullingVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - void apply(osg::Geode &geode) - { - geode.setCullingActive(false); - } -}; - class ModVertexAlphaVisitor : public osg::NodeVisitor { public: @@ -483,6 +469,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) + , mAtmosphereNightRoll(0.f) , mCreated(false) , mMoonRed(false) , mIsStorm(false) @@ -528,14 +515,18 @@ void SkyManager::create() mAtmosphereUpdater = new AtmosphereUpdater; mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); + mAtmosphereNightNode = new osg::PositionAttitudeTransform; + mAtmosphereNightNode->setNodeMask(0); + mRootNode->addChild(mAtmosphereNightNode); + + osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) - mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); + atmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mAtmosphereNightNode); else - mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode); - mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + atmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mAtmosphereNightNode); + atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); - mAtmosphereNight->accept(modStars); - mAtmosphereNight->setNodeMask(0); + atmosphereNight->accept(modStars); mSun.reset(new Sun(mRootNode, mSceneManager)); @@ -543,14 +534,16 @@ void SkyManager::create() mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); - mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); + mCloudNode = new osg::PositionAttitudeTransform; + mRootNode->addChild(mCloudNode); + osg::ref_ptr clouds = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); - mCloudNode->accept(modClouds); + clouds->accept(modClouds); mCloudUpdater = new CloudUpdater; - mCloudNode->addUpdateCallback(mCloudUpdater); + clouds->addUpdateCallback(mCloudUpdater); - mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + clouds->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -594,12 +587,18 @@ void SkyManager::updateRain(float dt) void SkyManager::update(float duration) { if (!mEnabled) return; - //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - //if (mIsStorm) - // mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - //else - // mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); + if (mIsStorm) + { + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); + + if (mParticleNode) + mParticleNode->setAttitude(quat); + mCloudNode->setAttitude(quat); + } + else + mCloudNode->setAttitude(osg::Quat()); updateRain(duration); @@ -611,6 +610,7 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); //mMasser->setColour (ColourValue(1,1,1,1)); @@ -641,7 +641,9 @@ void SkyManager::update(float duration) } // rotate the stars by 360 degrees every 4 days - //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); + mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f); + if (mAtmosphereNightNode->getNodeMask() != 0) + mAtmosphereNightNode->setAttitude(osg::Quat(mAtmosphereNightRoll, osg::Vec3f(0,0,1))); } void SkyManager::setEnabled(bool enabled) @@ -678,15 +680,18 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { - if (mParticleEffect) - mRootNode->removeChild(mParticleEffect); + if (mParticleNode) + mRootNode->removeChild(mParticleNode); mParticleEffect = NULL; } else { - mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode); - DisableCullingVisitor visitor; - mParticleEffect->accept(visitor); + if (!mParticleNode) + { + mParticleNode = new osg::PositionAttitudeTransform; + mRootNode->addChild(mParticleNode); + } + mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); @@ -757,7 +762,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } } - //mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); /* diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index d7cd88de57..e11f20c181 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -93,15 +93,17 @@ namespace MWRender osg::ref_ptr mRootNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; - osg::ref_ptr mCloudNode; + osg::ref_ptr mCloudNode; osg::ref_ptr mCloudUpdater; osg::ref_ptr mAtmosphereDay; - osg::ref_ptr mAtmosphereNight; + osg::ref_ptr mAtmosphereNightNode; + float mAtmosphereNightRoll; osg::ref_ptr mAtmosphereUpdater; From 3da8f6e62ea87252daec614200c113ad386fe21b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 20:36:48 +0200 Subject: [PATCH 0480/1812] Water ripples --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 29 +++- apps/openmw/mwrender/renderingmanager.hpp | 11 +- apps/openmw/mwrender/ripplesimulation.cpp | 202 ++++++++++++++++++++++ apps/openmw/mwrender/ripplesimulation.hpp | 76 ++++++++ apps/openmw/mwrender/water.cpp | 22 ++- apps/openmw/mwrender/water.hpp | 18 +- apps/openmw/mwworld/fallback.cpp | 1 + apps/openmw/mwworld/scene.cpp | 5 + apps/openmw/mwworld/worldimp.cpp | 3 +- 10 files changed, 355 insertions(+), 14 deletions(-) create mode 100644 apps/openmw/mwrender/ripplesimulation.cpp create mode 100644 apps/openmw/mwrender/ripplesimulation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 265fb43e82..cd1ac31ec5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,7 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4db776783a..5cbcaab83b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -114,7 +114,7 @@ namespace MWRender bool mWireframe; }; - RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -136,7 +136,7 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation())); + mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback)); mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); @@ -265,6 +265,8 @@ namespace MWRender if (store->getCell()->isExterior()) mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); + + mWater->removeCell(store); } void RenderingManager::setSkyEnabled(bool enabled) @@ -330,6 +332,7 @@ namespace MWRender { mEffectManager->update(dt); mSky->update(dt); + mWater->update(dt); mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -354,6 +357,11 @@ namespace MWRender mCamera->attachTo(ptr); } + void RenderingManager::removePlayer(const MWWorld::Ptr &player) + { + mWater->removeEmitter(player); + } + void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) { if(ptr == mCamera->getTrackingPtr() && @@ -378,6 +386,7 @@ namespace MWRender void RenderingManager::removeObject(const MWWorld::Ptr &ptr) { mObjects->removeObject(ptr); + mWater->removeEmitter(ptr); } void RenderingManager::setWaterEnabled(bool enabled) @@ -579,7 +588,7 @@ namespace MWRender void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); - //mWater->clearRipples(); + mWater->clearRipples(); } void RenderingManager::clear() @@ -613,6 +622,8 @@ namespace MWRender mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); player.getRefData().setBaseNode(mPlayerNode); + + mWater->addEmitter(player); } void RenderingManager::renderPlayer(const MWWorld::Ptr &player) @@ -621,8 +632,6 @@ namespace MWRender mCamera->setAnimation(mPlayerAnimation.get()); mCamera->attachTo(player); - //mWater->removeEmitter(ptr); - //mWater->addEmitter(ptr); } void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) @@ -643,6 +652,16 @@ namespace MWRender } } + void RenderingManager::addWaterRippleEmitter(const MWWorld::Ptr &ptr) + { + mWater->addEmitter(ptr); + } + + void RenderingManager::removeWaterRippleEmitter(const MWWorld::Ptr &ptr) + { + mWater->removeEmitter(ptr); + } + void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a37203cc22..302073e4dc 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -37,6 +37,11 @@ namespace Terrain class World; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { @@ -52,7 +57,7 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); ~RenderingManager(); MWRender::Objects& getObjects(); @@ -125,8 +130,12 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); Animation* getPlayerAnimation(); + void addWaterRippleEmitter(const MWWorld::Ptr& ptr); + void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); + void updatePlayerPtr(const MWWorld::Ptr &ptr); + void removePlayer(const MWWorld::Ptr& player); void setupPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp new file mode 100644 index 0000000000..a3e96a5b15 --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -0,0 +1,202 @@ +#include "ripplesimulation.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vismask.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwworld/fallback.hpp" + +namespace +{ + void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) + { + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + if (rippleFrameCount <= 0) + return; + + std::string tex = fallback->getFallbackString("Water_RippleTexture"); + + std::vector > textures; + for (int i=0; igetTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + + osg::ref_ptr stateset (new osg::StateSet); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + + osg::ref_ptr mat (new osg::Material); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); + mat->setColorMode(osg::Material::DIFFUSE); + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + + node->setStateSet(stateset); + } +} + +namespace MWRender +{ + +RippleSimulation::RippleSimulation(osg::Group *parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) + : mParent(parent) +{ + osg::ref_ptr geode (new osg::Geode); + + mParticleSystem = new osgParticle::ParticleSystem; + geode->addDrawable(mParticleSystem); + + mParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); + mParticleSystem->setAlignVectorX(osg::Vec3f(1,0,0)); + mParticleSystem->setAlignVectorY(osg::Vec3f(0,1,0)); + + osgParticle::Particle& particleTemplate = mParticleSystem->getDefaultParticleTemplate(); + particleTemplate.setSizeRange(osgParticle::rangef(15, 180)); + particleTemplate.setColorRange(osgParticle::rangev4(osg::Vec4f(1,1,1,0.7), osg::Vec4f(1,1,1,0.7))); + particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 0.f)); + particleTemplate.setAngularVelocity(osg::Vec3f(0,0,fallback->getFallbackFloat("Water_RippleRotSpeed"))); + particleTemplate.setLifeTime(fallback->getFallbackFloat("Water_RippleLifetime")); + + osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); + updater->addParticleSystem(mParticleSystem); + + mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->addChild(updater); + mParticleNode->addChild(geode); + mParticleNode->setNodeMask(Mask_Effect); + + createWaterRippleStateSet(resourceSystem, fallback, mParticleNode); + + mParent->addChild(mParticleNode); +} + +RippleSimulation::~RippleSimulation() +{ + mParent->removeChild(mParticleNode); +} + +void RippleSimulation::update(float dt) +{ + for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) + { + if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) + { + // fetch a new ptr (to handle cell change etc) + // for non-player actors this is done in updateObjectCell + it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + } + + osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); + currentPos.z() = 0; // Z is set by the Scene Node + + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) + { + it->mLastEmitPosition = currentPos; + + if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) + continue; // TODO: remove the oldest particle to make room? + + osgParticle::Particle* p = mParticleSystem->createParticle(NULL); + p->setPosition(currentPos); + p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + } + } +} + + +void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +{ + Emitter newEmitter; + newEmitter.mPtr = ptr; + newEmitter.mScale = scale; + newEmitter.mForce = force; + newEmitter.mLastEmitPosition = osg::Vec3f(0,0,0); + mEmitters.push_back (newEmitter); +} + +void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == ptr) + { + mEmitters.erase(it); + return; + } + } +} + +void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == old) + { + it->mPtr = ptr; + return; + } + } +} + +void RippleSimulation::removeCell(const MWWorld::CellStore *store) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) + { + if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + it = mEmitters.erase(it); + } + else + ++it; + } +} + +void RippleSimulation::setWaterHeight(float height) +{ + mParticleNode->setPosition(osg::Vec3f(0,0,height)); +} + +void RippleSimulation::clear() +{ + for (int i=0; inumParticles(); ++i) + mParticleSystem->destroyParticle(i); +} + + + +} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp new file mode 100644 index 0000000000..98c8a707dc --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -0,0 +1,76 @@ +#ifndef OPENMW_MWRENDER_RIPPLESIMULATION_H +#define OPENMW_MWRENDER_RIPPLESIMULATION_H + +#include + +#include "../mwworld/ptr.hpp" + +namespace osg +{ + class Group; +} + +namespace osgParticle +{ + class ParticleSystem; +} + +namespace Resource +{ + class ResourceSystem; +} + +namespace MWWorld +{ + class Fallback; +} + +namespace MWRender +{ + + struct Emitter + { + MWWorld::Ptr mPtr; + osg::Vec3f mLastEmitPosition; + float mScale; + float mForce; + }; + + class RippleSimulation + { + public: + RippleSimulation(osg::Group* parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); + ~RippleSimulation(); + + /// @param dt Time since the last frame + void update(float dt); + + /// adds an emitter, position will be tracked automatically + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void removeCell(const MWWorld::CellStore* store); + + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); + + /// Remove all active ripples + void clear(); + + private: + osg::ref_ptr mParent; + Resource::ResourceSystem* mResourceSystem; + + osg::ref_ptr mParticleSystem; + osg::ref_ptr mParticleNode; + + std::vector mEmitters; + + float mRippleLifeTime; + float mRippleRotSpeed; + + }; + +} + +#endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c2149358bd..3b07f35ba0 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -18,6 +18,7 @@ #include #include "vismask.hpp" +#include "ripplesimulation.hpp" namespace { @@ -107,13 +108,15 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback) : mParent(parent) , mResourceSystem(resourceSystem) , mEnabled(true) , mToggled(true) , mTop(0) { + mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); osg::ref_ptr geode (new osg::Geode); @@ -161,6 +164,11 @@ void Water::setHeight(const float height) mWaterNode->setPosition(pos); } +void Water::update(float dt) +{ + mSimulation->update(dt); +} + void Water::updateVisible() { mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); @@ -183,7 +191,6 @@ osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } -/* void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mSimulation->addEmitter (ptr, scale, force); @@ -198,6 +205,15 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) { mSimulation->updateEmitterPtr(old, ptr); } -*/ + +void Water::removeCell(const MWWorld::CellStore *store) +{ + mSimulation->removeCell(store); +} + +void Water::clearRipples() +{ + mSimulation->clear(); +} } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index d389392ba8..519cd51819 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -21,9 +21,16 @@ namespace Resource class ResourceSystem; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { + class RippleSimulation; + /// Water rendering class Water { @@ -34,6 +41,8 @@ namespace MWRender Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; + std::auto_ptr mSimulation; + bool mEnabled; bool mToggled; float mTop; @@ -42,7 +51,7 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback); ~Water(); void setEnabled(bool enabled); @@ -51,16 +60,19 @@ namespace MWRender bool isUnderwater(const osg::Vec3f& pos) const; - /* /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); - */ + void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell + + void clearRipples(); void changeCell(const MWWorld::CellStore* store); void setHeight(const float height); + void update(float dt); + }; } diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index fd60224813..e810f8241b 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -58,4 +58,5 @@ namespace MWWorld return osg::Vec4f(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f, 1.f); } } + } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 76c2f6ebac..db26b4f2a4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -39,6 +39,9 @@ namespace model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); ptr.getClass().insertObject (ptr, model, physics); + + if (ptr.getClass().isActor()) + rendering.addWaterRippleEmitter(ptr); } void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, @@ -570,6 +573,8 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->remove(ptr); mRendering.removeObject (ptr); + if (ptr.getClass().isActor()) + mRendering.removeWaterRippleEmitter(ptr); } bool Scene::isCellActive(const CellStore &cell) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 16dcadb231..4743b3ad9d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -161,7 +161,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); - mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); @@ -2064,6 +2064,7 @@ namespace MWWorld // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); mPhysics->remove(getPlayerPtr()); + mRendering->removePlayer(getPlayerPtr()); mPlayer->set(player); } From 1c151f2f0a67f34db34a0a703112f7531f582f51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 20:56:48 +0200 Subject: [PATCH 0481/1812] Re-enable some outcommented sky code --- apps/openmw/mwrender/renderingmanager.cpp | 22 ++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 5 ++++ apps/openmw/mwrender/sky.cpp | 6 ---- apps/openmw/mwrender/sky.hpp | 1 - apps/openmw/mwworld/worldimp.cpp | 35 +++++++---------------- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5cbcaab83b..478cadb74f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -219,6 +219,26 @@ namespace MWRender updateAmbient(); } + void RenderingManager::skySetDate(int day, int month) + { + mSky->setDate(day, month); + } + + int RenderingManager::skyGetMasserPhase() const + { + return mSky->getMasserPhase(); + } + + int RenderingManager::skyGetSecundaPhase() const + { + return mSky->getSecundaPhase(); + } + + void RenderingManager::skySetMoonColour(bool red) + { + mSky->setMoonColour(red); + } + void RenderingManager::configureAmbient(const ESM::Cell *cell) { setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); @@ -593,6 +613,8 @@ namespace MWRender void RenderingManager::clear() { + mSky->setMoonColour(false); + notifyWorldSpaceChanged(); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 302073e4dc..fc2f5a4f38 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -68,6 +68,11 @@ namespace MWRender void setAmbientColour(const osg::Vec4f& colour); + void skySetDate(int day, int month); + int skyGetMasserPhase() const; + int skyGetSecundaPhase() const; + void skySetMoonColour(bool red); + void setSunDirection(const osg::Vec3f& direction); void setSunColour(const osg::Vec4f& colour); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 07e4332085..4b70c81ab6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -473,7 +473,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mCreated(false) , mMoonRed(false) , mIsStorm(false) - , mHour(0.0f) , mDay(0) , mMonth(0) , mCloudAnimationTimer(0.f) @@ -886,11 +885,6 @@ void SkyManager::setSecundaFade(const float fade) mSecunda->setAlpha(fade); } -void SkyManager::setHour(double hour) -{ - mHour = static_cast(hour); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e11f20c181..f097029d1a 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -117,7 +117,6 @@ namespace MWRender bool mIsStorm; - float mHour; int mDay; int mMonth; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4743b3ad9d..0d6a8ef47c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -134,9 +134,8 @@ namespace MWWorld { if (mSky && (isCellExterior() || isCellQuasiExterior())) { - //mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); - //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - // mGlobalVariables["month"].getInteger()); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + mGlobalVariables["month"].getInteger()); mRendering->setSkyEnabled(true); } @@ -812,8 +811,6 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - //mRendering->skySetHour (hour); - mWeatherManager->setHour(static_cast(hour)); if (days>0) @@ -849,7 +846,7 @@ namespace MWWorld mGlobalVariables["day"].setInteger (day); mGlobalVariables["month"].setInteger (month); - //mRendering->skySetDate (day, month); + mRendering->skySetDate(day, month); } void World::setMonth (int month) @@ -870,7 +867,7 @@ namespace MWWorld if (years>0) mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); - //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); } int World::getDay() const @@ -916,36 +913,24 @@ namespace MWWorld bool World::toggleSky() { -#if 0 - if (mSky) - { - mSky = false; - mRendering->skyDisable(); - return false; - } - else - { - mSky = true; - mRendering->skyEnable(); - return true; - } -#endif - return 0; + mSky = !mSky; + mRendering->setSkyEnabled(mSky); + return mSky; } int World::getMasserPhase() const { - return 0;//mRendering->skyGetMasserPhase(); + return mRendering->skyGetMasserPhase(); } int World::getSecundaPhase() const { - return 0;//mRendering->skyGetSecundaPhase(); + return mRendering->skyGetSecundaPhase(); } void World::setMoonColour (bool red) { - //mRendering->skySetMoonColour (red); + mRendering->skySetMoonColour (red); } float World::getTimeScaleFactor() const From 6199c0bbc5049b8450e6c1b583ca027c876ce4da Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Jun 2015 23:50:19 +0200 Subject: [PATCH 0482/1812] Use osgDB::SharedStateManager for sharing of StateSets across NIF files --- components/resource/scenemanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index bb4c57e4c0..de4e2bd1c5 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -8,6 +8,9 @@ #include +#include +#include + #include #include @@ -103,6 +106,9 @@ namespace Resource NifOsg::Loader loader; osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); + // TODO: run SharedStateManager::prune on unload + if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); From 7b35882814b9c3ff5e6dfd09c6bfe957832bfe02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 15:13:17 +0200 Subject: [PATCH 0483/1812] RemoveParticlesVisitor fix --- apps/openmw/mwrender/objects.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 2eb72dfd2a..39e9f56520 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -35,12 +35,26 @@ namespace virtual void apply(osg::Node &node) { - if (dynamic_cast(&node) || dynamic_cast(&node)) + if (dynamic_cast(&node)) mToRemove.push_back(&node); traverse(node); } + virtual void apply(osg::Geode& geode) + { + std::vector partsysVector; + for (unsigned int i=0; i(drw)) + partsysVector.push_back(partsys); + } + + for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) + geode.removeDrawable(*it); + } + void remove() { for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) From b648722d3b26f12649bc33dcb88e48e539db4ffa Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 15:13:41 +0200 Subject: [PATCH 0484/1812] Don't use the ParticleSystem for computing placeable bounds (Bug #2700) --- apps/openmw/mwrender/vismask.hpp | 5 ++++- apps/openmw/mwworld/worldimp.cpp | 2 ++ components/resource/scenemanager.cpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index b794ac24a9..38fcfe6487 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -22,8 +22,11 @@ namespace MWRender Mask_Scene = (1<<8), Mask_GUI = (1<<9), + // Set on a Geode + Mask_ParticleSystem = (1<<10), + // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<10) + Mask_RenderToTexture = (1<<11) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0d6a8ef47c..6b43ae74f3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -37,6 +37,7 @@ #include "../mwrender/animation.hpp" #include "../mwrender/renderingmanager.hpp" #include "../mwrender/camera.hpp" +#include "../mwrender/vismask.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" @@ -1862,6 +1863,7 @@ namespace MWWorld { // Adjust position so the location we wanted ends up in the middle of the object bounding box osg::ComputeBoundsVisitor computeBounds; + computeBounds.setTraversalMask(~MWRender::Mask_ParticleSystem); dropped.getRefData().getBaseNode()->accept(computeBounds); osg::BoundingBox bounds = computeBounds.getBoundingBox(); if (bounds.valid()) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index de4e2bd1c5..6f38c41c4a 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -47,6 +47,7 @@ namespace if (geode->getNumParents() && geode->getParent(0)->getNumParents()) transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); } + geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem } } } From 934166a853411279cb8ffefc6f81ea7dc2798f88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 17:55:15 +0200 Subject: [PATCH 0485/1812] Ignore the alpha value for particle materials (Bug #2699) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 91dea6ef2d..e2db3d52bb 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -866,8 +866,8 @@ namespace NifOsg osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,diffuse.a())); + // NB ignoring diffuse.a() + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); mat->setColorMode(osg::Material::AMBIENT); } From b543308e3e63c21abe56e9ef570d3c4c830ad78f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 18:16:05 +0200 Subject: [PATCH 0486/1812] Remove an already resolved todo comment --- apps/openmw/mwrender/globalmap.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 9109be799a..890c8444a2 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -274,7 +274,6 @@ namespace MWRender image->setDataType(mOverlayImage->getDataType()); camera->attach(osg::Camera::COLOR_BUFFER, image); - // FIXME: why does the image get slightly darker by the read back? ImageDest imageDest; imageDest.mImage = image; imageDest.mX = x; From 3ebfb4e0d9b8731b2cc0e6c72ad86496eb1bcdf3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 18:22:31 +0200 Subject: [PATCH 0487/1812] Ignore particle systems in getScreenBounds --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9337b5a511..8c1b3c0a9a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1007,6 +1007,7 @@ namespace MWRender else { osg::ComputeBoundsVisitor computeBound; + computeBound.setTraversalMask(~Mask_ParticleSystem); parent->accept(computeBound); // PositionAttitudeTransform seems to be slightly faster than MatrixTransform diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 478cadb74f..7f76adb288 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -484,6 +484,7 @@ namespace MWRender return osg::Vec4f(); osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(~MWRender::Mask_ParticleSystem); ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); From 81a4a6da6bbde93bece0355e2310094714d6f14c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 20:32:10 +0200 Subject: [PATCH 0488/1812] Make better use of the available texture units (Bug #2702) Nvidia drivers only support a maximum of 4 fixed function texture units. To resolve this problem, bind texture units in order instead of binding to the NiTexturingProperty::TextureType unit. --- components/nifosg/nifloader.cpp | 52 ++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e2db3d52bb..d8920646d1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -344,7 +344,7 @@ namespace NifOsg osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::map(), 0, 0, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, NULL, textureManager, std::vector(), 0, 0, false, &textkeys->mTextKeys); if (nif->getUseSkinning()) { @@ -357,7 +357,7 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, - std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) + std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); @@ -558,7 +558,7 @@ namespace NifOsg return node; } - void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -568,8 +568,8 @@ namespace NifOsg { const Nif::NiUVController *uvctrl = static_cast(ctrl.getPtr()); std::set texUnits; - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) - texUnits.insert(it->first); + for (unsigned int i=0; i ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); @@ -888,7 +888,7 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -898,10 +898,10 @@ namespace NifOsg geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); } - for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) + int textureStage = 0; + for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) { - int textureStage = it->first; - int uvSet = it->second; + int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently @@ -928,7 +928,7 @@ namespace NifOsg applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map& boundTextures, int animflags) + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -1027,7 +1027,7 @@ namespace NifOsg } void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, - const std::map& boundTextures, int animflags) + const std::vector& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1152,7 +1152,7 @@ namespace NifOsg } void handleProperty(const Nif::Property *property, - osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map& boundTextures, int animflags) + osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector& boundTextures, int animflags) { switch (property->recType) { @@ -1254,6 +1254,15 @@ namespace NifOsg { const Nif::NiTexturingProperty* texprop = static_cast(property); osg::StateSet* stateset = node->getOrCreateStateSet(); + + if (boundTextures.size()) + { + // overriding a parent NiTexturingProperty, so remove what was previously bound + for (unsigned int i=0; isetTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF); + boundTextures.clear(); + } + for (int i=0; itextures[i].inUse) @@ -1290,19 +1299,21 @@ namespace NifOsg wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); + int texUnit = boundTextures.size(); + + stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON); if (i == Nif::NiTexturingProperty::GlowTexture) { osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::ADD); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DarkTexture) { osg::TexEnv* texEnv = new osg::TexEnv; texEnv->setMode(osg::TexEnv::MODULATE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DetailTexture) { @@ -1318,15 +1329,10 @@ namespace NifOsg texEnv->setOperand1_RGB(GL_SRC_COLOR); texEnv->setSource0_RGB(GL_PREVIOUS_ARB); texEnv->setSource1_RGB(GL_TEXTURE); - stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } - boundTextures[i] = tex.uvSet; - } - else if (boundTextures.find(i) != boundTextures.end()) - { - stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); - boundTextures.erase(i); + boundTextures.push_back(tex.uvSet); } handleTextureControllers(texprop, composite, textureManager, stateset, animflags); } From 6e5f3339ad0e6027e8845aebc0a67a9a35e72084 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 20:49:01 +0200 Subject: [PATCH 0489/1812] Make sure to play IdleSwim when the character is swimming (Bug #2696) --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c48599b465..16d7387fd5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1768,7 +1768,7 @@ void CharacterController::update(float duration) if(movestate != CharState_None) clearAnimQueue(); - if(mAnimQueue.empty()) + if(mAnimQueue.empty() || inwater || sneak) { idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); } From 0ffa1f964b06472c27f9bdf6589f65f1ddb0d337 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Jun 2015 22:49:20 +0200 Subject: [PATCH 0490/1812] Fix water ripple height --- apps/openmw/mwrender/water.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 3b07f35ba0..7cad745dd8 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -159,6 +159,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + osg::Vec3f pos = mWaterNode->getPosition(); pos.z() = height; mWaterNode->setPosition(pos); From fabc5126f3768ceb7a3af0bd195acd8a04a23f25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 00:30:51 +0200 Subject: [PATCH 0491/1812] Include cleanup --- apps/openmw/mwrender/sky.cpp | 1 + components/resource/scenemanager.hpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4b70c81ab6..0494b95447 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index f4ca0dea27..1dabe45e00 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -7,8 +7,6 @@ #include #include -#include - namespace Resource { class TextureManager; From 43384596d4835ac310a7d02295b228cc1d1477ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 01:26:10 +0200 Subject: [PATCH 0492/1812] Style fix --- components/resource/scenemanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 6f38c41c4a..efaccec133 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -104,8 +104,7 @@ namespace Resource // TODO: add support for non-NIF formats - NifOsg::Loader loader; - osg::ref_ptr loaded = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + osg::ref_ptr loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); // TODO: run SharedStateManager::prune on unload @@ -144,9 +143,8 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); - NifOsg::Loader loader; osg::ref_ptr loaded (new NifOsg::KeyframeHolder); - loader.loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); + NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); mKeyframeIndex[normalized] = loaded; return loaded; From a7c5beb7c5d495446e5d7facaa780fbf851d1848 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 01:26:45 +0200 Subject: [PATCH 0493/1812] Remove redundant allocations for NIF meshes --- components/nif/data.cpp | 17 ++++++++-- components/nif/data.hpp | 13 +++++--- components/nif/nifstream.cpp | 32 +++++++++--------- components/nif/nifstream.hpp | 11 ++++--- components/nifbullet/bulletnifloader.cpp | 18 +++++----- components/nifosg/nifloader.cpp | 42 +++++++++++------------- 6 files changed, 76 insertions(+), 57 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index fc0631b841..5a60ab8a5e 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -1,6 +1,9 @@ #include "data.hpp" #include "node.hpp" +#include +#include + namespace Nif { void NiSkinInstance::read(NIFStream *nif) @@ -37,15 +40,18 @@ void ShapeData::read(NIFStream *nif) { int verts = nif->getUShort(); + vertices = new osg::Vec3Array; if(nif->getInt()) nif->getVector3s(vertices, verts); + normals = new osg::Vec3Array(osg::Array::BIND_PER_VERTEX); if(nif->getInt()) nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); + colors = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX); if(nif->getInt()) nif->getVector4s(colors, verts); @@ -58,7 +64,10 @@ void ShapeData::read(NIFStream *nif) { uvlist.resize(uvs); for(int i = 0;i < uvs;i++) + { + uvlist[i] = new osg::Vec2Array(osg::Array::BIND_PER_VERTEX); nif->getVector2s(uvlist[i], verts); + } } } @@ -71,6 +80,7 @@ void NiTriShapeData::read(NIFStream *nif) // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); + triangles = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES); nif->getUShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to @@ -97,8 +107,9 @@ void NiAutoNormalParticlesData::read(NIFStream *nif) if(nif->getInt()) { + int numVerts = vertices->size(); // Particle sizes - nif->getFloats(sizes, vertices.size()); + nif->getFloats(sizes, numVerts); } } @@ -108,8 +119,9 @@ void NiRotatingParticlesData::read(NIFStream *nif) if(nif->getInt()) { + int numVerts = vertices->size(); // Rotation quaternions. - nif->getQuaternions(rotations, vertices.size()); + nif->getQuaternions(rotations, numVerts); } } @@ -224,6 +236,7 @@ void NiMorphData::read(NIFStream *nif) { mMorphs[i].mKeyFrames.reset(new FloatKeyMap); mMorphs[i].mKeyFrames->read(nif, true); + mMorphs[i].mVertices = new osg::Vec3Array; nif->getVector3s(mMorphs[i].mVertices, vertCount); } } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 63dc42aded..95f2441295 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -28,6 +28,8 @@ #include "niftypes.hpp" // Transformation +#include + namespace Nif { @@ -35,9 +37,10 @@ namespace Nif class ShapeData : public Record { public: - std::vector vertices, normals; - std::vector colors; - std::vector< std::vector > uvlist; + osg::ref_ptr vertices, normals; + osg::ref_ptr colors; + + std::vector< osg::ref_ptr > uvlist; osg::Vec3f center; float radius; @@ -48,7 +51,7 @@ class NiTriShapeData : public ShapeData { public: // Triangles, three vertex indices per triangle - std::vector triangles; + osg::ref_ptr triangles; void read(NIFStream *nif); }; @@ -166,7 +169,7 @@ struct NiMorphData : public Record { struct MorphData { FloatKeyMapPtr mKeyFrames; - std::vector mVertices; + osg::ref_ptr mVertices; }; std::vector mMorphs; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index d0fc9bab03..5f49c2d21e 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -103,11 +103,11 @@ std::string NIFStream::getVersionString() return result; } -void NIFStream::getUShorts(std::vector &vec, size_t size) +void NIFStream::getUShorts(osg::VectorGLushort* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getUShort()); } void NIFStream::getFloats(std::vector &vec, size_t size) { @@ -115,23 +115,23 @@ void NIFStream::getFloats(std::vector &vec, size_t size) for(size_t i = 0;i < vec.size();i++) vec[i] = getFloat(); } -void NIFStream::getVector2s(std::vector &vec, size_t size) +void NIFStream::getVector2s(osg::Vec2Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector2()); } -void NIFStream::getVector3s(std::vector &vec, size_t size) +void NIFStream::getVector3s(osg::Vec3Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector3()); } -void NIFStream::getVector4s(std::vector &vec, size_t size) +void NIFStream::getVector4s(osg::Vec4Array* vec, size_t size) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); + vec->reserve(size); + for(size_t i = 0;i < size;i++) + vec->push_back(getVector4()); } void NIFStream::getQuaternions(std::vector &quat, size_t size) { diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index f4163ce47c..f5d777bdfc 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -12,9 +12,12 @@ #include #include #include +#include +#include #include "niftypes.hpp" + namespace Nif { @@ -59,11 +62,11 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - void getUShorts(std::vector &vec, size_t size); + void getUShorts(osg::VectorGLushort* vec, size_t size); void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); + void getVector2s(osg::Vec2Array* vec, size_t size); + void getVector3s(osg::Vec3Array* vec, size_t size); + void getVector4s(osg::Vec4Array* vec, size_t size); void getQuaternions(std::vector &quat, size_t size); }; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 495c6ba50d..adf961dc25 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -292,13 +292,14 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Nif::NiTriShapeData *data = shape->data.getPtr(); - childMesh->preallocateVertices(data->vertices.size()); - childMesh->preallocateIndices(data->triangles.size()); + childMesh->preallocateVertices(data->vertices->size()); + childMesh->preallocateIndices(data->triangles->size()); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + const osg::Vec3Array& vertices = *data->vertices; + const osg::DrawElementsUShort& triangles = *data->triangles; - for(size_t i = 0;i < data->triangles.size();i+=3) + size_t numtris = data->triangles->size(); + for(size_t i = 0;i < numtris;i+=3) { osg::Vec3f b1 = vertices[triangles[i+0]]; osg::Vec3f b2 = vertices[triangles[i+1]]; @@ -332,10 +333,11 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, // Static shape, just transform all vertices into position const Nif::NiTriShapeData *data = shape->data.getPtr(); - const std::vector &vertices = data->vertices; - const std::vector &triangles = data->triangles; + const osg::Vec3Array& vertices = *data->vertices; + const osg::DrawElementsUShort& triangles = *data->triangles; - for(size_t i = 0;i < data->triangles.size();i+=3) + size_t numtris = data->triangles->size(); + for(size_t i = 0;i < numtris;i+=3) { osg::Vec3f b1 = vertices[triangles[i+0]]*transform; osg::Vec3f b2 = vertices[triangles[i+1]]*transform; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d8920646d1..802ca5425f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -736,11 +736,11 @@ namespace NifOsg // Note this position and velocity is not correct for a particle system with absolute reference frame, // which can not be done in this loader since we are not attached to the scene yet. Will be fixed up post-load in the SceneManager. created->setVelocity(particle.velocity); - created->setPosition(particledata->vertices.at(particle.vertex)); + created->setPosition(particledata->vertices->at(particle.vertex)); osg::Vec4f partcolor (1.f,1.f,1.f,1.f); - if (particle.vertex < int(particledata->colors.size())) - partcolor = particledata->colors.at(particle.vertex); + if (particle.vertex < int(particledata->colors->size())) + partcolor = particledata->colors->at(particle.vertex); float size = particledata->sizes.at(particle.vertex) * partctrl->size; @@ -892,11 +892,10 @@ namespace NifOsg { const Nif::NiTriShapeData* data = triShape->data.getPtr(); - { - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), &data->vertices[0])); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); - } + geometry->setVertexArray(data->vertices); + + if (!data->normals->empty()) + geometry->setNormalArray(data->normals); int textureStage = 0; for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) @@ -909,15 +908,14 @@ namespace NifOsg continue; } - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), &data->uvlist[uvSet][0]), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(textureStage, data->uvlist[uvSet]); } - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), &data->colors[0]), osg::Array::BIND_PER_VERTEX); + if (!data->colors->empty()) + geometry->setColorArray(data->colors); - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)&data->triangles[0])); + if (!data->triangles->empty()) + geometry->addPrimitiveSet(data->triangles); // osg::Material properties are handled here for two reasons: // - if there are no vertex colors, we need to disable colorMode. @@ -925,7 +923,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); + applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags); } void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -988,13 +986,13 @@ namespace NifOsg for (unsigned int i = 1; i < morphs.size(); ++i) { osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); + morphTarget->setVertexArray(morphs[i].mVertices); morphGeom->addMorphTarget(morphTarget, 0.f); } // build the bounding box containing all possible morph combinations - std::vector vertBounds(morphs[0].mVertices.size()); + std::vector vertBounds(morphs[0].mVertices->size()); // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. @@ -1005,19 +1003,19 @@ namespace NifOsg for (unsigned int i = 1; i < morphs.size(); ++i) { - for (unsigned int j=0; jsize() && vertBounds.size(); ++j) { osg::BoundingBox& bounds = vertBounds[j]; - bounds.expandBy(bounds._max + morphs[i].mVertices[j]); - bounds.expandBy(bounds._min + morphs[i].mVertices[j]); + bounds.expandBy(bounds._max + (*morphs[i].mVertices)[j]); + bounds.expandBy(bounds._min + (*morphs[i].mVertices)[j]); } } osg::BoundingBox box; for (unsigned int i=0; i Date: Thu, 18 Jun 2015 03:03:30 +0200 Subject: [PATCH 0494/1812] Re-enable a warning message --- components/nifosg/nifloader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 802ca5425f..c30ac671aa 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -903,8 +903,7 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently - //std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << std::endl; + std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << " in " << mFilename << std::endl; continue; } From 76799982a5f73c94ae913047af820b4402f3c2dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 14:56:43 +0200 Subject: [PATCH 0495/1812] Add missing include --- apps/opencs/view/render/object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 6ddea913ad..ea27b14320 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,6 +1,7 @@ #include "object.hpp" #include +#include #include #include From 04010b8a1aee77a69fbd654ecaf1be2238c7a8a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 15:00:04 +0200 Subject: [PATCH 0496/1812] Set OnPcHitMe even for missed hits --- apps/openmw/mwclass/creature.cpp | 16 ++++++++-------- apps/openmw/mwclass/npc.cpp | 15 ++++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c886915151..5b5a3a0cb4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -345,6 +345,14 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + const std::string &script = ptr.get()->mBase->mScript; + /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ + if(!script.empty()) + ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); + } + if(!successful) { // Missed @@ -355,14 +363,6 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - const std::string &script = ptr.get()->mBase->mScript; - /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ - if(!script.empty()) - ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); - } - if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c9de1f6ff2..b9ca69c630 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -610,6 +610,14 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + const std::string &script = ptr.getClass().getScript(ptr); + /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ + if(!script.empty()) + ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); + } + if(!successful) { // Missed @@ -620,13 +628,6 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - const std::string &script = ptr.getClass().getScript(ptr); - /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ - if(!script.empty()) - ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); - } if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); From fb94395628895532b12380134e98889274b777b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Jun 2015 23:15:13 +0200 Subject: [PATCH 0497/1812] Fix atmosphere lighting --- apps/openmw/mwrender/sky.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0494b95447..0032c4e4fc 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -104,7 +104,7 @@ public: protected: virtual void setDefaults(osg::StateSet* stateset) { - stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) @@ -224,9 +224,6 @@ public: if (!geom) continue; - // might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha - // (that isn't possible now, with the diffuse tracking the vertex colors) - osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); for (unsigned int i=0; isize(); ++i) { @@ -244,7 +241,7 @@ public: alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; } - (*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha); + (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); } geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); From 0c4ebee6b36920d56c1ff9ecb2c5a8cda65466c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 01:03:12 +0200 Subject: [PATCH 0498/1812] Cloud opacity & cross-fading --- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++++++++++++++++--------- apps/openmw/mwrender/sky.hpp | 3 ++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0032c4e4fc..25b19465b2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -141,8 +141,24 @@ public: protected: virtual void setDefaults(osg::StateSet *stateset) { - stateset->setTextureAttributeAndModes(0, new osg::TexMat, osg::StateAttribute::ON); + osg::ref_ptr texmat (new osg::TexMat); + stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(1, texmat, osg::StateAttribute::ON); stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // need to set opacity on a separate texture unit, diffuse alpha is used by the vertex colors already + osg::ref_ptr texEnvCombine (new osg::TexEnvCombine); + texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnvCombine->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnvCombine->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnvCombine->setConstantColor(osg::Vec4f(1,1,1,1)); + texEnvCombine->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE); + + stateset->setTextureAttributeAndModes(1, texEnvCombine, osg::StateAttribute::ON); + + stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) @@ -150,12 +166,14 @@ protected: osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(0, mAnimationTimer, 0.f))); - stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttribute(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttribute(1, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); - // FIXME: handle opacity, will have to resort to either shaders or multitexturing? diffuse alpha is in use by the vertex colors already + osg::TexEnvCombine* texEnvCombine = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnvCombine->setConstantColor(osg::Vec4f(1,1,1,mOpacity)); } private: @@ -533,14 +551,16 @@ void SkyManager::create() mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); - osg::ref_ptr clouds = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); - clouds->accept(modClouds); - + mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; - clouds->addUpdateCallback(mCloudUpdater); + mCloudMesh->addUpdateCallback(mCloudUpdater); - clouds->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); + mCloudMesh2->accept(modClouds); + mCloudUpdater2 = new CloudUpdater; + mCloudMesh2->addUpdateCallback(mCloudUpdater2); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -602,6 +622,7 @@ void SkyManager::update(float duration) // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed * 0.003; mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); + mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); @@ -708,18 +729,23 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mNextClouds != weather.mNextCloudTexture) { mNextClouds = weather.mNextCloudTexture; + + std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); + + if (!texture.empty()) + mCloudUpdater2->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, + osg::Texture::REPEAT, osg::Texture::REPEAT)); } - if (mCloudBlendFactor != weather.mCloudBlendFactor) + if (mCloudBlendFactor != weather.mCloudBlendFactor + || mCloudOpacity != weather.mCloudOpacity) { mCloudBlendFactor = weather.mCloudBlendFactor; - } - - if (mCloudOpacity != weather.mCloudOpacity) - { mCloudOpacity = weather.mCloudOpacity; - mCloudUpdater->setOpacity(0.3); + mCloudUpdater->setOpacity(mCloudOpacity * (1.f-mCloudBlendFactor)); + mCloudUpdater2->setOpacity(mCloudOpacity * mCloudBlendFactor); + mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } if (mCloudColour != weather.mSunColor) @@ -730,6 +756,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); mCloudUpdater->setEmissionColor(clr); + mCloudUpdater2->setEmissionColor(clr); mCloudColour = weather.mSunColor; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f097029d1a..e7514e7465 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -99,6 +99,9 @@ namespace MWRender osg::ref_ptr mCloudNode; osg::ref_ptr mCloudUpdater; + osg::ref_ptr mCloudUpdater2; + osg::ref_ptr mCloudMesh; + osg::ref_ptr mCloudMesh2; osg::ref_ptr mAtmosphereDay; From e0dfc1425eb6834f00707c296b187f467242c4e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 02:51:01 +0200 Subject: [PATCH 0499/1812] Correct moon blending --- apps/openmw/mwrender/sky.cpp | 107 ++++++++++++++++++++--------------- apps/openmw/mwrender/sky.hpp | 4 ++ 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 25b19465b2..43ed80dbf3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -288,10 +288,11 @@ public: void setDirection(const osg::Vec3f& direction) { - mTransform->setPosition(direction*1000.f); + osg::Vec3f normalizedDirection = direction / direction.length(); + mTransform->setPosition(normalizedDirection*1000.f); osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), direction); + quat.makeRotate(osg::Vec3f(0,0,1), normalizedDirection); mTransform->setAttitude(quat); } @@ -356,36 +357,13 @@ public: void setTextures(const std::string& phaseTex, const std::string& circleTex) { - osg::ref_ptr stateset = new osg::StateSet; - - osg::ref_ptr moonTex = mSceneManager->getTextureManager()->getTexture2D(circleTex, + osg::ref_ptr phaseTexPtr = mSceneManager->getTextureManager()->getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - // stage 0: render the moon circle in atmosphere color - stateset->setTextureAttributeAndModes(0, moonTex, osg::StateAttribute::ON); - - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor - - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - // stage 1: render the "lit" side of the moon blended over the circle - osg::ref_ptr moonTex2 = mSceneManager->getTextureManager()->getTexture2D(phaseTex, + osg::ref_ptr circleTexPtr = mSceneManager->getTextureManager()->getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(1, moonTex2, osg::StateAttribute::ON); - - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - texEnv2->setSource2_RGB(osg::TexEnvCombine::TEXTURE); - - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - mTransform->setStateSet(stateset); + mUpdater->setTextures(phaseTexPtr, circleTexPtr); } void setPhase(const Phase& phase) @@ -425,43 +403,75 @@ public: { public: MoonUpdater() - : mAlpha(1.f) { } virtual void setDefaults(osg::StateSet *stateset) { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, mAlpha)); + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(mAtmosphereColor); } - void setAlpha(float alpha) + + void setAtmosphereColor(const osg::Vec4f& color) { - mAlpha = alpha; + mAtmosphereColor = color; + } + + void setMoonColor(const osg::Vec4f& color) + { + mMoonColor = color; + } + + void setTextures(osg::ref_ptr phaseTex, osg::ref_ptr circleTex) + { + mPhaseTex = phaseTex; + mCircleTex = circleTex; + reset(); } private: - float mAlpha; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; }; - void setAlpha(float alpha) - { - mUpdater->setAlpha(alpha); - } void setAtmosphereColor(const osg::Vec4f& color) { - // TODO + mUpdater->setAtmosphereColor(color); } void setColor(const osg::Vec4f& color) { - // TODO + mUpdater->setMoonColor(color); } unsigned int getPhaseInt() const @@ -508,6 +518,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) + , mMasserFade(0.f) + , mSecundaFade(0.f) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -568,6 +580,8 @@ void SkyManager::create() mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); + mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color"); + mCreated = true; } @@ -628,9 +642,8 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); - //mMasser->setColour (ColourValue(1,1,1,1)); + mMasser->setColor(osg::Vec4f(mMasserFade,mMasserFade,mMasserFade,1)); + mSecunda->setColor(mMoonRed ? (mMoonScriptColor * mSecundaFade) : osg::Vec4f(mSecundaFade,mSecundaFade,mSecundaFade,1)); if (mSunEnabled) { @@ -766,6 +779,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSkyColour = weather.mSkyColor; mAtmosphereUpdater->setEmissionColor(mSkyColour); + mMasser->setAtmosphereColor(mSkyColour); + mSecunda->setAtmosphereColor(mSkyColour); } if (mFogColour != weather.mFogColor) @@ -900,14 +915,12 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { - if (!mCreated) return; - mMasser->setAlpha(fade); + mMasserFade = fade; } void SkyManager::setSecundaFade(const float fade) { - if (!mCreated) return; - mSecunda->setAlpha(fade); + mSecundaFade = fade; } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e7514e7465..8251f39bdc 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -154,6 +154,10 @@ namespace MWRender bool mEnabled; bool mSunEnabled; + + osg::Vec4f mMoonScriptColor; + float mMasserFade; + float mSecundaFade; }; } From 2b53e5d96573702697bc451eda27b0a8b8f008c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 03:32:48 +0200 Subject: [PATCH 0500/1812] Fix for explosion effects playing when the game is paused --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7f76adb288..719ee6ebcd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -350,7 +350,9 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { - mEffectManager->update(dt); + if (!paused) + mEffectManager->update(dt); + mSky->update(dt); mWater->update(dt); mCamera->update(dt, paused); From 7a5f220ac52ba29d4cc04f4a88f8afa9206ff398 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 17:43:13 +0200 Subject: [PATCH 0501/1812] GlowTexture keeps the alpha channel from the previous texture stage --- components/nifosg/nifloader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c30ac671aa..b5439afeed 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1302,8 +1302,13 @@ namespace NifOsg if (i == Nif::NiTexturingProperty::GlowTexture) { - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::ADD); + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::DarkTexture) From 38d90f47a63d8862e1b7ce96ba284e1fec341a18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:15:23 +0200 Subject: [PATCH 0502/1812] Moon fading fix (Bug #2713) --- apps/openmw/mwworld/weather.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 81497aa6c2..70d6f1b36e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -495,8 +495,6 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setMasserDirection(masser); mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -507,8 +505,22 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + if (masserAngleFade > 0) + { + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->masserEnable(); + } + else + mRendering->getSkyManager()->masserDisable(); + + if (secundaAngleFade > 0) + { + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + mRendering->getSkyManager()->secundaEnable(); + } + else + mRendering->getSkyManager()->secundaDisable(); + } else { From 1ed4e33815cd5a739ebb726ae7b3218292b1e475 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:19:52 +0200 Subject: [PATCH 0503/1812] Fading for mooncircle texture --- apps/openmw/mwrender/sky.cpp | 40 +++++++++++++++++++++++++----------- apps/openmw/mwrender/sky.hpp | 4 ---- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43ed80dbf3..d40ae35494 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -403,6 +403,8 @@ public: { public: MoonUpdater() + : mFade(0.f) + , mMoonColor(1,1,1,1) { } @@ -419,8 +421,9 @@ public: stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); osg::ref_ptr texEnv2 = new osg::TexEnvCombine; texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor @@ -432,12 +435,22 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor); + texEnv->setConstantColor(mMoonColor * mFade); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(mAtmosphereColor); + const float backdropFadeThreshold = 0.03; + if (mFade <= backdropFadeThreshold) + { + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); + } + else + texEnv2->setConstantColor(mAtmosphereColor); } + void setFade (const float fade) + { + mFade = fade; + } void setAtmosphereColor(const osg::Vec4f& color) { @@ -457,6 +470,7 @@ public: } private: + float mFade; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -474,6 +488,11 @@ public: mUpdater->setMoonColor(color); } + void setFade(const float fade) + { + mUpdater->setFade(fade); + } + unsigned int getPhaseInt() const { if (mPhase == Moon::Phase_New) return 0; @@ -497,7 +516,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana : mSceneManager(sceneManager) , mAtmosphereNightRoll(0.f) , mCreated(false) - , mMoonRed(false) , mIsStorm(false) , mDay(0) , mMonth(0) @@ -518,8 +536,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainFrequency(1) , mEnabled(true) , mSunEnabled(true) - , mMasserFade(0.f) - , mSecundaFade(0.f) { osg::ref_ptr skyroot (new CameraRelativeTransform); skyroot->setNodeMask(Mask_Sky); @@ -642,9 +658,6 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mMasser->setColor(osg::Vec4f(mMasserFade,mMasserFade,mMasserFade,1)); - mSecunda->setColor(mMoonRed ? (mMoonScriptColor * mSecundaFade) : osg::Vec4f(mSecundaFade,mSecundaFade,mSecundaFade,1)); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -692,7 +705,8 @@ void SkyManager::setEnabled(bool enabled) void SkyManager::setMoonColour (bool red) { - mMoonRed = red; + if (!mCreated) return; + mSecunda->setColor(red ? mMoonScriptColor : osg::Vec4f(1,1,1,1)); } void SkyManager::setWeather(const MWWorld::WeatherResult& weather) @@ -915,12 +929,14 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { - mMasserFade = fade; + if (!mCreated) return; + mMasser->setFade(fade); } void SkyManager::setSecundaFade(const float fade) { - mSecundaFade = fade; + if (!mCreated) return; + mSecunda->setFade(fade); } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 8251f39bdc..bb4d2e184f 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -116,8 +116,6 @@ namespace MWRender bool mCreated; - bool mMoonRed; - bool mIsStorm; int mDay; @@ -156,8 +154,6 @@ namespace MWRender bool mSunEnabled; osg::Vec4f mMoonScriptColor; - float mMasserFade; - float mSecundaFade; }; } From 170692b48004a7ee7ed3a96027d34ef78d110a8f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 19 Jun 2015 19:24:06 +0300 Subject: [PATCH 0504/1812] InfoTableProxyModel: invalidate first row cache after row insertion/deletion --- .../model/world/infotableproxymodel.cpp | 19 +++++++++++++------ .../model/world/infotableproxymodel.hpp | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 7522e492b6..5192dfec05 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -15,11 +15,18 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod { IdTableProxyModel::setSourceModel(sourceModel); mSourceModel = dynamic_cast(sourceModel); - connect(mSourceModel, - SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), - this, - SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &))); - mFirstRowCache.clear(); + if (mSourceModel != NULL) + { + connect(mSourceModel, + SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, + SLOT(modelRowsChanged(const QModelIndex &, int, int))); + connect(mSourceModel, + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(modelRowsChanged(const QModelIndex &, int, int))); + mFirstRowCache.clear(); + } } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const @@ -52,7 +59,7 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const return currentRow + 1; } -void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { mFirstRowCache.clear(); } diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 3228316264..7b0cd8ede4 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -31,7 +31,7 @@ namespace CSMWorld virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; private slots: - void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void modelRowsChanged(const QModelIndex &parent, int start, int end); }; } From f5c50aa5815b1ed0e5f0bc3eb4f2dfcff01d67ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 18:38:44 +0200 Subject: [PATCH 0505/1812] Disable FreezeOnCull for effect particles --- apps/openmw/mwrender/animation.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8c1b3c0a9a..3801cf6fc8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -1067,6 +1069,25 @@ namespace MWRender attachTo->addChild(lightSource); } + class DisableFreezeOnCullVisitor : public osg::NodeVisitor + { + public: + DisableFreezeOnCullVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &geode) + { + for (unsigned int i=0; i(drw)) + partsys->setFreezeOnCull(false); + } + } + }; + void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { if (!mObjectRoot.get()) @@ -1099,6 +1120,10 @@ namespace MWRender SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; node->accept(findMaxLengthVisitor); + // FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters + DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + node->accept(disableFreezeOnCullVisitor); + params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); node->setNodeMask(Mask_Effect); From 74260a9a44f159827316a1b325c56e0660a3d4af Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 20:30:04 +0200 Subject: [PATCH 0506/1812] Tweak moon sizes --- apps/openmw/mwrender/sky.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d40ae35494..206249c175 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -574,8 +574,8 @@ void SkyManager::create() mSun.reset(new Sun(mRootNode, mSceneManager)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); + mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); From efad4efe1961e823fda5876d0ed7454c925ba24e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Jun 2015 20:55:04 +0200 Subject: [PATCH 0507/1812] Star fading (Bug #2693) --- apps/openmw/mwrender/sky.cpp | 53 ++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 2 + components/resource/texturemanager.cpp | 5 +++ components/resource/texturemanager.hpp | 2 + 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 206249c175..e2f3dd82b5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -96,7 +96,7 @@ namespace MWRender class AtmosphereUpdater : public SceneUtil::StateSetUpdater { public: - void setEmissionColor(osg::Vec4f emissionColor) + void setEmissionColor(const osg::Vec4f& emissionColor) { mEmissionColor = emissionColor; } @@ -117,6 +117,45 @@ private: osg::Vec4f mEmissionColor; }; +class AtmosphereNightUpdater : public SceneUtil::StateSetUpdater +{ +public: + AtmosphereNightUpdater(Resource::TextureManager* textureManager) + { + // we just need a texture, its contents don't really matter + mTexture = textureManager->getWarningTexture(); + } + + void setFade(const float fade) + { + mColor.a() = fade; + } + +protected: + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr texEnv (new osg::TexEnvCombine); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + + stateset->setTextureAttributeAndModes(1, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mColor); + } + + osg::ref_ptr mTexture; + + osg::Vec4f mColor; +}; + class CloudUpdater : public SceneUtil::StateSetUpdater { public: @@ -129,7 +168,7 @@ public: { mTexture = texture; } - void setEmissionColor(osg::Vec4f emissionColor) + void setEmissionColor(const osg::Vec4f& emissionColor) { mEmissionColor = emissionColor; } @@ -570,6 +609,8 @@ void SkyManager::create() atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); ModVertexAlphaVisitor modStars(2); atmosphereNight->accept(modStars); + mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); + atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); mSun.reset(new Sun(mRootNode, mSceneManager)); @@ -806,13 +847,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (weather.mNight && mStarsOpacity != weather.mNightFade) { - if (weather.mNightFade != 0) - { - //sh::Factory::getInstance().setSharedParameter ("nightFade", - // sh::makeProperty(new sh::FloatValue(weather.mNightFade))); + mStarsOpacity = weather.mNightFade; - //mStarsOpacity = weather.mNightFade; - } + mAtmosphereNightUpdater->setFade(mStarsOpacity); } mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index bb4d2e184f..b05845e53c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -20,6 +20,7 @@ namespace Resource namespace MWRender { class AtmosphereUpdater; + class AtmosphereNightUpdater; class CloudUpdater; class Sun; class Moon; @@ -107,6 +108,7 @@ namespace MWRender osg::ref_ptr mAtmosphereNightNode; float mAtmosphereNightRoll; + osg::ref_ptr mAtmosphereNightUpdater; osg::ref_ptr mAtmosphereUpdater; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 50cfd9d57d..62cbd6bb39 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -145,4 +145,9 @@ namespace Resource } } + osg::Texture2D* TextureManager::getWarningTexture() + { + return mWarningTexture.get(); + } + } diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 5ff233348d..2ee3baa773 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -38,6 +38,8 @@ namespace Resource const VFS::Manager* getVFS() { return mVFS; } + osg::Texture2D* getWarningTexture(); + private: const VFS::Manager* mVFS; From f1a38ffe930cb2ae13554543095ab0746edaf637 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 11:29:15 +0300 Subject: [PATCH 0508/1812] InfoTableProxyModel: ignore the letter case in the search of the first Topic/Journal row --- .../model/world/infotableproxymodel.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 5192dfec05..2812bae602 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -1,8 +1,18 @@ #include "infotableproxymodel.hpp" +#include + #include "idtablebase.hpp" #include "columns.hpp" +namespace +{ + QString toLower(const QString &str) + { + return Misc::StringUtils::lowerCase(str.toStdString()).c_str(); + } +} + CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), @@ -45,7 +55,7 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const } int column = mSourceModel->findColumnIndex(columnId); - QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString(); + QString info = toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()); if (mFirstRowCache.contains(info)) { @@ -53,10 +63,11 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const } while (--currentRow >= 0 && - mSourceModel->data(mSourceModel->index(currentRow, column)) == info); + toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()) == info); + ++currentRow; - mFirstRowCache[info] = currentRow + 1; - return currentRow + 1; + mFirstRowCache[info] = currentRow; + return currentRow; } void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) From ced4e237a8e3c7069ebe769c0fea3fe2585d7e30 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 12:43:53 +0300 Subject: [PATCH 0509/1812] Fix the sorting of Info tables when new row are added --- apps/opencs/model/world/infotableproxymodel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 2812bae602..3e564506ce 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -43,6 +43,12 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod { QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); + + // If both indexes are belonged to the same Topic/Journal, compare their original rows only + if (first.row() == second.row()) + { + return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row(); + } return IdTableProxyModel::lessThan(first, second); } From 27ece7f36aec12f14987227b37a3af45b1f7e81b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 17:33:36 +0300 Subject: [PATCH 0510/1812] Rework DropLineEdit. Make it type-sensitive --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/droplineedit.cpp | 82 +++++++++++++++++++ apps/opencs/view/widget/droplineedit.hpp | 50 +++++++++++ apps/opencs/view/world/dialoguesubview.cpp | 5 +- .../view/world/idcompletiondelegate.cpp | 4 +- apps/opencs/view/world/util.cpp | 31 +------ apps/opencs/view/world/util.hpp | 19 ----- 7 files changed, 143 insertions(+), 50 deletions(-) create mode 100644 apps/opencs/view/widget/droplineedit.cpp create mode 100644 apps/opencs/view/widget/droplineedit.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d86798af95..fa703e4972 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -75,7 +75,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 completerpopup coloreditor colorpickerpopup + scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit ) opencs_units (view/render diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp new file mode 100644 index 0000000000..0b2ac63816 --- /dev/null +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -0,0 +1,82 @@ +#include "droplineedit.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +namespace +{ + const CSMWorld::TableMimeData *getEventMimeData(QDropEvent *event) + { + Q_ASSERT(event != NULL); + return dynamic_cast(event->mimeData()); + } +} + +CSVWidget::DropLineEdit::DropLineEdit(QWidget *parent, CSMWorld::UniversalId::Type type) + : QLineEdit(parent), + mDropType(type) +{ + setAcceptDrops(true); +} + +void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) +{ + if (canAcceptEventData(event)) + { + event->acceptProposedAction(); + } +} + +void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) +{ + if (canAcceptEventData(event)) + { + event->accept(); + } +} + +void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) +{ + const CSMWorld::TableMimeData *data = getEventMimeData(event); + if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped + { + return; + } + + int dataIndex = getAcceptedDataIndex(*data); + if (dataIndex != -1) + { + setText(data->getData()[dataIndex].getId().c_str()); + emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); + } +} + +bool CSVWidget::DropLineEdit::canAcceptEventData(QDropEvent *event) const +{ + const CSMWorld::TableMimeData *data = getEventMimeData(event); + if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped + { + return false; + } + return getAcceptedDataIndex(*data) != -1; +} + +int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const +{ + if (mDropType == CSMWorld::UniversalId::Type_None) + { + return 0; + } + + std::vector idData = data.getData(); + int size = static_cast(idData.size()); + for (int i = 0; i < size; ++i) + { + if (idData[i].getType() == mDropType) + { + return i; + } + } + return -1; +} diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp new file mode 100644 index 0000000000..e49c947b48 --- /dev/null +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_WIDGET_DROPLINEEDIT_HPP +#define CSV_WIDGET_DROPLINEEDIT_HPP + +#include + +#include "../../model/world/universalid.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class TableMimeData; +} + +namespace CSVWidget +{ + class DropLineEdit : public QLineEdit + { + Q_OBJECT + + CSMWorld::UniversalId::Type mDropType; + ///< The accepted ID type for this LineEdit. + ///< If \a mDropType has Type_None type, this LineEdit accepts all ID types + + bool canAcceptEventData(QDropEvent *event) const; + ///< Checks whether the \a event contains CSMWorld::TableMimeData with a proper ID type + + int getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const; + ///< Checks whether the \a data has a proper type + ///< \return -1 if there is no suitable data (ID type) + + public: + DropLineEdit(QWidget *parent = 0, + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::Type_None); + + protected: + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); + + signals: + void tableMimeDataDropped(const std::vector &data, + const CSMDoc::Document *document); + }; +} + +#endif diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5d9eda3f24..a1dbc902ee 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -34,6 +34,7 @@ #include "../../model/doc/document.hpp" #include "../widget/coloreditor.hpp" +#include "../widget/droplineedit.hpp" #include "recordstatusdelegate.hpp" #include "util.hpp" @@ -306,7 +307,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry // is required here - if (qobject_cast(editor)) + if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -850,7 +851,7 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, { if (document == &mDocument) { - qobject_cast(editor)->setText(id.getId().c_str()); + qobject_cast(editor)->setText(id.getId().c_str()); } } diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 056026471b..5c92e6576d 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -2,6 +2,8 @@ #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) @@ -26,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, } CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - DropLineEdit *editor = new DropLineEdit(parent); + CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(parent); editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5974987c0c..684327fc2c 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -17,7 +17,10 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" + #include "../widget/coloreditor.hpp" +#include "../widget/droplineedit.hpp" + #include "dialoguespinbox.hpp" #include "scriptedit.hpp" @@ -250,7 +253,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Video: case CSMWorld::ColumnBase::Display_GlobalVariable: - return new DropLineEdit(parent); + return new CSVWidget::DropLineEdit(parent); case CSMWorld::ColumnBase::Display_ScriptLines: @@ -324,29 +327,3 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde } } - -CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) : -QLineEdit(parent) -{ - setAcceptDrops(true); -} - -void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) -{ - event->acceptProposedAction(); -} - -void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) -{ - event->accept(); -} - -void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event) -{ - const CSMWorld::TableMimeData* data(dynamic_cast(event->mimeData())); - if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped - return; - - emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); - //WIP -} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 8355e971cb..d695be0d7e 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -5,7 +5,6 @@ #include #include -#include #include "../../model/world/columnbase.hpp" #include "../../model/doc/document.hpp" @@ -91,24 +90,6 @@ namespace CSVWorld }; - class DropLineEdit : public QLineEdit - { - Q_OBJECT - - public: - DropLineEdit(QWidget *parent); - - private: - void dragEnterEvent(QDragEnterEvent *event); - - void dragMoveEvent(QDragMoveEvent *event); - - void dropEvent(QDropEvent *event); - - signals: - void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); - }; - ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { From ad6764fa6aebd377117921bbc945340cd59e179d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Jun 2015 17:08:46 +0200 Subject: [PATCH 0511/1812] Fix bug #2715 --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 719ee6ebcd..2189f185b6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -351,9 +351,11 @@ namespace MWRender void RenderingManager::update(float dt, bool paused) { if (!paused) + { mEffectManager->update(dt); + mSky->update(dt); + } - mSky->update(dt); mWater->update(dt); mCamera->update(dt, paused); From 64701b273d041411bc75caaf9527ea2183ee6679 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 18:29:31 +0300 Subject: [PATCH 0512/1812] LineEdits for ID values accept drops with a proper type --- apps/opencs/view/widget/droplineedit.cpp | 9 ++++++++- apps/opencs/view/widget/droplineedit.hpp | 5 +++-- apps/opencs/view/world/idcompletiondelegate.cpp | 2 +- apps/opencs/view/world/util.cpp | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 0b2ac63816..f3500dcd25 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -13,13 +13,20 @@ namespace } } -CSVWidget::DropLineEdit::DropLineEdit(QWidget *parent, CSMWorld::UniversalId::Type type) +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent) : QLineEdit(parent), mDropType(type) { setAcceptDrops(true); } +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent) + : QLineEdit(parent), + mDropType(CSMWorld::TableMimeData::convertEnums(display)) +{ + setAcceptDrops(true); +} + void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) { if (canAcceptEventData(event)) diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index e49c947b48..7ba0513cc7 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -3,6 +3,7 @@ #include +#include "../../model/world/columnbase.hpp" #include "../../model/world/universalid.hpp" namespace CSMDoc @@ -33,8 +34,8 @@ namespace CSVWidget ///< \return -1 if there is no suitable data (ID type) public: - DropLineEdit(QWidget *parent = 0, - CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::Type_None); + DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent = 0); + DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent = 0); protected: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 5c92e6576d..970490828f 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -28,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, } CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); - CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(parent); + CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent); editor->setCompleter(completionManager.getCompleter(display).get()); return editor; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 684327fc2c..d3969dad42 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -253,7 +253,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Video: case CSMWorld::ColumnBase::Display_GlobalVariable: - return new CSVWidget::DropLineEdit(parent); + return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); case CSMWorld::ColumnBase::Display_ScriptLines: From 7dcdd130bb65be9fa79d8240946458420c2248d4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 20:52:47 +0300 Subject: [PATCH 0513/1812] Rework Dialogue subview code according to DropLineEdit changes --- apps/opencs/view/widget/droplineedit.cpp | 9 ++- apps/opencs/view/widget/droplineedit.hpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 70 +--------------------- apps/opencs/view/world/dialoguesubview.hpp | 20 ------- apps/opencs/view/world/util.cpp | 24 ++------ 5 files changed, 14 insertions(+), 112 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index f3500dcd25..6dae157468 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -54,8 +54,9 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) int dataIndex = getAcceptedDataIndex(*data); if (dataIndex != -1) { - setText(data->getData()[dataIndex].getId().c_str()); - emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); + std::vector idData = data->getData(); + setText(idData[dataIndex].getId().c_str()); + emit tableMimeDataDropped(idData[dataIndex], data->getDocumentPtr()); } } @@ -76,11 +77,13 @@ int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData return 0; } + bool isReferenceable = mDropType == CSMWorld::UniversalId::Type_Referenceable; std::vector idData = data.getData(); int size = static_cast(idData.size()); for (int i = 0; i < size; ++i) { - if (idData[i].getType() == mDropType) + CSMWorld::UniversalId::Type type = idData[i].getType(); + if (type == mDropType || isReferenceable && CSMWorld::TableMimeData::isReferencable(type)) { return i; } diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index 7ba0513cc7..ce086b7dc1 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -43,8 +43,7 @@ namespace CSVWidget void dropEvent(QDropEvent *event); signals: - void tableMimeDataDropped(const std::vector &data, - const CSMDoc::Document *document); + void tableMimeDataDropped(const CSMWorld::UniversalId &id, const CSMDoc::Document *document); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a1dbc902ee..284c5928ba 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -130,52 +130,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const return mEditor; } -void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document) -{ - QLineEdit* lineEdit = qobject_cast(mEditor); - { - if (!lineEdit || !mIndexWrapper.get()) - { - return; - } - } - for (unsigned i = 0; i < data.size(); ++i) - { - CSMWorld::UniversalId::Type type = data[i].getType(); - if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) - { - if (type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) - { - type = CSMWorld::UniversalId::Type_Referenceable; - } - } - if (mDisplay == CSMWorld::TableMimeData::convertEnums(type)) - { - emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document); - emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay); - break; - } - } -} /* ==============================DialogueDelegateDispatcher========================================== */ @@ -311,12 +265,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); - connect(editor, SIGNAL(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*)), - proxy, SLOT(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*))); - - connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - + connect(editor, SIGNAL(tableMimeDataDropped(const CSMWorld::UniversalId&, const CSMDoc::Document*)), + proxy, SLOT(editorDataCommited())); } else if (qobject_cast(editor)) { @@ -387,9 +337,6 @@ mCommandDispatcher (commandDispatcher), mDocument (document) { remake (row); - - connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -680,8 +627,6 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); - connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -844,17 +789,6 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, } } -void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) -{ - if (document == &mDocument) - { - qobject_cast(editor)->setText(id.getId().c_str()); - } -} - void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { changeCurrentId(id); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6cbd8ad778..69e0dc8648 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -86,18 +86,12 @@ namespace CSVWorld public slots: void editorDataCommited(); void setIndex(const QModelIndex& index); - void tableMimeDataDropped(const std::vector& data, - const CSMDoc::Document* document); signals: void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); - }; class DialogueDelegateDispatcher : public QAbstractItemDelegate @@ -153,11 +147,6 @@ namespace CSVWorld private slots: void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); - - signals: - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); }; class EditWidget : public QScrollArea @@ -182,11 +171,6 @@ namespace CSVWorld virtual ~EditWidget(); void remake(int row); - - signals: - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); }; class DialogueSubView : public CSVDoc::SubView @@ -230,10 +214,6 @@ namespace CSVWorld void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record - void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document); - void requestFocus (const std::string& id); void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index d3969dad42..8155055897 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -236,29 +236,15 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new QCheckBox(parent); - case CSMWorld::ColumnBase::Display_String: - case CSMWorld::ColumnBase::Display_Skill: - case CSMWorld::ColumnBase::Display_Script: - case CSMWorld::ColumnBase::Display_Race: - case CSMWorld::ColumnBase::Display_Region: - case CSMWorld::ColumnBase::Display_Class: - case CSMWorld::ColumnBase::Display_Faction: - case CSMWorld::ColumnBase::Display_Miscellaneous: - case CSMWorld::ColumnBase::Display_Sound: - case CSMWorld::ColumnBase::Display_Mesh: - case CSMWorld::ColumnBase::Display_Icon: - case CSMWorld::ColumnBase::Display_Music: - case CSMWorld::ColumnBase::Display_SoundRes: - case CSMWorld::ColumnBase::Display_Texture: - case CSMWorld::ColumnBase::Display_Video: - case CSMWorld::ColumnBase::Display_GlobalVariable: - - return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); - case CSMWorld::ColumnBase::Display_ScriptLines: return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent); + case CSMWorld::ColumnBase::Display_String: + // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used + + return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); + default: return QStyledItemDelegate::createEditor (parent, option, index); From dc37aea8ebd678b9824f0558b48085b30c61fe0a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 20 Jun 2015 21:00:15 +0300 Subject: [PATCH 0514/1812] Add missing mappings to TableMimeData --- apps/opencs/model/world/tablemimedata.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index d40e0c217c..101bbf9ba2 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -264,6 +264,8 @@ namespace { CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture }, { CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video }, { CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable }, + { CSMWorld::UniversalId::Type_BodyPart, CSMWorld::ColumnBase::Display_BodyPart }, + { CSMWorld::UniversalId::Type_Enchantment, CSMWorld::ColumnBase::Display_Enchantment }, { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker }; From c65e7a31e7272ac450fc792ecfe690075e7e643e Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 21 Jun 2015 16:23:40 +1200 Subject: [PATCH 0515/1812] Aquatic creatures no longer try to get onto land. AiWander for aquatic creatures no longer uses path grid points as they're usually on land. --- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1f4133c0aa..d89a29e1d0 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -651,9 +651,6 @@ namespace MWMechanics if (mAllowedNodes.empty()) return; - if (actor.getClass().isPureWaterCreature(actor)) - return; - state.moveIn(new AiWanderStorage()); int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); @@ -700,7 +697,8 @@ namespace MWMechanics // actor can wander from the spawn position. AiWander assumes that // pathgrid points are available, and uses them to randomly select wander // destinations within the allowed set of pathgrid points (nodes). - if(mDistance) + // ... pathgrids don't usually include water, so swimmers ignore them + if (mDistance && !actor.getClass().isPureWaterCreature(actor)) { float cellXOffset = 0; float cellYOffset = 0; From 256545205226c44320eb813397bd23021f0e8a31 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 17:08:10 +0300 Subject: [PATCH 0516/1812] Add some drag'n'drop utils to work with TableMimeData --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dragdroputils.cpp | 26 ++++++++++++++++++++ apps/opencs/view/world/dragdroputils.hpp | 30 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/dragdroputils.cpp create mode 100644 apps/opencs/view/world/dragdroputils.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fa703e4972..5386da707f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate - colordelegate + colordelegate dragdroputils ) opencs_units (view/widget diff --git a/apps/opencs/view/world/dragdroputils.cpp b/apps/opencs/view/world/dragdroputils.cpp new file mode 100644 index 0000000000..7f3974e539 --- /dev/null +++ b/apps/opencs/view/world/dragdroputils.cpp @@ -0,0 +1,26 @@ +#include "dragdroputils.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +const CSMWorld::TableMimeData *CSVWorld::DragDropUtils::getTableMimeData(const QDropEvent &event) +{ + return dynamic_cast(event.mimeData()); +} + +bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type) +{ + const CSMWorld::TableMimeData *data = getTableMimeData(event); + return data != NULL && data->holdsType(type); +} + +CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event, + CSMWorld::ColumnBase::Display type) +{ + if (canAcceptData(event, type)) + { + return getTableMimeData(event)->returnMatching(type); + } + return CSMWorld::UniversalId::Type_None; +} diff --git a/apps/opencs/view/world/dragdroputils.hpp b/apps/opencs/view/world/dragdroputils.hpp new file mode 100644 index 0000000000..88e2958a53 --- /dev/null +++ b/apps/opencs/view/world/dragdroputils.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_WORLD_DRAGDROPUTILS_HPP +#define CSV_WORLD_DRAGDROPUTILS_HPP + +#include "../../model/world/columnbase.hpp" + +class QDropEvent; + +namespace CSMWorld +{ + class TableMimeData; + class UniversalId; +} + +namespace CSVWorld +{ + class DragDropUtils + { + public: + static const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); + + static bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type + + static CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Gets the accepted data from the \a event using the \a type + ///< \return Type_None if the \a event data doesn't holds the \a type + }; +} + +#endif From a23de394f8ef2dd4c5fdb28b03cf8527cd42e3e0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 17:16:13 +0300 Subject: [PATCH 0517/1812] Refine DropLineEdit code --- apps/opencs/view/widget/droplineedit.cpp | 69 ++++-------------------- apps/opencs/view/widget/droplineedit.hpp | 17 ++---- apps/opencs/view/world/util.cpp | 2 +- 3 files changed, 14 insertions(+), 74 deletions(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 6dae157468..98f1d81c30 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -3,33 +3,20 @@ #include #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/universalid.hpp" -namespace -{ - const CSMWorld::TableMimeData *getEventMimeData(QDropEvent *event) - { - Q_ASSERT(event != NULL); - return dynamic_cast(event->mimeData()); - } -} +#include "../world/dragdroputils.hpp" -CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent) +CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent) : QLineEdit(parent), mDropType(type) { setAcceptDrops(true); } -CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent) - : QLineEdit(parent), - mDropType(CSMWorld::TableMimeData::convertEnums(display)) -{ - setAcceptDrops(true); -} - void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) { - if (canAcceptEventData(event)) + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { event->acceptProposedAction(); } @@ -37,7 +24,7 @@ void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event) void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) { - if (canAcceptEventData(event)) + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { event->accept(); } @@ -45,48 +32,10 @@ void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event) void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) { - const CSMWorld::TableMimeData *data = getEventMimeData(event); - if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped + if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { - return; - } - - int dataIndex = getAcceptedDataIndex(*data); - if (dataIndex != -1) - { - std::vector idData = data->getData(); - setText(idData[dataIndex].getId().c_str()); - emit tableMimeDataDropped(idData[dataIndex], data->getDocumentPtr()); + CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); + setText(id.getId().c_str()); + emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } - -bool CSVWidget::DropLineEdit::canAcceptEventData(QDropEvent *event) const -{ - const CSMWorld::TableMimeData *data = getEventMimeData(event); - if (data == NULL) // May happen when non-records (e.g. plain text) are dragged and dropped - { - return false; - } - return getAcceptedDataIndex(*data) != -1; -} - -int CSVWidget::DropLineEdit::getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const -{ - if (mDropType == CSMWorld::UniversalId::Type_None) - { - return 0; - } - - bool isReferenceable = mDropType == CSMWorld::UniversalId::Type_Referenceable; - std::vector idData = data.getData(); - int size = static_cast(idData.size()); - for (int i = 0; i < size; ++i) - { - CSMWorld::UniversalId::Type type = idData[i].getType(); - if (type == mDropType || isReferenceable && CSMWorld::TableMimeData::isReferencable(type)) - { - return i; - } - } - return -1; -} diff --git a/apps/opencs/view/widget/droplineedit.hpp b/apps/opencs/view/widget/droplineedit.hpp index ce086b7dc1..60832e71bc 100644 --- a/apps/opencs/view/widget/droplineedit.hpp +++ b/apps/opencs/view/widget/droplineedit.hpp @@ -4,7 +4,6 @@ #include #include "../../model/world/columnbase.hpp" -#include "../../model/world/universalid.hpp" namespace CSMDoc { @@ -14,6 +13,7 @@ namespace CSMDoc namespace CSMWorld { class TableMimeData; + class UniversalId; } namespace CSVWidget @@ -22,20 +22,11 @@ namespace CSVWidget { Q_OBJECT - CSMWorld::UniversalId::Type mDropType; - ///< The accepted ID type for this LineEdit. - ///< If \a mDropType has Type_None type, this LineEdit accepts all ID types - - bool canAcceptEventData(QDropEvent *event) const; - ///< Checks whether the \a event contains CSMWorld::TableMimeData with a proper ID type - - int getAcceptedDataIndex(const CSMWorld::TableMimeData &data) const; - ///< Checks whether the \a data has a proper type - ///< \return -1 if there is no suitable data (ID type) + CSMWorld::ColumnBase::Display mDropType; + ///< The accepted Display type for this LineEdit. public: - DropLineEdit(CSMWorld::UniversalId::Type type, QWidget *parent = 0); - DropLineEdit(CSMWorld::ColumnBase::Display display, QWidget *parent = 0); + DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent = 0); protected: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 8155055897..62cde4608a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -243,7 +243,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_String: // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used - return new CSVWidget::DropLineEdit(CSMWorld::UniversalId::Type_None, parent); + return new CSVWidget::DropLineEdit(display, parent); default: From 44582fe3b329d928934015cb2924daf52c964503 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 17:27:52 +0200 Subject: [PATCH 0518/1812] Don't use separate werewolf skills/attributes for non-player werewolves Still need to deal with save files. --- apps/openmw/mwmechanics/creaturestats.cpp | 11 ++--- apps/openmw/mwmechanics/creaturestats.hpp | 4 -- apps/openmw/mwmechanics/npcstats.cpp | 53 +++++++++-------------- apps/openmw/mwmechanics/npcstats.hpp | 5 ++- apps/openmw/mwworld/player.cpp | 49 +++++++++++++++++++++ apps/openmw/mwworld/player.hpp | 13 ++++++ apps/openmw/mwworld/worldimp.cpp | 11 +++++ components/esm/npcstats.cpp | 4 -- 8 files changed, 101 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 308e720279..e5cb561bf3 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -20,7 +20,7 @@ namespace MWMechanics mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), - mDeathAnimation(0), mIsWerewolf(false), mLevel (0) + mDeathAnimation(0), mLevel (0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; @@ -55,7 +55,7 @@ namespace MWMechanics if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); } - return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]); + return mAttributes[index]; } const DynamicStat &CreatureStats::getHealth() const @@ -139,14 +139,11 @@ namespace MWMechanics throw std::runtime_error("attribute index is out of range"); } - const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]; + const AttributeValue& currentValue = mAttributes[index]; if (value != currentValue) { - if(!mIsWerewolf) - mAttributes[index] = value; - else - mWerewolfAttributes[index] = value; + mAttributes[index] = value; if (index == ESM::Attribute::Intelligence) mRecalcMagicka = true; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 145eb8a5bf..146d9fb1eb 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -77,10 +77,6 @@ namespace MWMechanics std::vector mSummonGraveyard; protected: - // These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods. - bool mIsWerewolf; - AttributeValue mWerewolfAttributes[8]; - int mLevel; public: diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 94819e6260..577c76c97b 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -32,6 +32,7 @@ MWMechanics::NpcStats::NpcStats() , mWerewolfKills (0) , mLevelProgress(0) , mTimeToStartDrowning(20.0) + , mIsWerewolf(false) { mSkillIncreases.resize (ESM::Attribute::Length, 0); } @@ -51,7 +52,7 @@ const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); - return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); + return mSkill[index]; } MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) @@ -59,7 +60,15 @@ MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); - return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); + return mSkill[index]; +} + +void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue &value) +{ + if (index<0 || index>=ESM::Skill::Length) + throw std::runtime_error ("skill index out of range"); + + mSkill[index] = value; } const std::map& MWMechanics::NpcStats::getFactionRanks() const @@ -188,10 +197,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) { - // Don't increase skills as a werewolf - if(mIsWerewolf) - return; - const ESM::Skill *skill = MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); float skillGain = 1; @@ -403,34 +408,12 @@ bool MWMechanics::NpcStats::isWerewolf() const void MWMechanics::NpcStats::setWerewolf (bool set) { + if (mIsWerewolf == set) + return; + if(set != false) { - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - mWerewolfKills = 0; - - for(size_t i = 0;i < ESM::Attribute::Length;i++) - { - mWerewolfAttributes[i] = getAttribute(i); - // Oh, Bethesda. It's "Intelligence". - std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : - ESM::Attribute::sAttributeNames[i]); - mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat())); - } - - for(size_t i = 0;i < ESM::Skill::Length;i++) - { - mWerewolfSkill[i] = getSkill(i); - - // Acrobatics is set separately for some reason. - if(i == ESM::Skill::Acrobatics) - continue; - - // "Mercantile"! >_< - std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : - ESM::Skill::sSkillNames[i]); - mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat())); - } } mIsWerewolf = set; } @@ -466,12 +449,14 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const for (int i=0; i& getFactionRanks() const; /// Increase the rank in this faction by 1, if such a rank exists. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b81532e18..d0d99bfcfb 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -49,6 +49,55 @@ namespace MWWorld mPlayer.mData.setPosition(playerPos); } + void Player::saveSkillsAttributes() + { + MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + for (int i=0; i& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + for(size_t i = 0;i < ESM::Attribute::Length;++i) + { + // Oh, Bethesda. It's "Intelligence". + std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : + ESM::Attribute::sAttributeNames[i]); + + MWMechanics::AttributeValue value = stats.getAttribute(i); + value.setBase(int(gmst.find(name)->getFloat())); + stats.setAttribute(i, value); + } + + for(size_t i = 0;i < ESM::Skill::Length;i++) + { + // Acrobatics is set separately for some reason. + if(i == ESM::Skill::Acrobatics) + continue; + + // "Mercantile"! >_< + std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : + ESM::Skill::sSkillNames[i]); + + MWMechanics::SkillValue value = stats.getSkill(i); + value.setBase(int(gmst.find(name)->getFloat())); + stats.setSkill(i, value); + } + } + void Player::set(const ESM::NPC *player) { mPlayer.mBase = player; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 25d8981cde..2845c58228 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -6,6 +6,11 @@ #include "../mwmechanics/drawstate.hpp" +#include "../mwmechanics/stat.hpp" + +#include +#include + #include namespace ESM @@ -50,10 +55,18 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPaidCrimeId; // the last id paid off (0 bounty) + // Saved skills and attributes prior to becoming a werewolf + MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; + MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; + public: Player(const ESM::NPC *player, const MWBase::World& world); + void saveSkillsAttributes(); + void restoreSkillsAttributes(); + void setWerewolfSkillsAttributes(); + // For mark/recall magic effects void markPosition (CellStore* markedCell, ESM::Position markedPosition); void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f33f3d59b..f8de9f65b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2485,6 +2485,17 @@ namespace MWWorld if (npcStats.isWerewolf() == werewolf) return; + if (actor == getPlayerPtr()) + { + if (werewolf) + { + mPlayer->saveSkillsAttributes(); + mPlayer->setWerewolfSkillsAttributes(); + } + else + mPlayer->restoreSkillsAttributes(); + } + npcStats.setWerewolf(werewolf); // This is a bit dangerous. Equipped items other than WerewolfRobe may reference diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index cc1d6b3ddc..fa808b72f3 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -117,10 +117,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const mSkills[i].mWerewolf.save (esm); } - esm.writeHNT ("HWAT", true); - for (int i=0; i<8; ++i) - mWerewolfAttributes[i].save (esm); - if (mIsWerewolf) esm.writeHNT ("WOLF", mIsWerewolf); From d6a7255391425d34512b8b05ac27db1c6fdbf30f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 17:36:11 +0200 Subject: [PATCH 0519/1812] Loading/saving for player's original skills/attributes (prior to becoming a werewolf) --- apps/openmw/mwworld/player.cpp | 10 ++++++++++ components/esm/player.cpp | 13 +++++++++++++ components/esm/player.hpp | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d0d99bfcfb..e681bd7c5c 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -271,6 +271,11 @@ namespace MWWorld player.mAutoMove = mAutoMove ? 1 : 0; + for (int i=0; i mSaveAttributes[ESM::Attribute::Length]; + StatState mSaveSkills[ESM::Skill::Length]; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; From b9882eb59ab0c8a13d64b9ed7ffa7b1bdff0f12a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 18:40:13 +0300 Subject: [PATCH 0520/1812] DragRecordTable checks drag type before accepting it --- apps/opencs/view/world/dragrecordtable.cpp | 53 +++++++++++++++++++++- apps/opencs/view/world/dragrecordtable.hpp | 7 +++ apps/opencs/view/world/table.cpp | 30 ------------ apps/opencs/view/world/table.hpp | 2 - 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 2a1ae1f401..3712348e22 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -1,8 +1,14 @@ +#include "dragrecordtable.hpp" + #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/tablemimedata.hpp" -#include "dragrecordtable.hpp" +#include "../../model/world/commands.hpp" + +#include "dragdroputils.hpp" void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { @@ -35,5 +41,48 @@ void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event) void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) { - event->accept(); + QModelIndex index = indexAt(event->pos()); + if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index))) + { + event->accept(); + } + else + { + event->ignore(); + } +} + +void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); + if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) + { + const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event); + if (data->fromDocument(mDocument)) + { + CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display); + QVariant newIndexData = QString::fromUtf8(id.getId().c_str()); + QVariant oldIndexData = index.data(Qt::EditRole); + if (newIndexData != oldIndexData) + { + mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model(), index, newIndexData)); + } + } + } +} + +CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const +{ + Q_ASSERT(model() != NULL); + + if (index.isValid()) + { + QVariant display = model()->headerData(index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display); + if (display.isValid()) + { + return static_cast(display.toInt()); + } + } + return CSMWorld::ColumnBase::Display_None; } diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 48f9e25280..560864ba5a 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -4,6 +4,8 @@ #include #include +#include "../../model/world/columnbase.hpp" + class QWidget; class QAction; @@ -38,6 +40,11 @@ namespace CSVWorld void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); + + void dropEvent(QDropEvent *event); + + private: + CSMWorld::ColumnBase::Display getIndexDisplayType(const QModelIndex &index) const; }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 072b645c42..0ec701a65a 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -697,36 +697,6 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) } } -void CSVWorld::Table::dropEvent(QDropEvent *event) -{ - QModelIndex index = indexAt (event->pos()); - - if (!index.isValid()) - { - return; - } - - const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); - if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped - return; - - if (mime->fromDocument (mDocument)) - { - CSMWorld::ColumnBase::Display display = static_cast - (mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - - if (mime->holdsType (display)) - { - CSMWorld::UniversalId record (mime->returnMatching (display)); - - std::auto_ptr command (new CSMWorld::ModifyCommand - (*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str())))); - - mDocument.getUndoStack().push (command.release()); - } - } //TODO handle drops from different document -} - std::vector CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const { const int count = mModel->columnCount(); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 67bf3fe857..38fcd83bd6 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -76,8 +76,6 @@ namespace CSVWorld void mouseMoveEvent(QMouseEvent *event); - void dropEvent(QDropEvent *event); - protected: virtual void mouseDoubleClickEvent (QMouseEvent *event); From 2ce269c0fc2eff88d0dc0e2f7ce971255e842f1e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 18:18:24 +0200 Subject: [PATCH 0521/1812] Werewolf stats compatibility with old save files --- apps/openmw/mwmechanics/npcstats.cpp | 23 +++------------- apps/openmw/mwworld/player.cpp | 6 +++++ components/esm/esmreader.cpp | 11 ++++++++ components/esm/esmreader.hpp | 2 ++ components/esm/npcstats.cpp | 40 +++++++++++++++++++++------- components/esm/npcstats.hpp | 11 +++----- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 577c76c97b..b9aa8b301c 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -447,16 +447,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const state.mDisposition = mDisposition; for (int i=0; i > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0])); + + for (int i=0; i<27; ++i) + { + ESM::StatState skill; + skill.load(esm); + skills.push_back(skill); + } + + int i=0; + for (std::vector >::iterator it = skills.begin(); it != skills.end(); ++i) + { + if (i%2 == 1) + it = skills.erase(it); + else + ++it; + } + assert(skills.size() == 27); + std::copy(skills.begin(), skills.end(), mSkills); } + // No longer used bool hasWerewolfAttributes = false; esm.getHNOT (hasWerewolfAttributes, "HWAT"); - if (hasWerewolfAttributes) { + ESM::StatState dummy; for (int i=0; i<8; ++i) - mWerewolfAttributes[i].load (esm); + dummy.load(esm); + mWerewolfDeprecatedData = true; } mIsWerewolf = false; @@ -112,10 +136,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const esm.writeHNT ("DISP", mDisposition); for (int i=0; i<27; ++i) - { - mSkills[i].mRegular.save (esm); - mSkills[i].mWerewolf.save (esm); - } + mSkills[i].save (esm); if (mIsWerewolf) esm.writeHNT ("WOLF", mIsWerewolf); @@ -147,6 +168,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const void ESM::NpcStats::blank() { + mWerewolfDeprecatedData = false; mIsWerewolf = false; mDisposition = 0; mBounty = 0; diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index 0138ab2098..9b27f587c7 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -16,12 +16,6 @@ namespace ESM struct NpcStats { - struct Skill - { - StatState mRegular; - StatState mWerewolf; - }; - struct Faction { bool mExpelled; @@ -31,12 +25,13 @@ namespace ESM Faction(); }; - StatState mWerewolfAttributes[8]; bool mIsWerewolf; + bool mWerewolfDeprecatedData; + std::map mFactions; // lower case IDs int mDisposition; - Skill mSkills[27]; + StatState mSkills[27]; int mBounty; int mReputation; int mWerewolfKills; From d606b62688e14ea214d0939fec908c6996cf6b82 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 21 Jun 2015 21:35:00 +0300 Subject: [PATCH 0522/1812] Nested tables accept drops --- apps/opencs/view/world/dragrecordtable.cpp | 12 +++++++-- apps/opencs/view/world/nestedtable.cpp | 29 +++++++++------------- apps/opencs/view/world/nestedtable.hpp | 12 +++------ 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 3712348e22..8d01cff3ef 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -12,7 +12,13 @@ void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { - CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); + std::vector records = table.getDraggedRecords(); + if (records.empty()) + { + return; + } + + CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (records, mDocument); if (mime) { @@ -27,7 +33,9 @@ CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget* QTableView(parent), mDocument(document), mEditLock(false) -{} +{ + setAcceptDrops(true); +} void CSVWorld::DragRecordTable::setEditLock (bool locked) { diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 112873cb9a..92df59a5fc 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -14,8 +14,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, QWidget* parent) - : QTableView(parent), - mUndoStack(document.getUndoStack()), + : DragRecordTable(document, parent), mModel(model) { mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); @@ -47,8 +46,6 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, setModel(model); - setAcceptDrops(true); - mAddNewRowAction = new QAction (tr ("Add new row"), this); connect(mAddNewRowAction, SIGNAL(triggered()), @@ -60,12 +57,10 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, this, SLOT(removeRowActionTriggered())); } -void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) -{ -} - -void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) +std::vector CSVWorld::NestedTable::getDraggedRecords() const { + // No drag support for nested tables + return std::vector(); } void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) @@ -84,16 +79,16 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) void CSVWorld::NestedTable::removeRowActionTriggered() { - mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), - mModel->getParentId(), - selectionModel()->selectedRows().begin()->row(), - mModel->getParentColumn())); + mDocument.getUndoStack().push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().begin()->row(), + mModel->getParentColumn())); } void CSVWorld::NestedTable::addNewRowActionTriggered() { - mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), - mModel->getParentId(), - selectionModel()->selectedRows().size(), - mModel->getParentColumn())); + mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().size(), + mModel->getParentColumn())); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 5db977942a..1129204011 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -1,10 +1,10 @@ #ifndef CSV_WORLD_NESTEDTABLE_H #define CSV_WORLD_NESTEDTABLE_H -#include #include -class QUndoStack; +#include "dragrecordtable.hpp" + class QAction; class QContextMenuEvent; @@ -22,13 +22,12 @@ namespace CSMDoc namespace CSVWorld { - class NestedTable : public QTableView + class NestedTable : public DragRecordTable { Q_OBJECT QAction *mAddNewRowAction; QAction *mRemoveRowAction; - QUndoStack& mUndoStack; CSMWorld::NestedTableProxyModel* mModel; CSMWorld::CommandDispatcher *mDispatcher; @@ -38,10 +37,7 @@ namespace CSVWorld CSMWorld::NestedTableProxyModel* model, QWidget* parent = NULL); - protected: - void dragEnterEvent(QDragEnterEvent *event); - - void dragMoveEvent(QDragMoveEvent *event); + virtual std::vector getDraggedRecords() const; private: void contextMenuEvent (QContextMenuEvent *event); From 3f54f77647923571a42b4ceb5c18295ce25496c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Jun 2015 22:15:35 +0200 Subject: [PATCH 0523/1812] essimporter build fix --- apps/essimporter/convertacdt.cpp | 6 +++--- apps/essimporter/convertplayer.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 55a20ec3df..8f090b3fc4 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -41,9 +41,9 @@ namespace ESSImport { for (int i=0; i Date: Mon, 22 Jun 2015 21:06:27 +0200 Subject: [PATCH 0524/1812] Move head tracking from NpcAnimation to Animation (Bug #2720) --- apps/openmw/mwrender/animation.cpp | 48 ++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 15 ++++--- apps/openmw/mwrender/creatureanimation.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 44 ++------------------ apps/openmw/mwrender/npcanimation.hpp | 10 ----- 5 files changed, 62 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3801cf6fc8..5955fc4cfd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,6 +41,7 @@ #include "vismask.hpp" #include "util.hpp" +#include "rotatecontroller.hpp" namespace { @@ -257,6 +258,8 @@ namespace MWRender , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) , mTextKeyListener(NULL) + , mHeadYawRadians(0.f) + , mHeadPitchRadians(0.f) { for(size_t i = 0;i < sNumGroups;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -900,6 +903,15 @@ namespace MWRender updateEffects(duration); + if (mHeadController) + { + const float epsilon = 0.001f; + bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); + mHeadController->setEnabled(enable); + if (enable) + mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); + } + return movement; } @@ -1212,6 +1224,42 @@ namespace MWRender return found->second; } + void Animation::addControllers() + { + mHeadController = NULL; + + NodeMap::iterator found = mNodeMap.find("bip01 head"); + if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } + } + + void Animation::setHeadPitch(float pitchRadians) + { + mHeadPitchRadians = pitchRadians; + } + + void Animation::setHeadYaw(float yawRadians) + { + mHeadYawRadians = yawRadians; + } + + float Animation::getHeadPitch() const + { + return mHeadPitchRadians; + } + + float Animation::getHeadYaw() const + { + return mHeadYawRadians; + } + + // ------------------------------------------------------ + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { if (mTimePtr) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d80fd96a4f..1140fb172e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,6 +25,7 @@ namespace MWRender { class ResetAccumRootCallback; +class RotateController; class EffectAnimationTime : public SceneUtil::ControllerSource { @@ -197,6 +198,10 @@ protected: TextKeyListener* mTextKeyListener; + osg::ref_ptr mHeadController; + float mHeadYawRadians; + float mHeadPitchRadians; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -243,7 +248,7 @@ protected: * Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers * so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering. */ - virtual void addControllers() {} + virtual void addControllers(); osg::Vec4f getEnchantmentColor(MWWorld::Ptr item); @@ -374,10 +379,10 @@ public: /// @param effect Controls the radius and intensity of the light. virtual void setLightEffect(float effect) {} - virtual void setHeadPitch(float pitchRadians) {} - virtual void setHeadYaw(float yawRadians) {} - virtual float getHeadPitch() const {return 0.f;} - virtual float getHeadYaw() const {return 0.f;} + virtual void setHeadPitch(float pitchRadians); + virtual void setHeadYaw(float yawRadians); + virtual float getHeadPitch() const; + virtual float getHeadYaw() const; private: Animation(const Animation&); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9d1fccdb2c..ec4ee99e4d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -174,6 +174,7 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() void CreatureWeaponAnimation::addControllers() { + Animation::addControllers(); WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 21ec8d535c..2f20154321 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -243,9 +243,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowCarriedLeft(true), mNpcType(Type_Normal), mAlpha(1.f), - mSoundsDisabled(disableSounds), - mHeadYawRadians(0.f), - mHeadPitchRadians(0.f) + mSoundsDisabled(disableSounds) { mNpc = mPtr.get()->mBase; @@ -650,40 +648,11 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) mFirstPersonNeckController->setOffset(mFirstPersonOffset); } - if (mHeadController) - { - const float epsilon = 0.001f; - bool enable = (std::abs(mHeadPitchRadians) > epsilon || std::abs(mHeadYawRadians) > epsilon); - mHeadController->setEnabled(enable); - if (enable) - mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); - } - WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]); return ret; } -void NpcAnimation::setHeadPitch(float pitchRadians) -{ - mHeadPitchRadians = pitchRadians; -} - -void NpcAnimation::setHeadYaw(float yawRadians) -{ - mHeadYawRadians = yawRadians; -} - -float NpcAnimation::getHeadPitch() const -{ - return mHeadPitchRadians; -} - -float NpcAnimation::getHeadYaw() const -{ - return mHeadYawRadians; -} - void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) { mPartPriorities[type] = 0; @@ -843,6 +812,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector(found->second.get())) - { - osg::Node* node = found->second; - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); - } - WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 3eb4c4754b..726d88605e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -49,7 +49,6 @@ public: }; class NeckController; -class RotateController; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { @@ -101,9 +100,6 @@ private: float mAlpha; bool mSoundsDisabled; - float mHeadYawRadians; - float mHeadPitchRadians; - void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, @@ -119,7 +115,6 @@ private: bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); osg::ref_ptr mFirstPersonNeckController; - osg::ref_ptr mHeadController; protected: virtual void addControllers(); @@ -151,11 +146,6 @@ public: /// to indicate the facing orientation of the character. virtual void setPitchFactor(float factor) { mPitchFactor = factor; } - virtual void setHeadPitch(float pitchRadians); - virtual void setHeadYaw(float yawRadians); - virtual float getHeadPitch() const; - virtual float getHeadYaw() const; - virtual void showWeapons(bool showWeapon); virtual void showCarriedLeft(bool show); From d5b73f2a558a8aa92ec338a2899921ae20e4435e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Jun 2015 21:12:15 +0200 Subject: [PATCH 0525/1812] Move HeadAnimationTime to the implementation file --- apps/openmw/mwrender/npcanimation.cpp | 35 +++++++++++++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 34 +------------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2f20154321..81782873e4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -75,6 +75,41 @@ std::string getVampireHead(const std::string& race, bool female) namespace MWRender { +class HeadAnimationTime : public SceneUtil::ControllerSource +{ +private: + MWWorld::Ptr mReference; + float mTalkStart; + float mTalkStop; + float mBlinkStart; + float mBlinkStop; + + float mBlinkTimer; + + bool mEnabled; + + float mValue; +private: + void resetBlinkTimer(); +public: + HeadAnimationTime(MWWorld::Ptr reference); + + void updatePtr(const MWWorld::Ptr& updated); + + void update(float dt); + + void setEnabled(bool enabled); + + void setTalkStart(float value); + void setTalkStop(float value); + void setBlinkStart(float value); + void setBlinkStop(float value); + + virtual float getValue(osg::NodeVisitor* nv); +}; + +// -------------------------------------------------------------------------------- + /// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note Must be set on a MatrixTransform. diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 726d88605e..493629bdac 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,40 +15,8 @@ namespace ESM namespace MWRender { -class HeadAnimationTime : public SceneUtil::ControllerSource -{ -private: - MWWorld::Ptr mReference; - float mTalkStart; - float mTalkStop; - float mBlinkStart; - float mBlinkStop; - - float mBlinkTimer; - - bool mEnabled; - - float mValue; -private: - void resetBlinkTimer(); -public: - HeadAnimationTime(MWWorld::Ptr reference); - - void updatePtr(const MWWorld::Ptr& updated); - - void update(float dt); - - void setEnabled(bool enabled); - - void setTalkStart(float value); - void setTalkStop(float value); - void setBlinkStart(float value); - void setBlinkStop(float value); - - virtual float getValue(osg::NodeVisitor* nv); -}; - class NeckController; +class HeadAnimationTime; class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { From d7695f2560dd36ef3b488daf263abb839361a7aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Jun 2015 21:14:44 +0200 Subject: [PATCH 0526/1812] Remove unused NpcAnimation visibilityFlags --- apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.hpp | 5 +---- apps/openmw/mwrender/objects.cpp | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index d6c30da971..32e51c4d6d 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -158,7 +158,7 @@ namespace MWRender delete mAnimation; mAnimation = NULL; - mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, 0, true, true, + mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); onSetup(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 81782873e4..0e16d8eccc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -270,7 +270,7 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, int visibilityFlags, bool disableListener, bool disableSounds, ViewMode viewMode) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode) : Animation(ptr, parentNode, resourceSystem), mListenerDisabled(disableListener), mViewMode(viewMode), diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 493629bdac..2c1c66b8ec 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -90,8 +90,6 @@ protected: public: /** * @param ptr - * @param node - * @param visibilityFlags * @param disableListener Don't listen for equipment changes and magic effects. InventoryStore only supports * one listener at a time, so you shouldn't do this if creating several NpcAnimations * for the same Ptr, eg preview dolls for the player. @@ -99,8 +97,7 @@ public: * @param disableSounds Same as \a disableListener but for playing items sounds * @param viewMode */ - NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, - int visibilityFlags, bool disableListener = false, + NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener = false, bool disableSounds = false, ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 39e9f56520..bdefdcafa3 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -156,7 +156,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) insertBegin(ptr); ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor); - std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem, 0)); + std::auto_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem)); mObjects.insert(std::make_pair(ptr, anim.release())); } From d3ef0759521c0ae0657769a7d0f373b8aa6be89b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Jun 2015 05:06:49 +0200 Subject: [PATCH 0527/1812] Fix an uninitialized variable --- components/esm/npcstats.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 6394a29da6..e854410b1f 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -32,6 +32,7 @@ void ESM::NpcStats::load (ESMReader &esm) for (int i=0; i<27; ++i) mSkills[i].load (esm); + mWerewolfDeprecatedData = false; if (esm.peekNextSub("STBA")) { // we have deprecated werewolf skills, stored interleaved From 33a3dabc313665a83384b373a5f5decba8974e54 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 24 Jun 2015 03:50:36 +0200 Subject: [PATCH 0528/1812] An alchemy effect listed more than once in the same ingredient should not automatically create a potion of that effect (Bug #2722) --- apps/openmw/mwmechanics/alchemy.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 58c42ddb81..1d43c71ffa 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -44,6 +44,8 @@ std::set MWMechanics::Alchemy::listEffects() const { const MWWorld::LiveCellRef *ingredient = iter->get(); + std::set seenEffects; + for (int i=0; i<4; ++i) if (ingredient->mBase->mData.mEffectID[i]!=-1) { @@ -51,7 +53,8 @@ std::set MWMechanics::Alchemy::listEffects() const ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ? ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]); - ++effects[key]; + if (seenEffects.insert(key).second) + ++effects[key]; } } } From 6f34a0501a0d8a2562716fd009983644e9d4ca5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 24 Jun 2015 03:52:27 +0200 Subject: [PATCH 0529/1812] Attempting to make a potion with no effects removes the ingredients (Fixes #2722) --- apps/openmw/mwmechanics/alchemy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 1d43c71ffa..2fc9fe42f8 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -463,7 +463,10 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_NoName; if (listEffects().empty()) + { + removeIngredients(); return Result_NoEffects; + } if (beginEffects() == endEffects()) { From d1339a643afced0d1e502eebe79c947b2c4ad953 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 15:07:09 +0300 Subject: [PATCH 0530/1812] Fix for NestedTableProxyModel::forwardDataChanged() --- apps/opencs/model/world/nestedtableproxymodel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index acf1977168..052e629aac 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top emit dataChanged(index(0,0), index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); } + else if (topLeft.parent() == parent && bottomRight.parent() == parent) + { + emit dataChanged(index(topLeft.row(), topLeft.column()), index(bottomRight.row(), bottomRight.column())); + } } From 270c17faa786917ac03f44906c055eec70da577d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 16:36:09 +0300 Subject: [PATCH 0531/1812] Prevent drops on non-editable table cells --- apps/opencs/view/world/dragrecordtable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 8d01cff3ef..5e8ddae26d 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -52,7 +52,10 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) QModelIndex index = indexAt(event->pos()); if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index))) { - event->accept(); + if (index.flags() & Qt::ItemIsEditable) + { + event->accept(); + } } else { From e29d9bcc8eac923ecf90c73733302033e01c2700 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 24 Jun 2015 17:29:47 +0200 Subject: [PATCH 0532/1812] use a namespace instead of a class with only static functions --- apps/opencs/view/world/dragdroputils.hpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dragdroputils.hpp b/apps/opencs/view/world/dragdroputils.hpp index 88e2958a53..d1d780708e 100644 --- a/apps/opencs/view/world/dragdroputils.hpp +++ b/apps/opencs/view/world/dragdroputils.hpp @@ -13,18 +13,17 @@ namespace CSMWorld namespace CSVWorld { - class DragDropUtils + namespace DragDropUtils { - public: - static const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); + const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event); - static bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); - ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type + bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type - static CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); - ///< Gets the accepted data from the \a event using the \a type - ///< \return Type_None if the \a event data doesn't holds the \a type - }; + CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Gets the accepted data from the \a event using the \a type + ///< \return Type_None if the \a event data doesn't holds the \a type + } } #endif From 21f0b586ec1d09828cf75117804b09df3c480f64 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 24 Jun 2015 20:01:29 +0300 Subject: [PATCH 0533/1812] Rows with the same topic but in different letter case can be reordered --- apps/opencs/model/world/infocollection.cpp | 3 ++- apps/opencs/view/world/table.cpp | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index a508d28f3d..560be8131e 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/data.hpp" @@ -128,17 +130,24 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { int row = mProxyModel->mapToSource ( mProxyModel->index (selectedRows.begin()->row(), 0)).row(); + QString curData = mModel->data(mModel->index(row, column)).toString(); - if (row>0 && mModel->data (mModel->index (row, column))== - mModel->data (mModel->index (row-1, column))) + if (row > 0) { - menu.addAction (mMoveUpAction); + QString prevData = mModel->data(mModel->index(row - 1, column)).toString(); + if (Misc::StringUtils::ciEqual(curData.toStdString(), prevData.toStdString())) + { + menu.addAction(mMoveUpAction); + } } - if (rowrowCount()-1 && mModel->data (mModel->index (row, column))== - mModel->data (mModel->index (row+1, column))) + if (row < mModel->rowCount() - 1) { - menu.addAction (mMoveDownAction); + QString nextData = mModel->data(mModel->index(row + 1, column)).toString(); + if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString())) + { + menu.addAction(mMoveDownAction); + } } } } From 5b82b9d9d0efc0a395c289e546bd87cae00dcea3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 11:20:35 +0300 Subject: [PATCH 0534/1812] ReferenceCreator accepts drops of Cell ID --- apps/opencs/view/world/referencecreator.cpp | 5 +++-- apps/opencs/view/world/referencecreator.hpp | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 81efb17ab6..2b0d44df0c 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -2,7 +2,6 @@ #include "referencecreator.hpp" #include -#include #include "../../model/doc/document.hpp" @@ -12,6 +11,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + std::string CSVWorld::ReferenceCreator::getId() const { return mId; @@ -80,7 +81,7 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& QLabel *label = new QLabel ("Cell", this); insertBeforeButtons (label, false); - mCell = new QLineEdit (this); + mCell = new CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this); mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); insertBeforeButtons (mCell, true); diff --git a/apps/opencs/view/world/referencecreator.hpp b/apps/opencs/view/world/referencecreator.hpp index 7f56143c9f..c230d01268 100644 --- a/apps/opencs/view/world/referencecreator.hpp +++ b/apps/opencs/view/world/referencecreator.hpp @@ -3,13 +3,16 @@ #include "genericcreator.hpp" -class QLineEdit; - namespace CSMWorld { class IdCompletionManager; } +namespace CSVWidget +{ + class DropLineEdit; +} + namespace CSVWorld { @@ -17,7 +20,7 @@ namespace CSVWorld { Q_OBJECT - QLineEdit *mCell; + CSVWidget::DropLineEdit *mCell; std::string mId; private: From d282bead236fe73611dba32f15220e6b73a1ca10 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 11:24:19 +0300 Subject: [PATCH 0535/1812] InfoCreator accepts drops of Topic/Journal ID --- apps/opencs/view/world/infocreator.cpp | 5 +++-- apps/opencs/view/world/infocreator.hpp | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 916427fc24..268a82a280 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -17,6 +16,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../widget/droplineedit.hpp" + std::string CSVWorld::InfoCreator::getId() const { std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData()); @@ -48,12 +49,12 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, QLabel *label = new QLabel ("Topic", this); insertBeforeButtons (label, false); - mTopic = new QLineEdit (this); CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) { displayType = CSMWorld::ColumnBase::Display_Journal; } + mTopic = new CSVWidget::DropLineEdit(displayType, this); mTopic->setCompleter(completionManager.getCompleter(displayType).get()); insertBeforeButtons (mTopic, true); diff --git a/apps/opencs/view/world/infocreator.hpp b/apps/opencs/view/world/infocreator.hpp index 1928004bb9..d131e3fac5 100644 --- a/apps/opencs/view/world/infocreator.hpp +++ b/apps/opencs/view/world/infocreator.hpp @@ -3,21 +3,24 @@ #include "genericcreator.hpp" -class QLineEdit; - namespace CSMWorld { class InfoCollection; class IdCompletionManager; } +namespace CSVWidget +{ + class DropLineEdit; +} + namespace CSVWorld { class InfoCreator : public GenericCreator { Q_OBJECT - QLineEdit *mTopic; + CSVWidget::DropLineEdit *mTopic; virtual std::string getId() const; From 6fbdbb11d5c332913aa20d57707063245fb36d92 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 25 Jun 2015 12:03:40 +0200 Subject: [PATCH 0536/1812] added refrash menu item to report table (Fixes #2620) --- apps/opencs/model/doc/document.cpp | 4 ++-- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 13 +++++++++---- apps/opencs/model/tools/tools.hpp | 7 +++++-- apps/opencs/view/tools/reportsubview.cpp | 22 ++++++++++++++++++++-- apps/opencs/view/tools/reportsubview.hpp | 6 ++++++ apps/opencs/view/tools/reporttable.cpp | 18 ++++++++++++++++-- apps/opencs/view/tools/reporttable.hpp | 9 ++++++++- 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e6ae54550..cb349d8be3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2369,9 +2369,9 @@ void CSMDoc::Document::save() emit stateChanged (getState(), this); } -CSMWorld::UniversalId CSMDoc::Document::verify() +CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId) { - CSMWorld::UniversalId id = mTools.runVerifier(); + CSMWorld::UniversalId id = mTools.runVerifier (reportId); emit stateChanged (getState(), this); return id; } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4aaaf40b03..557f3cb23c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -120,7 +120,7 @@ namespace CSMDoc void save(); - CSMWorld::UniversalId verify(); + CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId()); CSMWorld::UniversalId newSearch(); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index f0d649f388..c9c1160918 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -146,14 +146,19 @@ CSMTools::Tools::~Tools() delete iter->second; } -CSMWorld::UniversalId CSMTools::Tools::runVerifier() +CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId) { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); - mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; + int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ? + reportId.getIndex() : mNextReportNumber++; + + if (mReports.find (reportNumber)==mReports.end()) + mReports.insert (std::make_pair (reportNumber, new ReportModel)); + + mActiveReports[CSMDoc::State_Verifying] = reportNumber; getVerifier()->start(); - return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber); } CSMWorld::UniversalId CSMTools::Tools::newSearch() diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 2912fc4717..78484d15d9 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -57,8 +57,11 @@ namespace CSMTools virtual ~Tools(); - CSMWorld::UniversalId runVerifier(); - ///< \return ID of the report for this verification run + /// \param reportId If a valid VerificationResults ID, run verifier for the + /// specified report instead of creating a new one. + /// + /// \return ID of the report for this verification run + CSMWorld::UniversalId runVerifier (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId()); /// Return ID of the report for this search. CSMWorld::UniversalId newSearch(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 492874c01b..42c4d40da0 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -4,12 +4,18 @@ #include "reporttable.hpp" CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mDocument (document), mRefreshState (0) { - setWidget (mTable = new ReportTable (document, id, false, this)); + if (id.getType()==CSMWorld::UniversalId::Type_VerificationResults) + mRefreshState = CSMDoc::State_Verifying; + + setWidget (mTable = new ReportTable (document, id, false, mRefreshState, this)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + + if (mRefreshState==CSMDoc::State_Verifying) + connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest())); } void CSVTools::ReportSubView::setEditLock (bool locked) @@ -21,3 +27,15 @@ void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStr { mTable->updateUserSetting (name, list); } + +void CSVTools::ReportSubView::refreshRequest() +{ + if (!(mDocument.getState() & mRefreshState)) + { + if (mRefreshState==CSMDoc::State_Verifying) + { + mTable->clear(); + mDocument.verify (getUniversalId()); + } + } +} diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index 7e8a08e3cd..b8eb2690a7 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -20,6 +20,8 @@ namespace CSVTools Q_OBJECT ReportTable *mTable; + CSMDoc::Document& mDocument; + int mRefreshState; public: @@ -28,6 +30,10 @@ namespace CSVTools virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString &, const QStringList &); + + private slots: + + void refreshRequest(); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index e530e1159e..6ef88bfdd8 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -74,7 +74,12 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) if (found) menu.addAction (mReplaceAction); + } + if (mRefreshAction) + { + mRefreshAction->setEnabled ((mDocument.getState() & mRefreshState)==0); + menu.addAction (mRefreshAction); } menu.exec (event->globalPos()); @@ -134,8 +139,10 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) } CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, - const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) -: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) + const CSMWorld::UniversalId& id, bool richTextDescription, int refreshState, + QWidget *parent) +: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)), + mRefreshAction (0), mRefreshState (refreshState) { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); @@ -171,6 +178,13 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); addAction (mReplaceAction); + if (mRefreshState) + { + mRefreshAction = new QAction (tr ("Refresh"), this); + connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); + addAction (mRefreshAction); + } + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 95ab07cbbf..4f77a57c4e 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -36,7 +36,9 @@ namespace CSVTools QAction *mShowAction; QAction *mRemoveAction; QAction *mReplaceAction; + QAction *mRefreshAction; std::map mDoubleClickActions; + int mRefreshState; private: @@ -49,8 +51,11 @@ namespace CSVTools public: /// \param richTextDescription Use rich text in the description column. + /// \param refreshState Document state to check for refresh function. If value is + /// 0 no refresh function exists. If the document current has the specified state + /// the refresh function is disabled. ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, - bool richTextDescription, QWidget *parent = 0); + bool richTextDescription, int refreshState = 0, QWidget *parent = 0); virtual std::vector getDraggedRecords() const; @@ -76,6 +81,8 @@ namespace CSVTools void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); void replaceRequest(); + + void refreshRequest(); }; } From 71f3b7ed4f6ab80592dfbf4ef03669e5909535b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 25 Jun 2015 20:21:51 +1000 Subject: [PATCH 0537/1812] Fix crash when user preference is missing. --- apps/opencs/model/tools/scriptcheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 928ae156f8..665edd7a33 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -120,7 +120,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) { - if (name=="script-editor/warnings") + if (name=="script-editor/warnings" && !value.isEmpty()) { if (value.at (0)=="Ignore") mWarningMode = Mode_Ignore; From c0f3d70f0662b79c2a8fd66fdef0f8ec61e61f50 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 25 Jun 2015 20:23:43 +1000 Subject: [PATCH 0538/1812] Use the new severity message attribute. --- apps/opencs/model/tools/pathgridcheck.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 76edeb573d..69ee5a8098 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message // check the number of pathgrid points if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) - messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); + messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error); else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) - messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); + messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error); std::vector pointList(pathgrid.mPoints.size()); std::vector duplList; @@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message std::ostringstream ss; ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 << " and " << pathgrid.mEdges[i].mV1; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); break; } } @@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -75,13 +75,13 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has has less edges than expected for point " << i; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) { std::ostringstream ss; ss << " has has more edges than expected for point " << i; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } // check that edges are bidirectional @@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message { std::ostringstream ss; ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -124,7 +124,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message << ") x=" << pathgrid.mPoints[i].mX << ", y=" << pathgrid.mPoints[i].mY << ", z=" << pathgrid.mPoints[i].mZ; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); duplList.push_back(i); break; @@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message << ") x=" << pathgrid.mPoints[i].mX << ", y=" << pathgrid.mPoints[i].mY << ", z=" << pathgrid.mPoints[i].mZ; - messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); + messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); } } From 69db0179ca104699d70142286a5a1d226177644f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 25 Jun 2015 13:05:57 +0200 Subject: [PATCH 0539/1812] update refresh menu item on stateChanged signal instead of when opening the menu --- apps/opencs/view/tools/reportsubview.cpp | 5 +++++ apps/opencs/view/tools/reporttable.cpp | 10 +++++++--- apps/opencs/view/tools/reporttable.hpp | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 42c4d40da0..e29447f250 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -15,7 +15,12 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc: SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); if (mRefreshState==CSMDoc::State_Verifying) + { connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest())); + + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + mTable, SLOT (stateChanged (int, CSMDoc::Document *))); + } } void CSVTools::ReportSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 6ef88bfdd8..ca6b0dabfb 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -77,10 +77,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) } if (mRefreshAction) - { - mRefreshAction->setEnabled ((mDocument.getState() & mRefreshState)==0); menu.addAction (mRefreshAction); - } menu.exec (event->globalPos()); } @@ -181,6 +178,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, if (mRefreshState) { mRefreshAction = new QAction (tr ("Refresh"), this); + mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState)); connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); addAction (mRefreshAction); } @@ -301,3 +299,9 @@ void CSVTools::ReportTable::clear() { mModel->clear(); } + +void CSVTools::ReportTable::stateChanged (int state, CSMDoc::Document *document) +{ + if (mRefreshAction) + mRefreshAction->setEnabled (!(state & mRefreshState)); +} diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 4f77a57c4e..e19b327e45 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -76,6 +76,10 @@ namespace CSVTools void removeSelection(); + public slots: + + void stateChanged (int state, CSMDoc::Document *document); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 3a21f05f6eb05623f8179b4e0ff889f7dbe258a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 17:23:01 +0200 Subject: [PATCH 0540/1812] Rain effect --- apps/openmw/mwrender/sky.cpp | 155 +++++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 16 +++- 2 files changed, 152 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e2f3dd82b5..96771eaa35 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -7,10 +7,16 @@ #include #include #include - #include #include +#include +#include +#include +#include +#include +#include + #include #include @@ -573,6 +579,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mRainEnabled(false) , mRainSpeed(0) , mRainFrequency(1) + , mWindSpeed(0.f) , mEnabled(true) , mSunEnabled(true) { @@ -642,9 +649,112 @@ void SkyManager::create() mCreated = true; } +class RainShooter : public osgParticle::Shooter +{ +public: + RainShooter() + : mAngle(0.f) + { + } + + virtual void shoot(osgParticle::Particle* particle) const + { + particle->setVelocity(mVelocity); + particle->setAngle(osg::Vec3f(-mAngle, 0, (Misc::Rng::rollProbability() * 2 - 1) * osg::PI)); + } + + void setVelocity(const osg::Vec3f& velocity) + { + mVelocity = velocity; + } + + void setAngle(float angle) + { + mAngle = angle; + } + + virtual osg::Object* cloneType() const + { + return new RainShooter; + } + virtual osg::Object* clone(const osg::CopyOp &) const + { + return new RainShooter(*this); + } + +private: + osg::Vec3f mVelocity; + float mAngle; +}; + +void SkyManager::createRain() +{ + if (mRainNode) + return; + + mRainNode = new osg::Group; + + mRainParticleSystem = new osgParticle::ParticleSystem; + mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); + mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); + mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1)); + + osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); + stateset->setTextureAttributeAndModes(0, mSceneManager->getTextureManager()->getTexture2D("textures/tx_raindrop_01.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP), osg::StateAttribute::ON); + stateset->setNestRenderBins(false); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); + particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f)); + particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 1.f)); + particleTemplate.setLifeTime(1); + + osg::ref_ptr emitter (new osgParticle::ModularEmitter); + emitter->setParticleSystem(mRainParticleSystem); + + osg::ref_ptr placer (new osgParticle::BoxPlacer); + placer->setXRange(-300, 300); // Rain_Diameter + placer->setYRange(-300, 300); + placer->setZRange(300, 300); + emitter->setPlacer(placer); + + osg::ref_ptr counter (new osgParticle::ConstantRateCounter); + counter->setNumberOfParticlesPerSecondToCreate(600.0); + emitter->setCounter(counter); + + osg::ref_ptr shooter (new RainShooter); + mRainShooter = shooter; + emitter->setShooter(shooter); + + osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); + updater->addParticleSystem(mRainParticleSystem); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(mRainParticleSystem); + + mRainNode->addChild(emitter); + mRainNode->addChild(geode); + mRainNode->addChild(updater); + + mRootNode->addChild(mRainNode); +} + +void SkyManager::destroyRain() +{ + if (!mRainNode) + return; + + mRootNode->removeChild(mRainNode); + mRainNode = NULL; + mRainParticleSystem = NULL; + mRainShooter = NULL; +} + SkyManager::~SkyManager() { - clearRain(); if (mRootNode) { mRootNode->getParent(0)->removeChild(mRootNode); @@ -664,14 +774,6 @@ int SkyManager::getSecundaPhase() const return mSecunda->getPhaseInt(); } -void SkyManager::clearRain() -{ -} - -void SkyManager::updateRain(float dt) -{ -} - void SkyManager::update(float duration) { if (!mEnabled) return; @@ -688,8 +790,6 @@ void SkyManager::update(float duration) else mCloudNode->setAttitude(osg::Quat()); - updateRain(duration); - // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed * 0.003; mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); @@ -736,9 +836,6 @@ void SkyManager::setEnabled(bool enabled) if (enabled && !mCreated) create(); - if (!enabled) - clearRain(); - mRootNode->setNodeMask(enabled ? Mask_Sky : 0); mEnabled = enabled; @@ -750,14 +847,38 @@ void SkyManager::setMoonColour (bool red) mSecunda->setColor(red ? mMoonScriptColor : osg::Vec4f(1,1,1,1)); } +void SkyManager::updateRainParameters() +{ + if (mRainShooter) + { + float angle = mWindSpeed/2.f * osg::PI/4; + mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * mWindSpeed / 2.f, -mRainSpeed)); + mRainShooter->setAngle(angle); + } +} + void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { if (!mCreated) return; - mRainEffect = weather.mRainEffect; - mRainEnabled = !mRainEffect.empty(); + if (mRainEffect != weather.mRainEffect) + { + mRainEffect = weather.mRainEffect; + if (!mRainEffect.empty()) + { + createRain(); + } + else + { + destroyRain(); + } + } + mRainFrequency = weather.mRainFrequency; mRainSpeed = weather.mRainSpeed; + mWindSpeed = weather.mWindSpeed; + updateRainParameters(); + mIsStorm = weather.mIsStorm; if (mCurrentParticleEffect != weather.mParticleEffect) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index b05845e53c..f9b9407ecc 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -12,6 +12,11 @@ namespace osg class Material; } +namespace osgParticle +{ + class ParticleSystem; +} + namespace Resource { class SceneManager; @@ -24,6 +29,7 @@ namespace MWRender class CloudUpdater; class Sun; class Moon; + class RainShooter; class SkyManager { @@ -87,8 +93,9 @@ namespace MWRender void create(); ///< no need to call this, automatically done on first enable() - void updateRain(float dt); - void clearRain(); + void createRain(); + void destroyRain(); + void updateRainParameters(); Resource::SceneManager* mSceneManager; @@ -116,6 +123,10 @@ namespace MWRender std::auto_ptr mMasser; std::auto_ptr mSecunda; + osg::ref_ptr mRainNode; + osg::ref_ptr mRainParticleSystem; + osg::ref_ptr mRainShooter; + bool mCreated; bool mIsStorm; @@ -151,6 +162,7 @@ namespace MWRender std::string mRainEffect; float mRainSpeed; float mRainFrequency; + float mWindSpeed; bool mEnabled; bool mSunEnabled; From 8a3889a81eef72e9113b4c9cb5b8090b933b0bcb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 17:38:08 +0200 Subject: [PATCH 0541/1812] Rain fading --- apps/openmw/mwrender/sky.cpp | 46 ++++++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 2 ++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 96771eaa35..e5563409d7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -687,6 +687,37 @@ private: float mAngle; }; +class RainFader : public SceneUtil::StateSetUpdater +{ +public: + RainFader() + : mAlpha(1.f) + { + } + + void setAlpha(float alpha) + { + mAlpha = alpha; + } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr mat (new osg::Material); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + } + +private: + float mAlpha; +}; + void SkyManager::createRain() { if (mRainNode) @@ -704,7 +735,6 @@ void SkyManager::createRain() osg::Texture::CLAMP, osg::Texture::CLAMP), osg::StateAttribute::ON); stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); @@ -739,6 +769,9 @@ void SkyManager::createRain() mRainNode->addChild(geode); mRainNode->addChild(updater); + mRainFader = new RainFader; + mRainNode->addUpdateCallback(mRainFader); + mRootNode->addChild(mRainNode); } @@ -751,6 +784,7 @@ void SkyManager::destroyRain() mRainNode = NULL; mRainParticleSystem = NULL; mRainShooter = NULL; + mRainFader = NULL; } SkyManager::~SkyManager() @@ -851,8 +885,9 @@ void SkyManager::updateRainParameters() { if (mRainShooter) { - float angle = mWindSpeed/2.f * osg::PI/4; - mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * mWindSpeed / 2.f, -mRainSpeed)); + float windFactor = mWindSpeed/3.f; + float angle = windFactor * osg::PI/4; + mRainShooter->setVelocity(osg::Vec3f(0, mRainSpeed * windFactor, -mRainSpeed)); mRainShooter->setAngle(angle); } } @@ -991,9 +1026,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mParticle.get()) setAlpha(mParticle, weather.mEffectFade); - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) - setAlpha(it->second, weather.mEffectFade); */ + + if (mRainFader) + mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? } void SkyManager::setGlare(const float glare) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f9b9407ecc..85174896b2 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -30,6 +30,7 @@ namespace MWRender class Sun; class Moon; class RainShooter; + class RainFader; class SkyManager { @@ -126,6 +127,7 @@ namespace MWRender osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; osg::ref_ptr mRainShooter; + osg::ref_ptr mRainFader; bool mCreated; From 867ce686ae3bbd4b571c467502d035334f63304c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 19:30:53 +0300 Subject: [PATCH 0542/1812] Proper conversion to QString for DropLineEdit::dropEvent() --- apps/opencs/view/widget/droplineedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 98f1d81c30..1df598cb8d 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); - setText(id.getId().c_str()); + setText(QString::fromUtf8(id.getId().c_str())); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } From 844e5c504d6d9f00d93e083274243fb1730c5112 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 19:41:26 +0300 Subject: [PATCH 0543/1812] Fix conversion to QString --- apps/opencs/model/world/infotableproxymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 3e564506ce..4ee9fa60ce 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,7 +9,7 @@ namespace { QString toLower(const QString &str) { - return Misc::StringUtils::lowerCase(str.toStdString()).c_str(); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); } } From ea97b0a20c3556f5f76d885677df2322ffe8cf04 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 25 Jun 2015 20:08:42 +0300 Subject: [PATCH 0544/1812] Refine InfoTableProxyModel::getFirstInfoRow() code --- .../model/world/infotableproxymodel.cpp | 25 ++++++++----------- .../model/world/infotableproxymodel.hpp | 3 +++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 4ee9fa60ce..e34c505668 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -16,7 +16,9 @@ namespace CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mSourceModel(NULL) + mSourceModel(NULL), + mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : + Columns::ColumnId_Journal) { Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); } @@ -54,26 +56,21 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { - Columns::ColumnId columnId = Columns::ColumnId_Topic; - if (mType == UniversalId::Type_JournalInfos) - { - columnId = Columns::ColumnId_Journal; - } - - int column = mSourceModel->findColumnIndex(columnId); - QString info = toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()); + int row = currentRow; + int column = mSourceModel->findColumnIndex(mInfoColumnId); + QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); if (mFirstRowCache.contains(info)) { return mFirstRowCache[info]; } - while (--currentRow >= 0 && - toLower(mSourceModel->data(mSourceModel->index(currentRow, column)).toString()) == info); - ++currentRow; + while (--row >= 0 && + toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info); + ++row; - mFirstRowCache[info] = currentRow; - return currentRow; + mFirstRowCache[info] = row; + return row; } void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 7b0cd8ede4..28d6017b31 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -4,6 +4,7 @@ #include #include "idtableproxymodel.hpp" +#include "columns.hpp" #include "universalid.hpp" namespace CSMWorld @@ -16,6 +17,8 @@ namespace CSMWorld UniversalId::Type mType; IdTableBase *mSourceModel; + Columns::ColumnId mInfoColumnId; + ///< Contains ID for Topic or Journal ID mutable QHash mFirstRowCache; From ea0339d471638b4718f0515fe7a58d0b15361d34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 21:45:59 +0200 Subject: [PATCH 0545/1812] Make the string argument to BetaComment optional --- apps/openmw/mwscript/docs/vmformat.txt | 6 ++++-- apps/openmw/mwscript/miscextensions.cpp | 20 ++++++++++++-------- components/compiler/extensions0.cpp | 4 ++-- components/compiler/opcodes.hpp | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 93720aef62..42c204ecb0 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -58,6 +58,8 @@ op 0x20029: PCRaiseRank, explicit reference op 0x2002a: PCLowerRank, explicit reference op 0x2002b: PCJoinFaction, explicit reference op 0x2002c: MenuTest +op 0x2002d: BetaComment +op 0x2002e: BetaComment, explicit reference opcodes 0x2002d-0x3ffff unused Segment 4: @@ -396,8 +398,8 @@ op 0x2000243: GetFactionReaction op 0x2000244: Activate, explicit op 0x2000245: ClearInfoActor op 0x2000246: ClearInfoActor, explicit -op 0x2000247: BetaComment -op 0x2000248: BetaComment, explicit +op 0x2000247: (unused) +op 0x2000248: (unused) op 0x2000249: OnMurder op 0x200024a: OnMurder, explicit op 0x200024b: ToggleMenus diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index e706140fbe..8409351aa0 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1016,10 +1016,10 @@ namespace MWScript }; template - class OpBetaComment : public Interpreter::Opcode0 + class OpBetaComment : public Interpreter::Opcode1 { public: - virtual void execute(Interpreter::Runtime &runtime) + virtual void execute(Interpreter::Runtime &runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); @@ -1052,10 +1052,14 @@ namespace MWScript msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; } - std::string notes = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - if (!notes.empty()) - msg << "Notes: " << notes << std::endl; + while (arg0 > 0) + { + std::string notes = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + if (!notes.empty()) + msg << "Notes: " << notes << std::endl; + --arg0; + } runtime.getContext().report(msg.str()); } @@ -1221,8 +1225,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling); - interpreter.installSegment5 (Compiler::Misc::opcodeBetaComment, new OpBetaComment); - interpreter.installSegment5 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment); + interpreter.installSegment3 (Compiler::Misc::opcodeBetaComment, new OpBetaComment); + interpreter.installSegment3 (Compiler::Misc::opcodeBetaCommentExplicit, new OpBetaComment); interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevCreature, new OpAddToLevCreature); interpreter.installSegment5 (Compiler::Misc::opcodeRemoveFromLevCreature, new OpRemoveFromLevCreature); interpreter.installSegment5 (Compiler::Misc::opcodeAddToLevItem, new OpAddToLevItem); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index a16e653c3a..61c9d9c20a 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -308,8 +308,8 @@ namespace Compiler extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); - extensions.registerInstruction ("betacomment", "S", opcodeBetaComment, opcodeBetaCommentExplicit); - extensions.registerInstruction ("bc", "S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index a4aab8aa1b..e7d51d934d 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -228,8 +228,8 @@ namespace Compiler const int opcodeGetLockedExplicit = 0x20001c8; const int opcodeGetEffect = 0x20001cf; const int opcodeGetEffectExplicit = 0x20001d0; - const int opcodeBetaComment = 0x2000247; - const int opcodeBetaCommentExplicit = 0x2000248; + const int opcodeBetaComment = 0x2002d; + const int opcodeBetaCommentExplicit = 0x2002e; const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeRemoveSoulGem = 0x20027; From 1d76607005e5cc5ead490fea13d3a5b0b89c931f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Jun 2015 21:48:47 +0200 Subject: [PATCH 0546/1812] Add ORI (ObjectReferenceInfo) alias for BetaComment (Fixes #2723) --- components/compiler/extensions0.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 61c9d9c20a..cd645f0cff 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -310,6 +310,7 @@ namespace Compiler extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); From 4ef6aa6b7f0856ead39121397282efdfe20875cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 02:30:39 +0200 Subject: [PATCH 0547/1812] Fix weather particles disappearing --- apps/openmw/mwrender/sky.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e5563409d7..1aa2fd8644 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -923,7 +923,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { if (mParticleNode) + { mRootNode->removeChild(mParticleNode); + mParticleNode = NULL; + } mParticleEffect = NULL; } else From 5bc6513e2db74a40c5689bd974b338a486904fc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 02:32:41 +0200 Subject: [PATCH 0548/1812] Fix projectile hit bug where the incorrect attackStrength would be used if a new attack has been performed in the meantime --- apps/openmw/mwmechanics/combat.cpp | 8 +++----- apps/openmw/mwmechanics/combat.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 5 ++++- apps/openmw/mwworld/projectilemanager.hpp | 1 + components/esm/projectilestate.cpp | 4 ++++ components/esm/projectilestate.hpp | 1 + 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b013dbb1b7..27ef1a00fa 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -166,13 +166,11 @@ namespace MWMechanics } void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile, - const osg::Vec3f& hitPosition) + const osg::Vec3f& hitPosition, float attackStrength) { MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &gmst = world->getStore().get(); - MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - if(victim.isEmpty() || !victim.getClass().isActor() || victim.getClass().getCreatureStats(victim).isDead()) // Can't hit non-actors or dead actors { @@ -199,12 +197,12 @@ namespace MWMechanics const unsigned char* attack = weapon.get()->mBase->mData.mChop; - float damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage + float damage = attack[0] + ((attack[1]-attack[0])*attackStrength); // Bow/crossbow damage // Arrow/bolt damage // NB in case of thrown weapons, we are applying the damage twice since projectile == weapon attack = projectile.get()->mBase->mData.mChop; - damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); + damage += attack[0] + ((attack[1]-attack[0])*attackStrength); adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 9412f62e79..1fabc57724 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -14,7 +14,7 @@ void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, - const osg::Vec3f& hitPosition); + const osg::Vec3f& hitPosition, float attackStrength); /// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d0a5de5b2d..16e1f6f472 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -123,6 +123,7 @@ namespace MWWorld state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; + state.mAttackStrength = actor.getClass().getCreatureStats(actor).getAttackStrength(); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -245,7 +246,7 @@ namespace MWWorld if (caster.isEmpty()) caster = result.mHitObject; - MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos); + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); mParent->removeChild(it->mNode); @@ -286,6 +287,7 @@ namespace MWWorld state.mBowId = it->mBowId; state.mVelocity = it->mVelocity; + state.mAttackStrength = it->mAttackStrength; state.save(writer); @@ -327,6 +329,7 @@ namespace MWWorld state.mBowId = esm.mBowId; state.mVelocity = esm.mVelocity; state.mId = esm.mId; + state.mAttackStrength = esm.mAttackStrength; std::string model; try diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 68e408149f..57a6fb6a50 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -108,6 +108,7 @@ namespace MWWorld std::string mBowId; osg::Vec3f mVelocity; + float mAttackStrength; }; std::vector mMagicBolts; diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 85c00025b6..70ae4c5ee6 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,6 +52,7 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); + esm.writeHNT ("STR_", mAttackStrength); } void ProjectileState::load(ESMReader &esm) @@ -60,6 +61,9 @@ namespace ESM mBowId = esm.getHNString ("BOW_"); esm.getHNT (mVelocity, "VEL_"); + + mAttackStrength = 1.f; + esm.getHNOT(mAttackStrength, "STR_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 38429e4595..3471fbfc79 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -45,6 +45,7 @@ namespace ESM { std::string mBowId; Vector3 mVelocity; + float mAttackStrength; void load (ESMReader &esm); void save (ESMWriter &esm) const; From beb108626023e54a7a95f76db678ad31ad9e30e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 04:21:10 +0200 Subject: [PATCH 0549/1812] Fix attackStrength being unset for creatures with no weapons --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d7387fd5..28e19d3956 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -991,6 +991,8 @@ bool CharacterController::updateCreatureState() 1, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; + + stats.setAttackStrength(std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability())); } } From 882e359008bc42a2216d18bf744dfe191716ca64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 05:15:07 +0200 Subject: [PATCH 0550/1812] Move attackStrength to the CharacterController, where it should have been to begin with Only relevant for actors in active cells, so doesn't belong in CreatureStats. This change should slightly reduce the game's memory usage. --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 12 ++++----- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 11 ++++---- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 29 +++++++++++----------- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwmechanics/combat.cpp | 14 +++++------ apps/openmw/mwmechanics/combat.hpp | 6 ++--- apps/openmw/mwmechanics/creaturestats.cpp | 14 +---------- apps/openmw/mwmechanics/creaturestats.hpp | 5 ---- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +-- apps/openmw/mwrender/creatureanimation.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwrender/npcanimation.hpp | 2 +- apps/openmw/mwrender/weaponanimation.cpp | 13 +++++----- apps/openmw/mwrender/weaponanimation.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/projectilemanager.cpp | 4 +-- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +-- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/creaturestats.cpp | 8 ++---- components/esm/creaturestats.hpp | 1 - components/esm/npcstats.cpp | 2 +- 27 files changed, 68 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 95553de76d..6e5029cc32 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -480,7 +480,7 @@ namespace MWBase float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) = 0; + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5b5a3a0cb4..946f024b8c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -209,7 +209,7 @@ namespace MWClass } - void Creature::hit(const MWWorld::Ptr& ptr, int type) const + void Creature::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -229,7 +229,7 @@ namespace MWClass weapon = *weaponslot; } - MWMechanics::applyFatigueLoss(ptr, weapon); + MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); // TODO: where is the distance defined? float dist = 200.f; @@ -276,7 +276,7 @@ namespace MWClass break; } - float damage = min + (max - min) * stats.getAttackStrength(); + float damage = min + (max - min) * attackStrength; bool healthdmg = true; if (!weapon.isEmpty()) { @@ -289,7 +289,7 @@ namespace MWClass attack = weapon.get()->mBase->mData.mThrust; if(attack) { - damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); + damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -310,12 +310,12 @@ namespace MWClass } else if (isBipedal(ptr)) { - MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } MWMechanics::applyElementalShields(ptr, victim); - if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; if (damage > 0) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 93ef3959c3..740552a60f 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -66,7 +66,7 @@ namespace MWClass virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats - virtual void hit(const MWWorld::Ptr& ptr, int type) const; + virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; virtual void block(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b9ca69c630..ac0d67269d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -470,7 +470,7 @@ namespace MWClass } - void Npc::hit(const MWWorld::Ptr& ptr, int type) const + void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -483,7 +483,7 @@ namespace MWClass if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) weapon = MWWorld::Ptr(); - MWMechanics::applyFatigueLoss(ptr, weapon); + MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); const float fCombatDistance = store.find("fCombatDistance")->getFloat(); float dist = fCombatDistance * (!weapon.isEmpty() ? @@ -522,7 +522,6 @@ namespace MWClass bool healthdmg; float damage = 0.0f; - MWMechanics::NpcStats &stats = getNpcStats(ptr); if(!weapon.isEmpty()) { const unsigned char *attack = NULL; @@ -534,7 +533,7 @@ namespace MWClass attack = weapon.get()->mBase->mData.mThrust; if(attack) { - damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); + damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); @@ -542,7 +541,7 @@ namespace MWClass } else { - MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); + MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { @@ -579,7 +578,7 @@ namespace MWClass MWMechanics::applyElementalShields(ptr, victim); - if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage)) + if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; if (healthdmg && damage > 0) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b786286f7b..f032ae77cd 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -81,7 +81,7 @@ namespace MWClass virtual bool hasInventoryStore(const MWWorld::Ptr &ptr) const { return true; } - virtual void hit(const MWWorld::Ptr& ptr, int type) const; + virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 28e19d3956..c39b7dcef9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -649,6 +649,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mUpperBodyState(UpperCharState_Nothing) , mJumpState(JumpState_None) , mWeaponType(WeapType_None) + , mAttackStrength(0.f) , mSkipAnim(false) , mSecondsOfSwimming(0) , mSecondsOfRunning(0) @@ -782,21 +783,21 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if(evt.compare(off, len, "unequip detach") == 0) mAnimation->showWeapons(false); else if(evt.compare(off, len, "chop hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if(evt.compare(off, len, "slash hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if(evt.compare(off, len, "thrust hit") == 0) - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else if(evt.compare(off, len, "hit") == 0) { if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else - mPtr.getClass().hit(mPtr); + mPtr.getClass().hit(mPtr, mAttackStrength); } else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 && evt.compare(off, len, "start") == 0) @@ -819,17 +820,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: if (!hasHitKey) { if (groupname == "attack1") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); else if (groupname == "attack3") - mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust); + mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); } } else if (evt.compare(off, len, "shoot attach") == 0) mAnimation->attachArrow(); else if (evt.compare(off, len, "shoot release") == 0) - mAnimation->releaseArrow(); + mAnimation->releaseArrow(mAttackStrength); else if (evt.compare(off, len, "shoot follow attach") == 0) mAnimation->attachArrow(); @@ -992,7 +993,7 @@ bool CharacterController::updateCreatureState() 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; - stats.setAttackStrength(std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability())); + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); } } @@ -1294,7 +1295,7 @@ bool CharacterController::updateWeaponState() sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack } } - stats.setAttackStrength(attackStrength); + mAttackStrength = attackStrength; mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, @@ -1418,7 +1419,7 @@ bool CharacterController::updateWeaponState() } else { - float str = stats.getAttackStrength(); + float str = mAttackStrength; start = mAttackType+((str < 0.5f) ? " small follow start" : (str < 1.0f) ? " medium follow start" : " large follow start"); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 797c2e6237..be8fb2bf64 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -167,6 +167,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener WeaponType mWeaponType; std::string mCurrentWeapon; + float mAttackStrength; + bool mSkipAnim; // counted for skill increase diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 27ef1a00fa..097dcadc27 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -51,7 +51,7 @@ bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, namespace MWMechanics { - bool blockMeleeAttack(const MWWorld::Ptr &attacker, const MWWorld::Ptr &blocker, const MWWorld::Ptr &weapon, float damage) + bool blockMeleeAttack(const MWWorld::Ptr &attacker, const MWWorld::Ptr &blocker, const MWWorld::Ptr &weapon, float damage, float attackStrength) { if (!blocker.getClass().hasInventoryStore(blocker)) return false; @@ -90,7 +90,7 @@ namespace MWMechanics float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); - float enemySwing = attackerStats.getAttackStrength(); + float enemySwing = attackStrength; float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); float blockerTerm = blockTerm * swingTerm; @@ -131,7 +131,7 @@ namespace MWMechanics normalizedEncumbrance = std::min(1.f, normalizedEncumbrance); float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult; if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult; + fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueBlockMult; fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); blockerStats.setFatigue(fatigue); @@ -363,7 +363,7 @@ namespace MWMechanics (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } - void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) + void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength) { // Note: MCP contains an option to include Strength in hand-to-hand damage // calculations. Some mods recommend using it, so we may want to include an @@ -372,7 +372,7 @@ namespace MWMechanics float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); - damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); + damage *= minstrike + ((maxstrike-minstrike)*attackStrength); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) @@ -398,7 +398,7 @@ namespace MWMechanics sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); } - void applyFatigueLoss(const MWWorld::Ptr &attacker, const MWWorld::Ptr &weapon) + void applyFatigueLoss(const MWWorld::Ptr &attacker, const MWWorld::Ptr &weapon, float attackStrength) { // somewhat of a guess, but using the weapon weight makes sense const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); @@ -410,7 +410,7 @@ namespace MWMechanics const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker); float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult; + fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueMult; fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 1fabc57724..ca78d7956e 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -7,7 +7,7 @@ namespace MWMechanics { /// @return can we block the attack? -bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage); +bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); @@ -31,10 +31,10 @@ void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const /// Adjust weapon damage based on its condition. A used weapon will be less effective. void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); -void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); +void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg, float attackStrength); /// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand) -void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon); +void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength); /// Can attacker operate in victim's environment? /// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index e5cb561bf3..5a09eb4eec 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -18,7 +18,7 @@ namespace MWMechanics : mDrawState (DrawState_Nothing), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), - mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f), + mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mDeathAnimation(0), mLevel (0) { @@ -466,16 +466,6 @@ namespace MWMechanics mDrawState = state; } - float CreatureStats::getAttackStrength() const - { - return mAttackStrength; - } - - void CreatureStats::setAttackStrength(float value) - { - mAttackStrength = value; - } - void CreatureStats::writeState (ESM::CreatureStats& state) const { for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - MWMechanics::applyFatigueLoss(actor, *weapon); + MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength); if (weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) { @@ -121,10 +121,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); - float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * - actor.getClass().getCreatureStats(actor).getAttackStrength(); + float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed); + MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed, attackStrength); showWeapon(false); @@ -148,9 +147,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); - float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * actor.getClass().getCreatureStats(actor).getAttackStrength(); + float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed); + MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed, attackStrength); inv.remove(*ammo, 1, actor); mAmmunition.reset(); diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 226d59c530..3bf0fb7211 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -36,7 +36,7 @@ namespace MWRender void attachArrow(MWWorld::Ptr actor); /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. - void releaseArrow(MWWorld::Ptr actor); + void releaseArrow(MWWorld::Ptr actor, float attackStrength); /// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map. void addControllers(const std::map >& nodes, diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f6170da7f1..5ec2d4e165 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -94,7 +94,7 @@ namespace MWWorld throw std::runtime_error ("class does not have item health"); } - void Class::hit(const Ptr& ptr, int type) const + void Class::hit(const Ptr& ptr, float attackStrength, int type) const { throw std::runtime_error("class cannot hit"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 87325144af..7ef1735550 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -118,9 +118,10 @@ namespace MWWorld ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) - virtual void hit(const Ptr& ptr, int type=-1) const; + virtual void hit(const Ptr& ptr, float attackStrength, int type=-1) const; ///< Execute a melee hit, using the current weapon. This will check the relevant skills /// of the given attacker, and whoever is hit. + /// \param attackStrength how long the attack was charged for, a value in 0-1 range. /// \param type - type of attack, one of the MWMechanics::CreatureStats::AttackType /// enums. ignored for creature attacks. /// (default implementation: throw an exception) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 16e1f6f472..f083bcb4aa 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -115,7 +115,7 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed) + void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); @@ -123,7 +123,7 @@ namespace MWWorld state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; state.mId = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; - state.mAttackStrength = actor.getClass().getCreatureStats(actor).getAttackStrength(); + state.mAttackStrength = attackStrength; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 57a6fb6a50..0aa2efded7 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -52,7 +52,7 @@ namespace MWWorld const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); void update(float dt); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 323eabc108..6980a7e6f5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2677,9 +2677,9 @@ namespace MWWorld } void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed) + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) { - mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed); + mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 6b09fbb659..7964edf459 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -569,7 +569,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); virtual const std::vector& getContentFiles() const; diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 75c1c28bc2..d0fe4be631 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -60,8 +60,8 @@ void ESM::CreatureStats::load (ESMReader &esm) mMovementFlags = 0; esm.getHNOT (mMovementFlags, "MOVE"); - mAttackStrength = 0; - esm.getHNOT (mAttackStrength, "ASTR"); + if (esm.isNextSub("ASTR")) + esm.skipHSub(); // attackStrength, no longer used mFallHeight = 0; esm.getHNOT (mFallHeight, "FALL"); @@ -170,9 +170,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mMovementFlags) esm.writeHNT ("MOVE", mMovementFlags); - if (mAttackStrength) - esm.writeHNT ("ASTR", mAttackStrength); - if (mFallHeight) esm.writeHNT ("FALL", mFallHeight); @@ -242,7 +239,6 @@ void ESM::CreatureStats::blank() mHitRecovery = false; mBlock = false; mMovementFlags = 0; - mAttackStrength = 0.f; mFallHeight = 0.f; mRecalcDynamicStats = false; mDrawState = 0; diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 2a03136d08..3b1d199e4b 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -52,7 +52,6 @@ namespace ESM bool mHitRecovery; bool mBlock; unsigned int mMovementFlags; - float mAttackStrength; float mFallHeight; std::string mLastHitObject; std::string mLastHitAttemptObject; diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index e854410b1f..10c0b6f169 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -86,7 +86,7 @@ void ESM::NpcStats::load (ESMReader &esm) if (esm.isNextSub("PROF")) esm.skipHSub(); // int profit - // No longer used. Now part of CreatureStats. + // No longer used if (esm.isNextSub("ASTR")) esm.skipHSub(); // attackStrength From a44be148d89cd7717708f74166388263726ba36b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 06:40:28 +0200 Subject: [PATCH 0551/1812] Fix door collisions --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2709ced4f5..2cb2618514 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -887,12 +887,12 @@ namespace MWPhysics const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { - const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; + const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; #else virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { - const btCollisionObject* collisionObject = col1; + const btCollisionObject* collisionObject = col0; #endif const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) From f3ff90e1fde2f46d980a3f2525b79f34edcc151d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 13:01:25 +0200 Subject: [PATCH 0552/1812] moved meta data into a new single-row table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 3 --- apps/opencs/model/world/data.cpp | 29 +++++++++++++------------ apps/opencs/model/world/data.hpp | 10 ++++----- apps/opencs/model/world/metadata.cpp | 27 +++++++++++++++++++++++ apps/opencs/model/world/metadata.hpp | 29 +++++++++++++++++++++++++ apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + 8 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 apps/opencs/model/world/metadata.cpp create mode 100644 apps/opencs/model/world/metadata.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5386da707f..3399b9dddb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection - idcompletionmanager + idcompletionmanager metadata ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 1e6ae54550..34ae3dd8ae 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2282,9 +2282,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mNew) { - mData.setDescription (""); - mData.setAuthor (""); - if (mContentFiles.size()==1) createBase(); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5acd80339e..3bd892618a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -475,6 +475,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mDebugProfiles.addColumn (new ScriptColumn ( ScriptColumn::Type_Lines)); + mMetaData.appendBlankRecord ("sys::meta"); + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); @@ -515,6 +517,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc UniversalId::Type_Texture); addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), UniversalId::Type_Video); + addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData); mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files } @@ -803,6 +806,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) return mResourcesManager.get (id.getType()); } +const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const +{ + return mMetaData.getRecord (0).get(); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -847,9 +855,12 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mBase = base; mProject = project; - mAuthor = mReader->getAuthor(); - mDescription = mReader->getDesc(); + MetaData metaData; + metaData.mId = "sys::meta"; + metaData.load (*mReader); + mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + return mReader->getRecordCount(); } @@ -1103,24 +1114,14 @@ int CSMWorld::Data::count (RecordBase::State state) const count (state, mPathgrids); } -void CSMWorld::Data::setDescription (const std::string& description) -{ - mDescription = description; -} - std::string CSMWorld::Data::getDescription() const { - return mDescription; -} - -void CSMWorld::Data::setAuthor (const std::string& author) -{ - mAuthor = author; + return mMetaData.getRecord (0).get().mDescription; } std::string CSMWorld::Data::getAuthor() const { - return mAuthor; + return mMetaData.getRecord (0).get().mAuthor; } std::vector CSMWorld::Data::getIds (bool listDeleted) const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 060e47bd95..edfd4bc31c 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -44,6 +44,7 @@ #include "infocollection.hpp" #include "nestedinfocollection.hpp" #include "pathgrid.hpp" +#include "metadata.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" #endif @@ -94,11 +95,10 @@ namespace CSMWorld RefIdCollection mReferenceables; RefCollection mRefs; IdCollection mFilters; + Collection mMetaData; const ResourcesManager& mResourcesManager; std::vector mModels; std::map mModelIndex; - std::string mAuthor; - std::string mDescription; ESM::ESMReader *mReader; const ESM::Dialogue *mDialogue; // last loaded dialogue bool mBase; @@ -238,6 +238,8 @@ namespace CSMWorld /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; + const MetaData& getMetaData() const; + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// @@ -267,12 +269,8 @@ namespace CSMWorld int count (RecordBase::State state) const; ///< Return number of top-level records with the given \a state. - void setDescription (const std::string& description); - std::string getDescription() const; - void setAuthor (const std::string& author); - std::string getAuthor() const; signals: diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp new file mode 100644 index 0000000000..40b8e95197 --- /dev/null +++ b/apps/opencs/model/world/metadata.cpp @@ -0,0 +1,27 @@ + +#include "metadata.hpp" + +#include +#include +#include + +void CSMWorld::MetaData::blank() +{ + mFormat = ESM::Header::CurrentFormat; + mAuthor.clear(); + mDescription.clear(); +} + +void CSMWorld::MetaData::load (ESM::ESMReader& esm) +{ + mFormat = esm.getHeader().mFormat; + mAuthor = esm.getHeader().mData.author.toString(); + mDescription = esm.getHeader().mData.desc.toString(); +} + +void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const +{ + esm.setFormat (mFormat); + esm.setAuthor (mAuthor); + esm.setDescription (mDescription); +} diff --git a/apps/opencs/model/world/metadata.hpp b/apps/opencs/model/world/metadata.hpp new file mode 100644 index 0000000000..f8df2690ec --- /dev/null +++ b/apps/opencs/model/world/metadata.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_WOLRD_METADATA_H +#define CSM_WOLRD_METADATA_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + +namespace CSMWorld +{ + struct MetaData + { + std::string mId; + + int mFormat; + std::string mAuthor; + std::string mDescription; + + void blank(); + + void load (ESM::ESMReader& esm); + void save (ESM::ESMWriter& esm) const; + }; +} + +#endif diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index e496fe79bb..584bf5e702 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -120,6 +120,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0a9fa38473..752504bc45 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -131,6 +131,7 @@ namespace CSMWorld Type_StartScripts, Type_StartScript, Type_Search, + Type_MetaData, Type_RunLog }; From 1870b087e7b3f9454c5450cfdbe30f6b86358054 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 13:13:22 +0200 Subject: [PATCH 0553/1812] ported setting of meta data for saving to the new mechanism --- apps/opencs/model/doc/savingstages.cpp | 6 ++---- apps/opencs/model/world/data.cpp | 10 ---------- apps/opencs/model/world/data.hpp | 4 ---- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index d6258da6ae..f78c57ecd6 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -53,18 +53,16 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) mState.getWriter().clearMaster(); - mState.getWriter().setFormat (0); - if (mSimple) { mState.getWriter().setAuthor (""); mState.getWriter().setDescription (""); mState.getWriter().setRecordCount (0); + mState.getWriter().setFormat (ESM::Header::CurrentFormat); } else { - mState.getWriter().setAuthor (mDocument.getData().getAuthor()); - mState.getWriter().setDescription (mDocument.getData().getDescription()); + mDocument.getData().getMetaData().save (mState.getWriter()); mState.getWriter().setRecordCount ( mDocument.getData().count (CSMWorld::RecordBase::State_Modified) + mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) + diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3bd892618a..368c7a766f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1114,16 +1114,6 @@ int CSMWorld::Data::count (RecordBase::State state) const count (state, mPathgrids); } -std::string CSMWorld::Data::getDescription() const -{ - return mMetaData.getRecord (0).get().mDescription; -} - -std::string CSMWorld::Data::getAuthor() const -{ - return mMetaData.getRecord (0).get().mAuthor; -} - std::vector CSMWorld::Data::getIds (bool listDeleted) const { std::vector ids; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index edfd4bc31c..15e39b9bab 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -269,10 +269,6 @@ namespace CSMWorld int count (RecordBase::State state) const; ///< Return number of top-level records with the given \a state. - std::string getDescription() const; - - std::string getAuthor() const; - signals: void idListChanged(); From 5a37530c1c296b15b273b5da3cc53e10b6db7a63 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:17:18 +0200 Subject: [PATCH 0554/1812] added missing MetaData table UniversalId type --- apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 584bf5e702..73d893a260 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -56,6 +56,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 752504bc45..e9104fc226 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -131,6 +131,7 @@ namespace CSMWorld Type_StartScripts, Type_StartScript, Type_Search, + Type_MetaDatas, Type_MetaData, Type_RunLog }; From 10fbe6aada504ebd0e5afebdc5569382f5051806 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:17:47 +0200 Subject: [PATCH 0555/1812] split DialogueSubView in SimpleDialogueSubView and DialogueSubView --- apps/opencs/view/world/dialoguesubview.cpp | 402 +++++++++++---------- apps/opencs/view/world/dialoguesubview.hpp | 61 +++- 2 files changed, 262 insertions(+), 201 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 284c5928ba..d588c2edba 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -548,12 +548,38 @@ void CSVWorld::EditWidget::remake(int row) this->setWidgetResizable(true); } -/* -==============================DialogueSubView========================================== -*/ -CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, - const CreatorFactoryBase& creatorFactory, bool sorting) : +QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout() +{ + return *mMainLayout; +} + +CSMWorld::IdTable& CSVWorld::SimpleDialogueSubView::getTable() +{ + return *mTable; +} + +CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatcher() +{ + return mCommandDispatcher; +} + +std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const +{ + return mCurrentId; +} + +CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget() +{ + return *mEditWidget; +} + +bool CSVWorld::SimpleDialogueSubView::isLocked() const +{ + return mLocked; +} + +CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mEditWidget(0), mMainLayout(NULL), @@ -570,60 +596,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM QWidget *mainWidget = new QWidget(this); - QHBoxLayout *buttonsLayout = new QHBoxLayout; - QToolButton* prevButton = new QToolButton(mainWidget); - prevButton->setIcon(QIcon(":/go-previous.png")); - prevButton->setToolTip ("Switch to previous record"); - QToolButton* nextButton = new QToolButton(mainWidget); - nextButton->setIcon(QIcon(":/go-next.png")); - nextButton->setToolTip ("Switch to next record"); - buttonsLayout->addWidget(prevButton, 0); - buttonsLayout->addWidget(nextButton, 1); - buttonsLayout->addStretch(2); - - QToolButton* cloneButton = new QToolButton(mainWidget); - cloneButton->setIcon(QIcon(":/edit-clone.png")); - cloneButton->setToolTip ("Clone record"); - QToolButton* addButton = new QToolButton(mainWidget); - addButton->setIcon(QIcon(":/add.png")); - addButton->setToolTip ("Add new record"); - QToolButton* deleteButton = new QToolButton(mainWidget); - deleteButton->setIcon(QIcon(":/edit-delete.png")); - deleteButton->setToolTip ("Delete record"); - QToolButton* revertButton = new QToolButton(mainWidget); - revertButton->setIcon(QIcon(":/edit-undo.png")); - revertButton->setToolTip ("Revert record"); - - if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview) - { - QToolButton* previewButton = new QToolButton(mainWidget); - previewButton->setIcon(QIcon(":/edit-preview.png")); - previewButton->setToolTip ("Open a preview of this record"); - buttonsLayout->addWidget(previewButton); - connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); - } - - if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View) - { - QToolButton* viewButton = new QToolButton(mainWidget); - viewButton->setIcon(QIcon(":/cell.png")); - viewButton->setToolTip ("Open a scene view of the cell this record is located in"); - buttonsLayout->addWidget(viewButton); - connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); - } - - buttonsLayout->addWidget(cloneButton); - buttonsLayout->addWidget(addButton); - buttonsLayout->addWidget(deleteButton); - buttonsLayout->addWidget(revertButton); - - connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); - connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); - connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert())); - connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete())); - mMainLayout = new QVBoxLayout(mainWidget); + setWidget (mainWidget); mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); @@ -631,98 +605,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); - - mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); - - connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); - - if(!mBottom->canCreateAndDelete()) - { - cloneButton->setDisabled (true); - addButton->setDisabled (true); - deleteButton->setDisabled (true); - } - dataChanged(mTable->getModelIndex (mCurrentId, 0)); - mMainLayout->addLayout (buttonsLayout); - setWidget (mainWidget); } -void CSVWorld::DialogueSubView::prevId () -{ - int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; - - if (newRow < 0) - { - return; - } - while (newRow >= 0) - { - QModelIndex newIndex(mTable->index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) - { - mEditWidget->remake(newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - - mEditWidget->setDisabled(mLocked); - - return; - } - --newRow; - } -} - -void CSVWorld::DialogueSubView::nextId () -{ - int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; - - if (newRow >= mTable->rowCount()) - { - return; - } - - while (newRow < mTable->rowCount()) - { - QModelIndex newIndex(mTable->index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted)) - { - mEditWidget->remake(newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - - mEditWidget->setDisabled(mLocked); - - return; - } - ++newRow; - } -} - -void CSVWorld::DialogueSubView::setEditLock (bool locked) +void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) { if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid return; @@ -741,7 +627,7 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) } -void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) +void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); @@ -774,7 +660,7 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) } } -void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); @@ -789,45 +675,14 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, } } -void CSVWorld::DialogueSubView::requestFocus (const std::string& id) +void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id) { changeCurrentId(id); mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } -void CSVWorld::DialogueSubView::cloneRequest () -{ - mBottom->cloneRequest(mCurrentId, static_cast(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt())); -} - -void CSVWorld::DialogueSubView::showPreview () -{ - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (currentIndex.isValid() && - mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - currentIndex.row() < mTable->rowCount()) - { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); - } -} - -void CSVWorld::DialogueSubView::viewRecord () -{ - QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); - - if (currentIndex.isValid() && - currentIndex.row() < mTable->rowCount()) - { - std::pair params = mTable->view (currentIndex.row()); - - if (params.first.getType()!=CSMWorld::UniversalId::Type_None) - emit focusId (params.first, params.second); - } -} - -void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) +void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId) { std::vector selection; mCurrentId = std::string(newId); @@ -835,3 +690,186 @@ void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) selection.push_back(mCurrentId); mCommandDispatcher.setSelection(selection); } + + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) +: SimpleDialogueSubView (id, document) +{ + // bottom box + getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); + + mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + + connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + + // buttons + QHBoxLayout *buttonsLayout = new QHBoxLayout; + QToolButton* prevButton = new QToolButton (this); + prevButton->setIcon(QIcon(":/go-previous.png")); + prevButton->setToolTip ("Switch to previous record"); + QToolButton* nextButton = new QToolButton (this); + nextButton->setIcon(QIcon(":/go-next.png")); + nextButton->setToolTip ("Switch to next record"); + buttonsLayout->addWidget(prevButton, 0); + buttonsLayout->addWidget(nextButton, 1); + buttonsLayout->addStretch(2); + + QToolButton* cloneButton = new QToolButton (this); + cloneButton->setIcon(QIcon(":/edit-clone.png")); + cloneButton->setToolTip ("Clone record"); + QToolButton* addButton = new QToolButton (this); + addButton->setIcon(QIcon(":/add.png")); + addButton->setToolTip ("Add new record"); + QToolButton* deleteButton = new QToolButton (this); + deleteButton->setIcon(QIcon(":/edit-delete.png")); + deleteButton->setToolTip ("Delete record"); + QToolButton* revertButton = new QToolButton (this); + revertButton->setIcon(QIcon(":/edit-undo.png")); + revertButton->setToolTip ("Revert record"); + + if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview) + { + QToolButton* previewButton = new QToolButton (this); + previewButton->setIcon(QIcon(":/edit-preview.png")); + previewButton->setToolTip ("Open a preview of this record"); + buttonsLayout->addWidget(previewButton); + connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); + } + + if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View) + { + QToolButton* viewButton = new QToolButton (this); + viewButton->setIcon(QIcon(":/cell.png")); + viewButton->setToolTip ("Open a scene view of the cell this record is located in"); + buttonsLayout->addWidget(viewButton); + connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); + } + + buttonsLayout->addWidget(cloneButton); + buttonsLayout->addWidget(addButton); + buttonsLayout->addWidget(deleteButton); + buttonsLayout->addWidget(revertButton); + + connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); + connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); + connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); + connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert())); + connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete())); + + connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); + + if(!mBottom->canCreateAndDelete()) + { + cloneButton->setDisabled (true); + addButton->setDisabled (true); + deleteButton->setDisabled (true); + } + + getMainLayout().addLayout (buttonsLayout); +} + +void CSVWorld::DialogueSubView::cloneRequest() +{ + mBottom->cloneRequest (getCurrentId(), + static_cast (getTable(). + data (getTable().getModelIndex(getCurrentId(), 2)).toInt())); +} + +void CSVWorld::DialogueSubView::prevId() +{ + int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1; + + if (newRow < 0) + { + return; + } + while (newRow >= 0) + { + QModelIndex newIndex (getTable().index(newRow, 0)); + + if (!newIndex.isValid()) + { + return; + } + + CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); + if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) + { + getEditWidget().remake (newRow); + + setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), + getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); + + changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); + + getEditWidget().setDisabled (isLocked()); + + return; + } + --newRow; + } +} + +void CSVWorld::DialogueSubView::nextId () +{ + int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1; + + if (newRow >= getTable().rowCount()) + { + return; + } + + while (newRow < getTable().rowCount()) + { + QModelIndex newIndex (getTable().index(newRow, 0)); + + if (!newIndex.isValid()) + { + return; + } + + CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); + if (!(state == CSMWorld::RecordBase::State_Deleted)) + { + getEditWidget().remake(newRow); + + setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), + getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); + + changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); + + getEditWidget().setDisabled (isLocked()); + + return; + } + ++newRow; + } +} + + +void CSVWorld::DialogueSubView::showPreview () +{ + QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + + if (currentIndex.isValid() && + getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && + currentIndex.row() < getTable().rowCount()) + { + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), ""); + } +} + +void CSVWorld::DialogueSubView::viewRecord () +{ + QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + + if (currentIndex.isValid() && + currentIndex.row() < getTable().rowCount()) + { + std::pair params = getTable().view (currentIndex.row()); + + if (params.first.getType()!=CSMWorld::UniversalId::Type_None) + emit focusId (params.first, params.second); + } +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 69e0dc8648..5d6915d42d 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -173,7 +173,7 @@ namespace CSVWorld void remake(int row); }; - class DialogueSubView : public CSVDoc::SubView + class SimpleDialogueSubView : public CSVDoc::SubView { Q_OBJECT @@ -184,33 +184,32 @@ namespace CSVWorld std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; - TableBottomBox* mBottom; CSMWorld::CommandDispatcher mCommandDispatcher; + protected: + + QVBoxLayout& getMainLayout(); + + CSMWorld::IdTable& getTable(); + + CSMWorld::CommandDispatcher& getCommandDispatcher(); + + std::string getCurrentId() const; + + EditWidget& getEditWidget(); + + void changeCurrentId(const std::string& newCurrent); + + bool isLocked() const; + public: - DialogueSubView (const CSMWorld::UniversalId& id, - CSMDoc::Document& document, - const CreatorFactoryBase& creatorFactory, - bool sorting = false); + SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); virtual void setEditLock (bool locked); - private: - void changeCurrentId(const std::string& newCurrent); - private slots: - void nextId(); - - void prevId(); - - void showPreview(); - - void viewRecord(); - - void cloneRequest(); - void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record @@ -218,6 +217,30 @@ namespace CSVWorld void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; + + class DialogueSubView : public SimpleDialogueSubView + { + Q_OBJECT + + TableBottomBox* mBottom; + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + const CreatorFactoryBase& creatorFactory, bool sorting = false); + + private slots: + + void cloneRequest(); + + void nextId(); + + void prevId(); + + void showPreview(); + + void viewRecord(); + }; } #endif From 57015f366609f57a0ac727796585a2bace3915aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 15:50:36 +0200 Subject: [PATCH 0556/1812] fixed handling of numeric read-only fields in dialogue sub views --- apps/opencs/view/world/dialoguesubview.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d588c2edba..99650834ef 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -64,16 +64,24 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo } } + CSMWorld::Columns::ColumnId columnId = static_cast ( + mTable->getColumnId (index.column())); + if (QVariant::String == v.type()) { label->setText(v.toString()); } - else //else we are facing enums + else if (CSMWorld::Columns::hasEnums (columnId)) { int data = v.toInt(); - std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); + std::vector enumNames (CSMWorld::Columns::getEnums (columnId)); + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } + else + { + label->setText (v.toString()); + } } void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const From 1e033fa8fe87f8eac5b6414b697d5a55b066bead Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 16:11:00 +0200 Subject: [PATCH 0557/1812] added meta data dialogue sub view --- apps/opencs/model/world/columnimp.hpp | 72 +++++++++++++++++++++++++++ apps/opencs/model/world/columns.cpp | 4 ++ apps/opencs/model/world/columns.hpp | 4 ++ apps/opencs/model/world/data.cpp | 8 ++- apps/opencs/view/doc/view.cpp | 9 ++++ apps/opencs/view/doc/view.hpp | 2 + apps/opencs/view/world/subviews.cpp | 3 ++ 7 files changed, 101 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a8ae5dfa12..ba23a3603a 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2308,6 +2308,78 @@ namespace CSMWorld return true; } }; + + template + struct FormatColumn : public Column + { + FormatColumn() + : Column (Columns::ColumnId_FileFormat, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mFormat; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template + struct AuthorColumn : public Column + { + AuthorColumn() + : Column (Columns::ColumnId_Author, ColumnBase::Display_String) + {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mAuthor.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mAuthor = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct FileDescriptionColumn : public Column + { + FileDescriptionColumn() + : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString) + {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mDescription.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mDescription = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9491c32469..d6e27caeb1 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -311,6 +311,10 @@ namespace CSMWorld { ColumnId_WaterLevel, "Water Level" }, { ColumnId_MapColor, "Map Color" }, + { ColumnId_FileFormat, "File Format" }, + { ColumnId_FileDescription, "File Description" }, + { ColumnId_Author, "Author" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 191bbdea8c..d699c67b7e 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -302,6 +302,10 @@ namespace CSMWorld ColumnId_WaterLevel = 273, ColumnId_MapColor = 274, + ColumnId_FileFormat = 275, + ColumnId_FileDescription = 276, + ColumnId_Author = 277, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 368c7a766f..29f7fa9b84 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -476,7 +476,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc ScriptColumn::Type_Lines)); mMetaData.appendBlankRecord ("sys::meta"); - + + mMetaData.addColumn (new StringIdColumn (true)); + mMetaData.addColumn (new RecordStateColumn); + mMetaData.addColumn (new FormatColumn); + mMetaData.addColumn (new AuthorColumn); + mMetaData.addColumn (new FileDescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 64b066eb1e..c4abb26225 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu() connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); file->addAction (loadErrors); + QAction *meta = new QAction (tr ("Meta Data"), this); + connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView())); + file->addAction (meta); + QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); file->addAction(close); @@ -813,6 +817,11 @@ void CSVDoc::View::addSearchSubView() addSubView (mDocument->newSearch()); } +void CSVDoc::View::addMetaDataSubView() +{ + addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 814dabc6b5..7f4255f8fc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -224,6 +224,8 @@ namespace CSVDoc void addSearchSubView(); + void addMetaDataSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index ba3ab1358c..b8a6ba4298 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Filter, new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_MetaData, + new CSVDoc::SubViewFactory); + //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); } From a4c2c75d1fafd5458bfae3d555f55b8ab4a00844 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 16:22:06 +0200 Subject: [PATCH 0558/1812] fixed overwriting of meta data when loading project file --- apps/opencs/model/world/data.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 29f7fa9b84..b38607748f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -861,11 +861,14 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mBase = base; mProject = project; - MetaData metaData; - metaData.mId = "sys::meta"; - metaData.load (*mReader); + if (!mProject && !mBase) + { + MetaData metaData; + metaData.mId = "sys::meta"; + metaData.load (*mReader); - mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); + } return mReader->getRecordCount(); } From 59db9664ba4b7111c496e1a7eee9fbe176bf5648 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 17:47:04 +0200 Subject: [PATCH 0559/1812] Pass the CharacterController to AiPackage::execute --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/aiactivate.cpp | 2 +- apps/openmw/mwmechanics/aiactivate.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.hpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aiescort.cpp | 2 +- apps/openmw/mwmechanics/aiescort.hpp | 2 +- apps/openmw/mwmechanics/aifollow.cpp | 2 +- apps/openmw/mwmechanics/aifollow.hpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 4 +++- apps/openmw/mwmechanics/aipursue.cpp | 2 +- apps/openmw/mwmechanics/aipursue.hpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 4 ++-- apps/openmw/mwmechanics/aisequence.hpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/aitravel.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 20 files changed, 24 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 03ab3d0201..2c53c00b7c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1124,7 +1124,7 @@ namespace MWMechanics { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) - stats.getAiSequence().execute(iter->first,iter->second->getAiState(), duration); + stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration); if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 9e25084d38..b0621c8052 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -21,7 +21,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const { return new AiActivate(*this); } -bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); //position of the actor const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index e25afe2853..2ca985be9a 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -28,7 +28,7 @@ namespace MWMechanics AiActivate(const ESM::AiSequence::AiActivate* activate); virtual AiActivate *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; virtual void writeState(ESM::AiSequence::AiSequence& sequence) const; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 29bf19942c..457c9a95ca 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -17,7 +17,7 @@ MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) } -bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 7590c8fcba..1ad945bca8 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -20,7 +20,7 @@ namespace MWMechanics virtual AiAvoidDoor *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 032c304ae3..56dd11b996 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,7 +181,7 @@ namespace MWMechanics * Use the Observer Pattern to co-ordinate attacks, provide intelligence on * whether the target was hit, etc. */ - bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiCombat::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // get or create temporary storage AiCombatStorage& storage = state.get(); diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 94c7beb3a8..083f233849 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -40,7 +40,7 @@ namespace MWMechanics virtual AiCombat *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index f9ebefe136..593f9f173e 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -63,7 +63,7 @@ namespace MWMechanics return new AiEscort(*this); } - bool AiEscort::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiEscort::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // If AiEscort has ran for as long or longer then the duration specified // and the duration is not infinite, the package is complete. diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index f02cdba220..9f6335b933 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -33,7 +33,7 @@ namespace MWMechanics virtual AiEscort *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 524a7f904f..a92e9eedc8 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -54,7 +54,7 @@ AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) } -bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { MWWorld::Ptr target = getTarget(); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 68a1f0ea5f..8555f9bc4d 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -35,7 +35,7 @@ namespace MWMechanics virtual AiFollow *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 78a2bfd9f7..da43dc6dae 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -25,6 +25,8 @@ namespace ESM namespace MWMechanics { + class CharacterController; + /// \brief Base class for AI packages class AiPackage { @@ -53,7 +55,7 @@ namespace MWMechanics /// Updates and runs the package (Should run every frame) /// \return Package completed? - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration) = 0; + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) = 0; /// Returns the TypeID of the AiPackage /// \see enum TypeId diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 8c31a10db6..ac6b23ef6b 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -30,7 +30,7 @@ AiPursue *MWMechanics::AiPursue::clone() const { return new AiPursue(*this); } -bool AiPursue::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { if(actor.getClass().getCreatureStats(actor).isDead()) return true; diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index 493a279859..813b87cff0 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -31,7 +31,7 @@ namespace MWMechanics AiPursue(const ESM::AiSequence::AiPursue* pursue); virtual AiPursue *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; MWWorld::Ptr getTarget() const; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 0606e5146e..3e1f896245 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -150,7 +150,7 @@ bool AiSequence::isPackageDone() const return mDone; } -void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration) +void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { @@ -211,7 +211,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float durati } } - if (package->execute (actor,state,duration)) + if (package->execute (actor,characterController,state,duration)) { // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 19f1e14545..1eefe7c697 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -24,6 +24,7 @@ namespace ESM namespace MWMechanics { class AiPackage; + class CharacterController; template< class Base > class DerivedClassStorage; struct AiTemporaryBase; @@ -95,7 +96,7 @@ namespace MWMechanics void stopPursuit(); /// Execute current package, switching if needed. - void execute (const MWWorld::Ptr& actor, MWMechanics::AiState& state, float duration); + void execute (const MWWorld::Ptr& actor, CharacterController& characterController, MWMechanics::AiState& state, float duration); /// Simulate the passing of time using the currently active AI package void fastForward(const MWWorld::Ptr &actor, AiState &state); diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index fb6e89cf6d..f192bed63f 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics return new AiTravel(*this); } - bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a5a4577e60..9f263fd46c 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -30,7 +30,7 @@ namespace MWMechanics virtual AiTravel *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7e55ac9a29..41cfb9df4f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -168,7 +168,7 @@ namespace MWMechanics * actors will enter combat (i.e. no longer wandering) and different pathfinding * will kick in. */ - bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration) + bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { // get or create temporary storage AiWanderStorage& storage = state.get(); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4b83179d54..13e3e571f7 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -46,7 +46,7 @@ namespace MWMechanics virtual AiPackage *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); virtual int getTypeId() const; From 4487bda702da64a34913219ccf22a318e0545a21 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 18:19:00 +0200 Subject: [PATCH 0560/1812] size limits for meta data strings --- apps/opencs/model/world/columnbase.cpp | 3 ++- apps/opencs/model/world/columnbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 4 ++-- apps/opencs/view/world/util.cpp | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 9385038757..f209e48c66 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -100,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (Display display) bool CSMWorld::ColumnBase::isText (Display display) { - return display==Display_String || display==Display_LongString; + return display==Display_String || display==Display_LongString || + display==Display_String32 || display==Display_LongString256; } bool CSMWorld::ColumnBase::isScript (Display display) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 789823d5cd..59f2836c21 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -123,6 +123,8 @@ namespace CSMWorld Display_InfoCondVar, Display_InfoCondComp, Display_RaceSkill, + Display_String32, + Display_LongString256, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index ba23a3603a..15dd2c15b0 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2331,7 +2331,7 @@ namespace CSMWorld struct AuthorColumn : public Column { AuthorColumn() - : Column (Columns::ColumnId_Author, ColumnBase::Display_String) + : Column (Columns::ColumnId_Author, ColumnBase::Display_String32) {} virtual QVariant get (const Record& record) const @@ -2358,7 +2358,7 @@ namespace CSMWorld struct FileDescriptionColumn : public Column { FileDescriptionColumn() - : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString) + : Column (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString256) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 62cde4608a..f216585811 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -232,6 +232,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return edit; } + case CSMWorld::ColumnBase::Display_LongString256: + { + /// \todo implement size limit. QPlainTextEdit does not support a size limit. + QPlainTextEdit *edit = new QPlainTextEdit(parent); + edit->setUndoRedoEnabled (false); + return edit; + } + case CSMWorld::ColumnBase::Display_Boolean: return new QCheckBox(parent); @@ -245,6 +253,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new CSVWidget::DropLineEdit(display, parent); + case CSMWorld::ColumnBase::Display_String32: + { + // For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used + CSVWidget::DropLineEdit *widget = new CSVWidget::DropLineEdit(display, parent); + widget->setMaxLength (32); + return widget; + } + default: return QStyledItemDelegate::createEditor (parent, option, index); From 6d5823e8aabefc0031a65c6157fa66de0afcd03c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Jun 2015 18:54:49 +0200 Subject: [PATCH 0561/1812] killed some tabs --- apps/opencs/model/world/infotableproxymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index e34c505668..6216291d07 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,7 +9,7 @@ namespace { QString toLower(const QString &str) { - return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); } } From 502cc852da0f10dae95ba10ec363a2be66707304 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Jun 2015 20:16:32 +0200 Subject: [PATCH 0562/1812] Handle encoding conversions when saving TES3 header (Fixes #2727) --- components/esm/esmwriter.cpp | 9 +++++++++ components/esm/esmwriter.hpp | 1 + components/esm/loadtes3.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index c64678e702..4d99991434 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -174,6 +174,15 @@ namespace ESM endRecord(name); } + void ESMWriter::writeFixedSizeString(const std::string &data, int size) + { + std::string string; + if (!data.empty()) + string = mEncoder ? mEncoder->getLegacyEnc(data) : data; + string.resize(size); + write(string.c_str(), string.size()); + } + void ESMWriter::writeHString(const std::string& data) { if (data.size() == 0) diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 30cec58b46..d11b3c940b 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -120,6 +120,7 @@ public: void startSubRecord(const std::string& name); void endRecord(const std::string& name); void endRecord(uint32_t name); + void writeFixedSizeString(const std::string& data, int size); void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 9c0c55b8f6..7d749c4d95 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -71,7 +71,13 @@ void ESM::Header::save (ESMWriter &esm) if (mFormat>0) esm.writeHNT ("FORM", mFormat); - esm.writeHNT ("HEDR", mData, 300); + esm.startSubRecord("HEDR"); + esm.writeT(mData.version); + esm.writeT(mData.type); + esm.writeFixedSizeString(mData.author.toString(), 32); + esm.writeFixedSizeString(mData.desc.toString(), 256); + esm.writeT(mData.records); + esm.endRecord("HEDR"); for (std::vector::iterator iter = mMaster.begin(); iter != mMaster.end(); ++iter) From a7f31988d17d20cb9abcf89267641dc82a4d89b8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 22:14:11 +0300 Subject: [PATCH 0563/1812] Add the ability to search a nested column index --- apps/opencs/model/world/idtree.cpp | 10 ++++++++ apps/opencs/model/world/idtree.hpp | 6 +++++ apps/opencs/model/world/nestedcollection.cpp | 25 ++++++++++++++++++++ apps/opencs/model/world/nestedcollection.hpp | 8 +++++++ 4 files changed, 49 insertions(+) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 1e81d6ac2f..9dbe7e002f 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -261,3 +261,13 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde return mNestedCollection->nestedTable(index.row(), index.column()); } + +int CSMWorld::IdTree::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + return mNestedCollection->searchNestedColumnIndex(parentColumn, id); +} + +int CSMWorld::IdTree::findNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + return mNestedCollection->findNestedColumnIndex(parentColumn, id); +} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 5337ed82b8..79e93fc3df 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -73,6 +73,12 @@ namespace CSMWorld virtual bool hasChildren (const QModelIndex& index) const; + virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or -1 if the requested column wasn't found. + + virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or throws an exception if the requested column wasn't found. + signals: void resetStart(const QString& id); diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp index 937ad6ad60..850d8c3859 100644 --- a/apps/opencs/model/world/nestedcollection.cpp +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -15,3 +15,28 @@ int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const { return 0; } + +int CSMWorld::NestedCollection::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + // Assumed that the parentColumn is always a valid index + const NestableColumn *parent = getNestableColumn(parentColumn); + int nestedColumnCount = getNestedColumnsCount(0, parentColumn); + for (int i = 0; i < nestedColumnCount; ++i) + { + if (parent->nestedColumn(i).mColumnId == id) + { + return i; + } + } + return -1; +} + +int CSMWorld::NestedCollection::findNestedColumnIndex(int parentColumn, Columns::ColumnId id) +{ + int index = searchNestedColumnIndex(parentColumn, id); + if (index == -1) + { + throw std::logic_error("CSMWorld::NestedCollection: No such nested column"); + } + return index; +} diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index b075f53c41..4548cfb2b9 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H +#include "columns.hpp" + class QVariant; namespace CSMWorld @@ -33,6 +35,12 @@ namespace CSMWorld virtual int getNestedColumnsCount(int row, int column) const; virtual NestableColumn *getNestableColumn(int column) = 0; + + virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or -1 if the requested column wasn't found. + + virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id); + ///< \return the column index or throws an exception if the requested column wasn't found. }; } From f3bb00e3d9949c9bf24426551c665d4cbb893825 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 22:16:12 +0300 Subject: [PATCH 0564/1812] Add the ability to add nested values to the Create command --- apps/opencs/model/world/commands.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 5 +++++ 2 files changed, 29 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index a44d8770f6..5e0cc8f880 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -58,6 +58,25 @@ void CSMWorld::CreateCommand::applyModifications() { for (std::map::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter) mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second); + + if (!mNestedValues.empty()) + { + CSMWorld::IdTree *tree = dynamic_cast(&mModel); + if (tree == NULL) + { + throw std::logic_error("CSMWorld::CreateCommand: Attempt to add nested values to the non-nested model"); + } + + std::map >::const_iterator current = mNestedValues.begin(); + std::map >::const_iterator end = mNestedValues.end(); + for (; current != end; ++current) + { + QModelIndex index = tree->index(0, + current->second.first, + tree->getNestedModelIndex(mId, current->first)); + tree->setData(index, current->second.second); + } + } } CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent) @@ -71,6 +90,11 @@ void CSMWorld::CreateCommand::addValue (int column, const QVariant& value) mValues[column] = value; } +void CSMWorld::CreateCommand::addNestedValue(int parentColumn, int nestedColumn, const QVariant &value) +{ + mNestedValues[parentColumn] = std::make_pair(nestedColumn, value); +} + void CSMWorld::CreateCommand::setType (UniversalId::Type type) { mType = type; diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index cdd398153c..81c40d0abc 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -48,6 +48,9 @@ namespace CSMWorld class CreateCommand : public QUndoCommand { std::map mValues; + std::map > mNestedValues; + ///< Parameter order: a parent column, a nested column, a data. + ///< A nested row has index of 0. protected: @@ -68,6 +71,8 @@ namespace CSMWorld void addValue (int column, const QVariant& value); + void addNestedValue(int parentColumn, int nestedColumn, const QVariant &value); + virtual void redo(); virtual void undo(); From 5761ec428d9c56edd9bca7895422127301a6c935 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 26 Jun 2015 23:38:20 +0300 Subject: [PATCH 0565/1812] Creating/cloning Cell sets the proper Interior flag --- apps/opencs/view/world/cellcreator.cpp | 12 ++++++++++++ apps/opencs/view/world/cellcreator.hpp | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index cdeee56559..5dfb6af45f 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -8,6 +8,9 @@ #include #include +#include "../../model/world/commands.hpp" +#include "../../model/world/idtree.hpp" + std::string CSVWorld::CellCreator::getId() const { if (mType->currentIndex()==0) @@ -20,6 +23,15 @@ std::string CSVWorld::CellCreator::getId() const return stream.str(); } +void CSVWorld::CellCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const +{ + CSMWorld::IdTree *model = dynamic_cast(getData().getTableModel(getCollectionId())); + Q_ASSERT(model != NULL); + int parentIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Cell); + int index = model->findNestedColumnIndex(parentIndex, CSMWorld::Columns::ColumnId_Interior); + command.addNestedValue(parentIndex, index, mType->currentIndex() == 0); +} + CSVWorld::CellCreator::CellCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) : GenericCreator (data, undoStack, id) diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index db9fbf8a34..4d5314f230 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -23,6 +23,9 @@ namespace CSVWorld virtual std::string getId() const; + /// Allow subclasses to add additional data to \a command. + virtual void configureCreateCommand(CSMWorld::CreateCommand& command) const; + public: CellCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); From cad4ce4e0f137b85922be69093061def2f5e7020 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 11:47:59 +0300 Subject: [PATCH 0566/1812] Cell type can be changed when cloning a cell --- apps/opencs/view/world/cellcreator.cpp | 7 ------- apps/opencs/view/world/cellcreator.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index 5dfb6af45f..45fac2c5f0 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -106,10 +106,3 @@ void CSVWorld::CellCreator::cloneMode(const std::string& originId, mType->setCurrentIndex(0); } } - - -void CSVWorld::CellCreator::toggleWidgets(bool active) -{ - CSVWorld::GenericCreator::toggleWidgets(active); - mType->setEnabled(active); -} diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index 4d5314f230..b633ca06e1 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -32,8 +32,6 @@ namespace CSVWorld virtual void reset(); - virtual void toggleWidgets(bool active = true); - virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); From cbb124ab4f05a15d186f481090debae3b4b54753 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 12:26:19 +0300 Subject: [PATCH 0567/1812] Close the creator when the original record is removed (in clone mode) --- apps/opencs/view/world/genericcreator.cpp | 11 +++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ 2 files changed, 13 insertions(+) diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index c641096087..5f04d9a7a8 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -161,6 +161,8 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo connect (mCreate, SIGNAL (clicked (bool)), this, SLOT (create())); connect (mId, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); + + connect (&mData, SIGNAL (idListChanged()), this, SLOT (dataIdListChanged())); } void CSVWorld::GenericCreator::setEditLock (bool locked) @@ -291,3 +293,12 @@ void CSVWorld::GenericCreator::scopeChanged (int index) update(); updateNamespace(); } + +void CSVWorld::GenericCreator::dataIdListChanged() +{ + // If the original ID of cloned record was removed, cancel the creator + if (mCloneMode && !mData.hasId(mClonedId)) + { + emit done(); + } +} diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 0d2a40486f..471d0622eb 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -113,6 +113,8 @@ namespace CSVWorld void create(); void scopeChanged (int index); + + void dataIdListChanged(); }; } From 49dc30683f1e0d9366ab3afa65419e8f9d14c57d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 12:49:56 +0200 Subject: [PATCH 0568/1812] refactored dialogue subview button bar into a new class --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 72 +++------------ apps/opencs/view/world/recordbuttonbar.cpp | 100 +++++++++++++++++++++ apps/opencs/view/world/recordbuttonbar.hpp | 54 +++++++++++ 4 files changed, 165 insertions(+), 63 deletions(-) create mode 100644 apps/opencs/view/world/recordbuttonbar.cpp create mode 100644 apps/opencs/view/world/recordbuttonbar.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3399b9dddb..0607f67eea 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox + dialoguespinbox recordbuttonbar ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 99650834ef..a2f25df44b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -40,6 +40,7 @@ #include "util.hpp" #include "tablebottombox.hpp" #include "nestedtable.hpp" +#include "recordbuttonbar.hpp" /* ==============================NotEditableSubDelegate========================================== */ @@ -712,69 +713,16 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); // buttons - QHBoxLayout *buttonsLayout = new QHBoxLayout; - QToolButton* prevButton = new QToolButton (this); - prevButton->setIcon(QIcon(":/go-previous.png")); - prevButton->setToolTip ("Switch to previous record"); - QToolButton* nextButton = new QToolButton (this); - nextButton->setIcon(QIcon(":/go-next.png")); - nextButton->setToolTip ("Switch to next record"); - buttonsLayout->addWidget(prevButton, 0); - buttonsLayout->addWidget(nextButton, 1); - buttonsLayout->addStretch(2); + RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, + &getCommandDispatcher(), this); + + getMainLayout().addWidget (buttons); - QToolButton* cloneButton = new QToolButton (this); - cloneButton->setIcon(QIcon(":/edit-clone.png")); - cloneButton->setToolTip ("Clone record"); - QToolButton* addButton = new QToolButton (this); - addButton->setIcon(QIcon(":/add.png")); - addButton->setToolTip ("Add new record"); - QToolButton* deleteButton = new QToolButton (this); - deleteButton->setIcon(QIcon(":/edit-delete.png")); - deleteButton->setToolTip ("Delete record"); - QToolButton* revertButton = new QToolButton (this); - revertButton->setIcon(QIcon(":/edit-undo.png")); - revertButton->setToolTip ("Revert record"); - - if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview) - { - QToolButton* previewButton = new QToolButton (this); - previewButton->setIcon(QIcon(":/edit-preview.png")); - previewButton->setToolTip ("Open a preview of this record"); - buttonsLayout->addWidget(previewButton); - connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); - } - - if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View) - { - QToolButton* viewButton = new QToolButton (this); - viewButton->setIcon(QIcon(":/cell.png")); - viewButton->setToolTip ("Open a scene view of the cell this record is located in"); - buttonsLayout->addWidget(viewButton); - connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); - } - - buttonsLayout->addWidget(cloneButton); - buttonsLayout->addWidget(addButton); - buttonsLayout->addWidget(deleteButton); - buttonsLayout->addWidget(revertButton); - - connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); - connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); - connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert())); - connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete())); - - connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); - - if(!mBottom->canCreateAndDelete()) - { - cloneButton->setDisabled (true); - addButton->setDisabled (true); - deleteButton->setDisabled (true); - } - - getMainLayout().addLayout (buttonsLayout); + connect (buttons, SIGNAL(nextId()), this, SLOT(nextId())); + connect (buttons, SIGNAL (prevId()), this, SLOT(prevId())); + connect (buttons, SIGNAL (cloneRequest()), this, SLOT(cloneRequest())); + connect (buttons, SIGNAL (showPreview()), this, SLOT(showPreview())); + connect (buttons, SIGNAL (viewRecord()), this, SLOT(viewRecord())); } void CSVWorld::DialogueSubView::cloneRequest() diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp new file mode 100644 index 0000000000..2f5395317c --- /dev/null +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -0,0 +1,100 @@ + +#include "recordbuttonbar.hpp" + +#include +#include + +#include "../../model/world/idtable.hpp" +#include "../../model/world/commanddispatcher.hpp" + +#include "../world/tablebottombox.hpp" + +CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox, + CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) +: QWidget (parent), mTable (table), mBottom (bottomBox), mCommandDispatcher (commandDispatcher) +{ + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->setContentsMargins (0, 0, 0, 0); + + // left section + QToolButton* prevButton = new QToolButton (this); + prevButton->setIcon(QIcon(":/go-previous.png")); + prevButton->setToolTip ("Switch to previous record"); + buttonsLayout->addWidget (prevButton, 0); + + QToolButton* nextButton = new QToolButton (this); + nextButton->setIcon(QIcon(":/go-next.png")); + nextButton->setToolTip ("Switch to next record"); + buttonsLayout->addWidget (nextButton, 1); + + buttonsLayout->addStretch(2); + + // optional buttons of the right section + if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview) + { + QToolButton* previewButton = new QToolButton (this); + previewButton->setIcon(QIcon(":/edit-preview.png")); + previewButton->setToolTip ("Open a preview of this record"); + buttonsLayout->addWidget(previewButton); + connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview())); + } + + if (mTable.getFeatures() & CSMWorld::IdTable::Feature_View) + { + QToolButton* viewButton = new QToolButton (this); + viewButton->setIcon(QIcon(":/cell.png")); + viewButton->setToolTip ("Open a scene view of the cell this record is located in"); + buttonsLayout->addWidget(viewButton); + connect (viewButton, SIGNAL(clicked()), this, SIGNAL (viewRecord())); + } + + // right section + QToolButton* cloneButton = new QToolButton (this); + cloneButton->setIcon(QIcon(":/edit-clone.png")); + cloneButton->setToolTip ("Clone record"); + buttonsLayout->addWidget(cloneButton); + + QToolButton* addButton = new QToolButton (this); + addButton->setIcon(QIcon(":/add.png")); + addButton->setToolTip ("Add new record"); + buttonsLayout->addWidget(addButton); + + QToolButton* deleteButton = new QToolButton (this); + deleteButton->setIcon(QIcon(":/edit-delete.png")); + deleteButton->setToolTip ("Delete record"); + buttonsLayout->addWidget(deleteButton); + + QToolButton* revertButton = new QToolButton (this); + revertButton->setIcon(QIcon(":/edit-undo.png")); + revertButton->setToolTip ("Revert record"); + buttonsLayout->addWidget(revertButton); + + setLayout (buttonsLayout); + + // disabling and connections + if(!mBottom || !mBottom->canCreateAndDelete()) + { + cloneButton->setDisabled (true); + addButton->setDisabled (true); + deleteButton->setDisabled (true); + } + else + { + connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); + connect (cloneButton, SIGNAL (clicked()), this, SIGNAL (cloneRequest())); + } + + connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); + connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); + + if (!mCommandDispatcher) + { + revertButton->setDisabled (true); + deleteButton->setDisabled (true); + } + else + { + connect (revertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); + connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); + } +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp new file mode 100644 index 0000000000..28e59407f5 --- /dev/null +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -0,0 +1,54 @@ +#ifndef CSV_WORLD_RECORDBUTTONBAR_H +#define CSV_WORLD_RECORDBUTTONBAR_H + +#include + +namespace CSMWorld +{ + class IdTable; + class CommandDispatcher; +} + +namespace CSVWorld +{ + class TableBottomBox; + + /// \brief Button bar for use in dialogue-type subviews + /// + /// Contains the following buttons: + /// - next/prev + /// - clone + /// - add + /// - delete + /// - revert + /// - preview (optional) + /// - view (optional) + class RecordButtonBar : public QWidget + { + Q_OBJECT + + CSMWorld::IdTable& mTable; + TableBottomBox *mBottom; + CSMWorld::CommandDispatcher *mCommandDispatcher; + + public: + + RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, + CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + + signals: + + void showPreview(); + + void viewRecord(); + + void nextId(); + + void prevId(); + + void cloneRequest(); + + }; +} + +#endif From 7f1129df3b22334f6531d82f9dee95f26bb860e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 12:53:46 +0200 Subject: [PATCH 0569/1812] cleaned up DialogueSubView constructor; moved bottom box below button bar --- apps/opencs/view/world/dialoguesubview.cpp | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a2f25df44b..5669d9680d 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -706,23 +706,27 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, : SimpleDialogueSubView (id, document) { // bottom box - getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); + mBottom = new TableBottomBox (creatorFactory, document, id, this); - mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); - connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect (mBottom, SIGNAL (requestFocus (const std::string&)), + this, SLOT (requestFocus (const std::string&))); - // buttons + // button bar RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, &getCommandDispatcher(), this); - - getMainLayout().addWidget (buttons); - connect (buttons, SIGNAL(nextId()), this, SLOT(nextId())); - connect (buttons, SIGNAL (prevId()), this, SLOT(prevId())); - connect (buttons, SIGNAL (cloneRequest()), this, SLOT(cloneRequest())); - connect (buttons, SIGNAL (showPreview()), this, SLOT(showPreview())); - connect (buttons, SIGNAL (viewRecord()), this, SLOT(viewRecord())); + // layout + getMainLayout().addWidget (buttons); + getMainLayout().addWidget (mBottom); + + // connections + connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); + connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); + connect (buttons, SIGNAL (cloneRequest()), this, SLOT (cloneRequest())); + connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); } void CSVWorld::DialogueSubView::cloneRequest() From 67694793586200ec9b2ff48ceacccdeda65d89ee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 13:47:07 +0200 Subject: [PATCH 0570/1812] moved code for initiating record cloning from DialogueSubView to RecordButtonBar --- apps/opencs/view/doc/subview.cpp | 1 + apps/opencs/view/doc/subview.hpp | 2 ++ apps/opencs/view/world/dialoguesubview.cpp | 12 +++------ apps/opencs/view/world/dialoguesubview.hpp | 2 -- apps/opencs/view/world/recordbuttonbar.cpp | 30 +++++++++++++++++++--- apps/opencs/view/world/recordbuttonbar.hpp | 17 +++++++++--- 6 files changed, 46 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index f4f0c6afe8..e0c2fbc46a 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -45,6 +45,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); + emit universalIdChanged (mUniversalId); } void CSVDoc::SubView::closeEvent (QCloseEvent *event) diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index b323f9ed92..189bb40ebe 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -68,6 +68,8 @@ namespace CSVDoc void updateSubViewIndicies (SubView *view = 0); + void universalIdChanged (const CSMWorld::UniversalId& universalId); + protected slots: void closeRequest(); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5669d9680d..92b9807e85 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -714,7 +714,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - RecordButtonBar *buttons = new RecordButtonBar (getTable(), mBottom, + RecordButtonBar *buttons = new RecordButtonBar (id, getTable(), mBottom, &getCommandDispatcher(), this); // layout @@ -724,16 +724,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, // connections connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); - connect (buttons, SIGNAL (cloneRequest()), this, SLOT (cloneRequest())); connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); -} - -void CSVWorld::DialogueSubView::cloneRequest() -{ - mBottom->cloneRequest (getCurrentId(), - static_cast (getTable(). - data (getTable().getModelIndex(getCurrentId(), 2)).toInt())); + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + buttons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } void CSVWorld::DialogueSubView::prevId() diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5d6915d42d..6c0fcc59b0 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -231,8 +231,6 @@ namespace CSVWorld private slots: - void cloneRequest(); - void nextId(); void prevId(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 2f5395317c..1560a31a56 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -9,9 +9,11 @@ #include "../world/tablebottombox.hpp" -CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox, +CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, + CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) -: QWidget (parent), mTable (table), mBottom (bottomBox), mCommandDispatcher (commandDispatcher) +: QWidget (parent), mId (id), mTable (table), mBottom (bottomBox), + mCommandDispatcher (commandDispatcher) { QHBoxLayout *buttonsLayout = new QHBoxLayout; buttonsLayout->setContentsMargins (0, 0, 0, 0); @@ -81,7 +83,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBotto else { connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); - connect (cloneButton, SIGNAL (clicked()), this, SIGNAL (cloneRequest())); + connect (cloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); @@ -98,3 +100,25 @@ CSVWorld::RecordButtonBar::RecordButtonBar (CSMWorld::IdTable& table, TableBotto connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } } + +void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) +{ + mId = id; +} + +void CSVWorld::RecordButtonBar::cloneRequest() +{ + if (mBottom) + { + int typeColumn = mTable.searchColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + + if (typeColumn!=-1) + { + QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); + CSMWorld::UniversalId::Type type = static_cast ( + mTable.data (typeIndex).toInt()); + + mBottom->cloneRequest (mId.getId(), type); + } + } +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 28e59407f5..08f16a6877 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -3,6 +3,8 @@ #include +#include "../../model/world/universalid.hpp" + namespace CSMWorld { class IdTable; @@ -27,15 +29,25 @@ namespace CSVWorld { Q_OBJECT + CSMWorld::UniversalId mId; CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; public: - RecordButtonBar (CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, + RecordButtonBar (const CSMWorld::UniversalId& id, + CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + public slots: + + void universalIdChanged (const CSMWorld::UniversalId& id); + + private slots: + + void cloneRequest(); + signals: void showPreview(); @@ -45,9 +57,6 @@ namespace CSVWorld void nextId(); void prevId(); - - void cloneRequest(); - }; } From d5e6d8a58bf666518cb21e7508e8f28b335effd4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 14:25:48 +0200 Subject: [PATCH 0571/1812] disable dialogue subview buttons while document is locked --- apps/opencs/view/world/dialoguesubview.cpp | 20 ++++-- apps/opencs/view/world/dialoguesubview.hpp | 5 ++ apps/opencs/view/world/recordbuttonbar.cpp | 81 ++++++++++++---------- apps/opencs/view/world/recordbuttonbar.hpp | 13 ++++ 4 files changed, 77 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 92b9807e85..ffb6064975 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -714,20 +714,26 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - RecordButtonBar *buttons = new RecordButtonBar (id, getTable(), mBottom, + mButtons = new RecordButtonBar (id, getTable(), mBottom, &getCommandDispatcher(), this); // layout - getMainLayout().addWidget (buttons); + getMainLayout().addWidget (mButtons); getMainLayout().addWidget (mBottom); // connections - connect (buttons, SIGNAL (nextId()), this, SLOT (nextId())); - connect (buttons, SIGNAL (prevId()), this, SLOT (prevId())); - connect (buttons, SIGNAL (showPreview()), this, SLOT (showPreview())); - connect (buttons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (nextId()), this, SLOT (nextId())); + connect (mButtons, SIGNAL (prevId()), this, SLOT (prevId())); + connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - buttons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + +void CSVWorld::DialogueSubView::setEditLock (bool locked) +{ + SimpleDialogueSubView::setEditLock (locked); + mButtons->setEditLock (locked); } void CSVWorld::DialogueSubView::prevId() diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6c0fcc59b0..63b25d06e5 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -218,17 +218,22 @@ namespace CSVWorld void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; + class RecordButtonBar; + class DialogueSubView : public SimpleDialogueSubView { Q_OBJECT TableBottomBox* mBottom; + RecordButtonBar *mButtons; public: DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting = false); + virtual void setEditLock (bool locked); + private slots: void nextId(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 1560a31a56..93a6a5823c 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -9,11 +9,25 @@ #include "../world/tablebottombox.hpp" +void CSVWorld::RecordButtonBar::updateModificationButtons() +{ + bool createAndDeleteDisabled = !mBottom || !mBottom->canCreateAndDelete() || mLocked; + + mCloneButton->setDisabled (createAndDeleteDisabled); + mAddButton->setDisabled (createAndDeleteDisabled); + mDeleteButton->setDisabled (createAndDeleteDisabled); + + bool commandDisabled = !mCommandDispatcher || mLocked; + + mRevertButton->setDisabled (commandDisabled); + mDeleteButton->setDisabled (commandDisabled); +} + CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) : QWidget (parent), mId (id), mTable (table), mBottom (bottomBox), - mCommandDispatcher (commandDispatcher) + mCommandDispatcher (commandDispatcher), mLocked (false) { QHBoxLayout *buttonsLayout = new QHBoxLayout; buttonsLayout->setContentsMargins (0, 0, 0, 0); @@ -51,54 +65,51 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, } // right section - QToolButton* cloneButton = new QToolButton (this); - cloneButton->setIcon(QIcon(":/edit-clone.png")); - cloneButton->setToolTip ("Clone record"); - buttonsLayout->addWidget(cloneButton); + mCloneButton = new QToolButton (this); + mCloneButton->setIcon(QIcon(":/edit-clone.png")); + mCloneButton->setToolTip ("Clone record"); + buttonsLayout->addWidget(mCloneButton); - QToolButton* addButton = new QToolButton (this); - addButton->setIcon(QIcon(":/add.png")); - addButton->setToolTip ("Add new record"); - buttonsLayout->addWidget(addButton); + mAddButton = new QToolButton (this); + mAddButton->setIcon(QIcon(":/add.png")); + mAddButton->setToolTip ("Add new record"); + buttonsLayout->addWidget(mAddButton); - QToolButton* deleteButton = new QToolButton (this); - deleteButton->setIcon(QIcon(":/edit-delete.png")); - deleteButton->setToolTip ("Delete record"); - buttonsLayout->addWidget(deleteButton); + mDeleteButton = new QToolButton (this); + mDeleteButton->setIcon(QIcon(":/edit-delete.png")); + mDeleteButton->setToolTip ("Delete record"); + buttonsLayout->addWidget(mDeleteButton); - QToolButton* revertButton = new QToolButton (this); - revertButton->setIcon(QIcon(":/edit-undo.png")); - revertButton->setToolTip ("Revert record"); - buttonsLayout->addWidget(revertButton); + mRevertButton = new QToolButton (this); + mRevertButton->setIcon(QIcon(":/edit-undo.png")); + mRevertButton->setToolTip ("Revert record"); + buttonsLayout->addWidget(mRevertButton); setLayout (buttonsLayout); - // disabling and connections - if(!mBottom || !mBottom->canCreateAndDelete()) + // connections + if(mBottom && mBottom->canCreateAndDelete()) { - cloneButton->setDisabled (true); - addButton->setDisabled (true); - deleteButton->setDisabled (true); - } - else - { - connect (addButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); - connect (cloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); + connect (mAddButton, SIGNAL (clicked()), mBottom, SLOT (createRequest())); + connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); - if (!mCommandDispatcher) + if (mCommandDispatcher) { - revertButton->setDisabled (true); - deleteButton->setDisabled (true); - } - else - { - connect (revertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); - connect (deleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); + connect (mRevertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert())); + connect (mDeleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } + + updateModificationButtons(); +} + +void CSVWorld::RecordButtonBar::setEditLock (bool locked) +{ + mLocked = locked; + updateModificationButtons(); } void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 08f16a6877..95b567594f 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -5,6 +5,8 @@ #include "../../model/world/universalid.hpp" +class QToolButton; + namespace CSMWorld { class IdTable; @@ -33,13 +35,24 @@ namespace CSVWorld CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; + QToolButton *mCloneButton; + QToolButton *mAddButton; + QToolButton *mDeleteButton; + QToolButton *mRevertButton; + bool mLocked; + private: + + void updateModificationButtons(); + public: RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0, CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); + void setEditLock (bool locked); + public slots: void universalIdChanged (const CSMWorld::UniversalId& id); From a8c26ec0c11a5252de2e75fd26d9d83ef1afc13e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 14:42:22 +0200 Subject: [PATCH 0572/1812] moved most of the code for next/prev buttons from DialogueSubView to RecordBUttonBar --- apps/opencs/view/world/dialoguesubview.cpp | 88 ++++------------------ apps/opencs/view/world/dialoguesubview.hpp | 6 +- apps/opencs/view/world/recordbuttonbar.cpp | 28 ++++++- apps/opencs/view/world/recordbuttonbar.hpp | 8 +- 4 files changed, 47 insertions(+), 83 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ffb6064975..cf9d69f028 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -722,10 +722,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, getMainLayout().addWidget (mBottom); // connections - connect (mButtons, SIGNAL (nextId()), this, SLOT (nextId())); - connect (mButtons, SIGNAL (prevId()), this, SLOT (prevId())); connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } @@ -736,78 +736,6 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } -void CSVWorld::DialogueSubView::prevId() -{ - int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1; - - if (newRow < 0) - { - return; - } - while (newRow >= 0) - { - QModelIndex newIndex (getTable().index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) - { - getEditWidget().remake (newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), - getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - getEditWidget().setDisabled (isLocked()); - - return; - } - --newRow; - } -} - -void CSVWorld::DialogueSubView::nextId () -{ - int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1; - - if (newRow >= getTable().rowCount()) - { - return; - } - - while (newRow < getTable().rowCount()) - { - QModelIndex newIndex (getTable().index(newRow, 0)); - - if (!newIndex.isValid()) - { - return; - } - - CSMWorld::RecordBase::State state = static_cast (getTable().data (getTable().index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted)) - { - getEditWidget().remake(newRow); - - setUniversalId(CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (newRow, 2)).toInt()), - getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData())); - - getEditWidget().setDisabled (isLocked()); - - return; - } - ++newRow; - } -} - - void CSVWorld::DialogueSubView::showPreview () { QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); @@ -833,3 +761,15 @@ void CSVWorld::DialogueSubView::viewRecord () emit focusId (params.first, params.second); } } + +void CSVWorld::DialogueSubView::switchToRow (int row) +{ + getEditWidget().remake (row); + + setUniversalId (CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (row, 2)).toInt()), + getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + + changeCurrentId(std::string (getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + + getEditWidget().setDisabled (isLocked()); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 63b25d06e5..ff70a37d3f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -236,13 +236,11 @@ namespace CSVWorld private slots: - void nextId(); - - void prevId(); - void showPreview(); void viewRecord(); + + void switchToRow (int row); }; } diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 93a6a5823c..375ab68c3d 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -94,8 +94,8 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } - connect (nextButton, SIGNAL (clicked()), this, SIGNAL (nextId())); - connect (prevButton, SIGNAL (clicked()), this, SIGNAL (prevId())); + connect (nextButton, SIGNAL (clicked()), this, SLOT (nextId())); + connect (prevButton, SIGNAL (clicked()), this, SLOT (prevId())); if (mCommandDispatcher) { @@ -133,3 +133,27 @@ void CSVWorld::RecordButtonBar::cloneRequest() } } } + +void CSVWorld::RecordButtonBar::nextId() +{ + int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; + + if (newRow >= mTable.rowCount()) + { + return; + } + + emit switchToRow (newRow); +} + +void CSVWorld::RecordButtonBar::prevId() +{ + int newRow = mTable.getModelIndex (mId.getId(), 0).row() - 1; + + if (newRow < 0) + { + return; + } + + emit switchToRow (newRow); +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 95b567594f..6a5fadca57 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -60,6 +60,10 @@ namespace CSVWorld private slots: void cloneRequest(); + + void nextId(); + + void prevId(); signals: @@ -67,9 +71,7 @@ namespace CSVWorld void viewRecord(); - void nextId(); - - void prevId(); + void switchToRow (int row); }; } From 9aa153984aa0e5b8cfe347eadada6b1be262b0c4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:02:50 +0200 Subject: [PATCH 0573/1812] fixed inconsistent handling of deleted records in dialogue; general cleanup --- apps/opencs/view/world/dialoguesubview.cpp | 19 ++++++++++++++----- apps/opencs/view/world/recordbuttonbar.cpp | 15 ++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cf9d69f028..4ef06766cd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -764,12 +764,21 @@ void CSVWorld::DialogueSubView::viewRecord () void CSVWorld::DialogueSubView::switchToRow (int row) { + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + std::string id = getTable().data (getTable().index (row, idColumn)).toString().toUtf8().constData(); + + int typeColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + CSMWorld::UniversalId::Type type = static_cast ( + getTable().data (getTable().index (row, typeColumn)).toInt()); + + setUniversalId (CSMWorld::UniversalId (type, id)); + changeCurrentId (id); + getEditWidget().remake (row); - setUniversalId (CSMWorld::UniversalId (static_cast (getTable().data (getTable().index (row, 2)).toInt()), - getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); + int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification); + CSMWorld::RecordBase::State state = static_cast ( + getTable().data (getTable().index (row, stateColumn)).toInt()); - changeCurrentId(std::string (getTable().data (getTable().index (row, 0)).toString().toUtf8().constData())); - - getEditWidget().setDisabled (isLocked()); + getEditWidget().setDisabled (isLocked() || state==CSMWorld::RecordBase::State_Deleted); } diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 375ab68c3d..db23203415 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -121,16 +121,13 @@ void CSVWorld::RecordButtonBar::cloneRequest() { if (mBottom) { - int typeColumn = mTable.searchColumnIndex (CSMWorld::Columns::ColumnId_RecordType); + int typeColumn = mTable.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); - if (typeColumn!=-1) - { - QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); - CSMWorld::UniversalId::Type type = static_cast ( - mTable.data (typeIndex).toInt()); - - mBottom->cloneRequest (mId.getId(), type); - } + QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn); + CSMWorld::UniversalId::Type type = static_cast ( + mTable.data (typeIndex).toInt()); + + mBottom->cloneRequest (mId.getId(), type); } } From 95522fcad29cd72a58c16fa064b5bd9553689642 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:29:54 +0200 Subject: [PATCH 0574/1812] more general cleanup --- apps/opencs/view/world/dialoguesubview.cpp | 51 +++++++++------------- apps/opencs/view/world/dialoguesubview.hpp | 24 +++++----- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4ef06766cd..69255f8212 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include @@ -573,11 +571,6 @@ CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatch return mCommandDispatcher; } -std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const -{ - return mCurrentId; -} - CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget() { return *mEditWidget; @@ -593,7 +586,6 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mEditWidget(0), mMainLayout(NULL), mTable(dynamic_cast(document.getData().getTableModel(id))), - mUndoStack(document.getUndoStack()), mLocked(false), mDocument(document), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -601,7 +593,7 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); connect(mTable, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int))); - changeCurrentId(id.getId()); + updateCurrentId(); QWidget *mainWidget = new QWidget(this); @@ -609,21 +601,21 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa setWidget (mainWidget); mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); + mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - dataChanged(mTable->getModelIndex (mCurrentId, 0)); + dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); } void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) { - if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid + if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid return; mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid()) { @@ -638,7 +630,7 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid() && (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) @@ -671,7 +663,7 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) { @@ -684,19 +676,10 @@ void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &pa } } -void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id) -{ - changeCurrentId(id); - - mEditWidget->remake(mTable->getModelIndex (id, 0).row()); -} - -void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId) +void CSVWorld::SimpleDialogueSubView::updateCurrentId() { std::vector selection; - mCurrentId = std::string(newId); - - selection.push_back(mCurrentId); + selection.push_back (getUniversalId().getId()); mCommandDispatcher.setSelection(selection); } @@ -738,19 +721,19 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); if (currentIndex.isValid() && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && currentIndex.row() < getTable().rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getUniversalId().getId()), ""); } } void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0)); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); if (currentIndex.isValid() && currentIndex.row() < getTable().rowCount()) @@ -772,7 +755,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row) getTable().data (getTable().index (row, typeColumn)).toInt()); setUniversalId (CSMWorld::UniversalId (type, id)); - changeCurrentId (id); + updateCurrentId(); getEditWidget().remake (row); @@ -782,3 +765,11 @@ void CSVWorld::DialogueSubView::switchToRow (int row) getEditWidget().setDisabled (isLocked() || state==CSMWorld::RecordBase::State_Deleted); } + +void CSVWorld::DialogueSubView::requestFocus (const std::string& id) +{ + QModelIndex index = getTable().getModelIndex (id, 0); + + if (index.isValid()) + switchToRow (index.row()); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index ff70a37d3f..aec98d69c3 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -175,16 +175,14 @@ namespace CSVWorld class SimpleDialogueSubView : public CSVDoc::SubView { - Q_OBJECT + Q_OBJECT - EditWidget* mEditWidget; - QVBoxLayout* mMainLayout; - CSMWorld::IdTable* mTable; - QUndoStack& mUndoStack; - std::string mCurrentId; - bool mLocked; - const CSMDoc::Document& mDocument; - CSMWorld::CommandDispatcher mCommandDispatcher; + EditWidget* mEditWidget; + QVBoxLayout* mMainLayout; + CSMWorld::IdTable* mTable; + bool mLocked; + const CSMDoc::Document& mDocument; + CSMWorld::CommandDispatcher mCommandDispatcher; protected: @@ -194,11 +192,9 @@ namespace CSVWorld CSMWorld::CommandDispatcher& getCommandDispatcher(); - std::string getCurrentId() const; - EditWidget& getEditWidget(); - void changeCurrentId(const std::string& newCurrent); + void updateCurrentId(); bool isLocked() const; @@ -213,8 +209,6 @@ namespace CSVWorld void dataChanged(const QModelIndex & index); ///\brief we need to care for deleting currently edited record - void requestFocus (const std::string& id); - void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); }; @@ -241,6 +235,8 @@ namespace CSVWorld void viewRecord(); void switchToRow (int row); + + void requestFocus (const std::string& id); }; } From e27a75bd103430a3b88190b4e63612706116ba24 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 15:56:41 +0200 Subject: [PATCH 0575/1812] added user setting for cyclic prev/next --- apps/opencs/model/settings/usersettings.cpp | 8 ++++++++ apps/opencs/view/world/recordbuttonbar.cpp | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3e59d0582f..bcf7c3ba9c 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -356,6 +356,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); } + declareSection ("general-input", "General Input"); + { + Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous"); + cycle->setDefaultValue ("false"); + cycle->setToolTip ("When using next/previous functions at the last/first item of a " + "list go to the first/last item"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index db23203415..5dcc1d5cd0 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -7,6 +7,8 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../../model/settings/usersettings.hpp" + #include "../world/tablebottombox.hpp" void CSVWorld::RecordButtonBar::updateModificationButtons() @@ -132,12 +134,16 @@ void CSVWorld::RecordButtonBar::cloneRequest() } void CSVWorld::RecordButtonBar::nextId() -{ +{ int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; if (newRow >= mTable.rowCount()) { - return; + if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") + =="true") + newRow = 0; + else + return; } emit switchToRow (newRow); @@ -149,7 +155,11 @@ void CSVWorld::RecordButtonBar::prevId() if (newRow < 0) { - return; + if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") + =="true") + newRow = mTable.rowCount()-1; + else + return; } emit switchToRow (newRow); From 15bb2855a99d548b3f13aa799dc188dd0dab2b56 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Jun 2015 16:57:45 +0200 Subject: [PATCH 0576/1812] disable prev/next buttons if there is no previous/next record --- apps/opencs/view/world/dialoguesubview.cpp | 6 +++ apps/opencs/view/world/dialoguesubview.hpp | 2 + apps/opencs/view/world/recordbuttonbar.cpp | 61 ++++++++++++++++++---- apps/opencs/view/world/recordbuttonbar.hpp | 11 +++- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 69255f8212..1d3eb53139 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -719,6 +719,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } +void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) +{ + SimpleDialogueSubView::updateUserSetting (name, value); + mButtons->updateUserSetting (name, value); +} + void CSVWorld::DialogueSubView::showPreview () { QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index aec98d69c3..be58be5ade 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -228,6 +228,8 @@ namespace CSVWorld virtual void setEditLock (bool locked); + virtual void updateUserSetting (const QString& name, const QStringList& value); + private slots: void showPreview(); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 5dcc1d5cd0..63c0dd0a18 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -25,6 +25,29 @@ void CSVWorld::RecordButtonBar::updateModificationButtons() mDeleteButton->setDisabled (commandDisabled); } +void CSVWorld::RecordButtonBar::updatePrevNextButtons() +{ + int rows = mTable.rowCount(); + + if (rows<=1) + { + mPrevButton->setDisabled (true); + mNextButton->setDisabled (true); + } + else if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")=="true") + { + mPrevButton->setDisabled (false); + mNextButton->setDisabled (false); + } + else + { + int row = mTable.getModelIndex (mId.getId(), 0).row(); + + mPrevButton->setDisabled (row<=0); + mNextButton->setDisabled (row>=rows-1); + } +} + CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, CSMWorld::IdTable& table, TableBottomBox *bottomBox, CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent) @@ -35,15 +58,15 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, buttonsLayout->setContentsMargins (0, 0, 0, 0); // left section - QToolButton* prevButton = new QToolButton (this); - prevButton->setIcon(QIcon(":/go-previous.png")); - prevButton->setToolTip ("Switch to previous record"); - buttonsLayout->addWidget (prevButton, 0); + mPrevButton = new QToolButton (this); + mPrevButton->setIcon(QIcon(":/go-previous.png")); + mPrevButton->setToolTip ("Switch to previous record"); + buttonsLayout->addWidget (mPrevButton, 0); - QToolButton* nextButton = new QToolButton (this); - nextButton->setIcon(QIcon(":/go-next.png")); - nextButton->setToolTip ("Switch to next record"); - buttonsLayout->addWidget (nextButton, 1); + mNextButton = new QToolButton (this); + mNextButton->setIcon(QIcon(":/go-next.png")); + mNextButton->setToolTip ("Switch to next record"); + buttonsLayout->addWidget (mNextButton, 1); buttonsLayout->addStretch(2); @@ -96,8 +119,8 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest())); } - connect (nextButton, SIGNAL (clicked()), this, SLOT (nextId())); - connect (prevButton, SIGNAL (clicked()), this, SLOT (prevId())); + connect (mNextButton, SIGNAL (clicked()), this, SLOT (nextId())); + connect (mPrevButton, SIGNAL (clicked()), this, SLOT (prevId())); if (mCommandDispatcher) { @@ -105,7 +128,13 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (mDeleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete())); } + connect (&mTable, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + updateModificationButtons(); + updatePrevNextButtons(); } void CSVWorld::RecordButtonBar::setEditLock (bool locked) @@ -114,9 +143,16 @@ void CSVWorld::RecordButtonBar::setEditLock (bool locked) updateModificationButtons(); } +void CSVWorld::RecordButtonBar::updateUserSetting (const QString& name, const QStringList& value) +{ + if (name=="general-input/cycle") + updatePrevNextButtons(); +} + void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) { mId = id; + updatePrevNextButtons(); } void CSVWorld::RecordButtonBar::cloneRequest() @@ -164,3 +200,8 @@ void CSVWorld::RecordButtonBar::prevId() emit switchToRow (newRow); } + +void CSVWorld::RecordButtonBar::rowNumberChanged (const QModelIndex& parent, int start, int end) +{ + updatePrevNextButtons(); +} diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 6a5fadca57..93ca45518e 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -6,6 +6,7 @@ #include "../../model/world/universalid.hpp" class QToolButton; +class QModelIndex; namespace CSMWorld { @@ -35,6 +36,8 @@ namespace CSVWorld CSMWorld::IdTable& mTable; TableBottomBox *mBottom; CSMWorld::CommandDispatcher *mCommandDispatcher; + QToolButton *mPrevButton; + QToolButton *mNextButton; QToolButton *mCloneButton; QToolButton *mAddButton; QToolButton *mDeleteButton; @@ -44,6 +47,8 @@ namespace CSVWorld private: void updateModificationButtons(); + + void updatePrevNextButtons(); public: @@ -52,7 +57,9 @@ namespace CSVWorld CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0); void setEditLock (bool locked); - + + void updateUserSetting (const QString& name, const QStringList& value); + public slots: void universalIdChanged (const CSMWorld::UniversalId& id); @@ -64,6 +71,8 @@ namespace CSVWorld void nextId(); void prevId(); + + void rowNumberChanged (const QModelIndex& parent, int start, int end); signals: From 81c7ce5b06783e26b174ab2003d37cd503422f2c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 27 Jun 2015 21:59:16 +0300 Subject: [PATCH 0577/1812] Add the proper getErrors() method to CellCreator. Fix the impossibility of the Exterior Cell creation. --- apps/opencs/view/world/cellcreator.cpp | 14 ++++++++++++++ apps/opencs/view/world/cellcreator.hpp | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index 45fac2c5f0..c7d909f4cf 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -106,3 +106,17 @@ void CSVWorld::CellCreator::cloneMode(const std::string& originId, mType->setCurrentIndex(0); } } + +std::string CSVWorld::CellCreator::getErrors() const +{ + std::string errors; + if (mType->currentIndex() == 0) + { + errors = GenericCreator::getErrors(); + } + else if (getData().hasId(getId())) + { + errors = "The Exterior Cell is already exist"; + } + return errors; +} diff --git a/apps/opencs/view/world/cellcreator.hpp b/apps/opencs/view/world/cellcreator.hpp index b633ca06e1..6c682c6cd4 100644 --- a/apps/opencs/view/world/cellcreator.hpp +++ b/apps/opencs/view/world/cellcreator.hpp @@ -35,6 +35,10 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); + virtual std::string getErrors() const; + ///< Return formatted error descriptions for the current state of the creator. if an empty + /// string is returned, there is no error. + private slots: void setType (int index); From e4d52ff9b0056a7824c797af144e7364bd6aac98 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 28 Jun 2015 00:31:41 +0300 Subject: [PATCH 0578/1812] Deleted records can be cloned --- apps/opencs/view/world/table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index d757d5bbed..ba691131b0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -447,7 +447,7 @@ void CSVWorld::Table::cloneRecord() { QModelIndexList selectedRows = selectionModel()->selectedRows(); const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row()); - if (selectedRows.size()==1 && !mModel->isDeleted (toClone.getId())) + if (selectedRows.size() == 1) { emit cloneRequest (toClone); } From cd2e6d44367e84d94373bfec68fcb24992d5ea50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Jun 2015 05:53:03 +0200 Subject: [PATCH 0579/1812] Move the __STDC_CONSTANT_MACROS define to cmakelists --- CMakeLists.txt | 2 ++ apps/openmw/mwsound/ffmpeg_decoder.hpp | 6 ------ apps/openmw/mwsound/libavwrapper.cpp | 3 --- extern/osg-ffmpeg-videoplayer/audiodecoder.hpp | 3 --- extern/osg-ffmpeg-videoplayer/libavwrapper.cpp | 3 --- extern/osg-ffmpeg-videoplayer/videoplayer.hpp | 6 ------ extern/osg-ffmpeg-videoplayer/videostate.hpp | 3 --- 7 files changed, 2 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bcdf35e2a..a133a8d6a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,8 @@ else() message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") endif() endif() +# Required for building the FFmpeg headers +add_definitions(-D__STDC_CONSTANT_MACROS) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 3abf7c474d..da8e58964b 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -1,12 +1,6 @@ #ifndef GAME_SOUND_FFMPEG_DECODER_H #define GAME_SOUND_FFMPEG_DECODER_H -// FIXME: This can't be right? The headers refuse to build without UINT64_C, -// which only gets defined in stdint.h in either C99 mode or with this macro -// defined... -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include extern "C" { diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp index a7a3245da3..40be671760 100644 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -1,9 +1,6 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp index fe36ec39f1..a592b02d37 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.hpp @@ -1,9 +1,6 @@ #ifndef VIDEOPLAYER_AUDIODECODER_H #define VIDEOPLAYER_AUDIODECODER_H -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp index 6edc362077..26a7b63706 100644 --- a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp +++ b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp @@ -3,9 +3,6 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp index 79f9edb1c6..c118ddb7f5 100644 --- a/extern/osg-ffmpeg-videoplayer/videoplayer.hpp +++ b/extern/osg-ffmpeg-videoplayer/videoplayer.hpp @@ -1,12 +1,6 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H -// FIXME: This can't be right? The ffmpeg headers refuse to build without UINT64_C, -// which only gets defined in stdint.h in either C99 mode or with this macro -// defined... -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 247e04ec47..72a2aab186 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -1,9 +1,6 @@ #ifndef VIDEOPLAYER_VIDEOSTATE_H #define VIDEOPLAYER_VIDEOSTATE_H -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif #include #include From bbf4927a10db240cac09fc77a53fcd4b9f4ba5b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Jun 2015 16:38:11 +0200 Subject: [PATCH 0580/1812] Disable OSX travis for now, needs to be updated with an OSG package --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6b03be1141..d3b54b1797 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ os: - linux - - osx +# - osx language: cpp branches: only: From 017c9f7ac9f2f6b7f8adac319e5bb6e9b71d28f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Jun 2015 20:19:46 +0200 Subject: [PATCH 0581/1812] Fading for weather particle effects --- apps/openmw/mwrender/sky.cpp | 81 ++++++++++++++++++++++++++++++------ apps/openmw/mwrender/sky.hpp | 2 + 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1aa2fd8644..56afaadf16 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -687,10 +687,11 @@ private: float mAngle; }; -class RainFader : public SceneUtil::StateSetUpdater +// Updater for alpha value on a node's StateSet. Assumes the node has an existing Material StateAttribute. +class AlphaFader : public SceneUtil::StateSetUpdater { public: - RainFader() + AlphaFader() : mAlpha(1.f) { } @@ -700,20 +701,71 @@ public: mAlpha = alpha; } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + } + + // Helper for adding AlphaFader to a subgraph + class SetupVisitor : public osg::NodeVisitor + { + public: + SetupVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + mAlphaFader = new AlphaFader; + } + + virtual void apply(osg::Node &node) + { + if (osg::StateSet* stateset = node.getStateSet()) + { + if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) + { + SceneUtil::CompositeStateSetUpdater* composite = NULL; + osg::NodeCallback* callback = node.getUpdateCallback(); + while (callback) + { + if ((composite = dynamic_cast(callback))) + break; + callback = callback->getNestedCallback(); + } + + if (composite) + composite->addController(mAlphaFader); + else + node.addUpdateCallback(mAlphaFader); + } + } + traverse(node); + } + + osg::ref_ptr getAlphaFader() + { + return mAlphaFader; + } + + private: + osg::ref_ptr mAlphaFader; + }; + +private: + float mAlpha; +}; + +class RainFader : public AlphaFader +{ +public: virtual void setDefaults(osg::StateSet* stateset) { osg::ref_ptr mat (new osg::Material); mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) - { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); - } - private: float mAlpha; }; @@ -928,6 +980,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mParticleNode = NULL; } mParticleEffect = NULL; + mParticleFader = NULL; } else { @@ -940,6 +993,10 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); + + AlphaFader::SetupVisitor alphaFaderSetupVisitor; + mParticleEffect->accept(alphaFaderSetupVisitor); + mParticleFader = alphaFaderSetupVisitor.getAlphaFader(); } } @@ -1025,14 +1082,12 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); mSun->setVisibility(weather.mGlareView * strength); - - - if (mParticle.get()) - setAlpha(mParticle, weather.mEffectFade); - */ + */ if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? + if (mParticleFader) + mParticleFader->setAlpha(weather.mEffectFade); } void SkyManager::setGlare(const float glare) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 85174896b2..4d1c73e446 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -31,6 +31,7 @@ namespace MWRender class Moon; class RainShooter; class RainFader; + class AlphaFader; class SkyManager { @@ -104,6 +105,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; + osg::ref_ptr mParticleFader; osg::ref_ptr mCloudNode; From e2103287aa0a9114b8e6b401aa3a699577aeec47 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 29 Jun 2015 22:45:34 +0300 Subject: [PATCH 0582/1812] Not accepted drag event must be ignored --- apps/opencs/view/world/dragrecordtable.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 5e8ddae26d..a5f933283c 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -55,12 +55,10 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) if (index.flags() & Qt::ItemIsEditable) { event->accept(); + return; } } - else - { - event->ignore(); - } + event->ignore(); } void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) From d5a47cfafee1c7929635365f6587f31e7990f8f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 01:41:03 +0200 Subject: [PATCH 0583/1812] Include cleanup --- apps/openmw/mwrender/sky.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 56afaadf16..dc43783ff5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -17,8 +16,6 @@ #include #include -#include - #include #include From 4b2391c60fc11ada92b484f96c7edfc910a23c70 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 02:51:32 +0200 Subject: [PATCH 0584/1812] Ignore effect meshes in getScreenBounds --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2189f185b6..d85c1c0065 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -488,7 +488,7 @@ namespace MWRender return osg::Vec4f(); osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(~MWRender::Mask_ParticleSystem); + computeBoundsVisitor.setTraversalMask(~(Mask_ParticleSystem|Mask_Effect)); ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); From ca21e9ecb174fb4ab2bd86803a35677d762471c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 02:52:09 +0200 Subject: [PATCH 0585/1812] Fix magic hit VFX showing when casting on a static object --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6980a7e6f5..d8f331c625 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2653,6 +2653,10 @@ namespace MWWorld target = result.mHitObject; hitPosition = result.mHitPos; + // don't allow casting on non-activatable objects + if (!target.isEmpty() && !target.getClass().isActor() && target.getClass().getName(target).empty()) + target = MWWorld::Ptr(); + std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From 43f9c7f2954fcc78e93e8a504328739a03807398 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:25:30 +0200 Subject: [PATCH 0586/1812] Skip the Update traversal for inactive skeletons --- components/sceneutil/skeleton.cpp | 7 +++++++ components/sceneutil/skeleton.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 96941126b9..5c2af4397e 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -133,6 +133,13 @@ bool Skeleton::getActive() const return mActive; } +void Skeleton::traverse(osg::NodeVisitor& nv) +{ + if (!mActive && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) + return; + osg::Group::traverse(nv); +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index 1987fd4e8f..d4418fa272 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -53,6 +53,8 @@ namespace SceneUtil bool getActive() const; + void traverse(osg::NodeVisitor& nv); + private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. // As far as the scene graph goes we support multiple root bones. From 4eaaa5e855d8a362b1385ade296835abf26f298c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:54:56 +0200 Subject: [PATCH 0587/1812] Increment save file version and mark it as used, will be used in next commit --- apps/openmw/mwstate/statemanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 7c111a090c..3132790636 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -218,8 +218,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.setFormat (ESM::Header::CurrentFormat); + writer.setVersion(1); + // all unused - writer.setVersion(0); writer.setType(0); writer.setAuthor(""); writer.setDescription(""); From 463775060148a6b9a53676846a5ea31c4b38b423 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 03:58:23 +0200 Subject: [PATCH 0588/1812] Savegame loading optimization --- apps/openmw/mwclass/creature.cpp | 30 ++++++++++++++---------------- apps/openmw/mwclass/npc.cpp | 19 +++++++++---------- components/esm/objectstate.cpp | 2 ++ components/esm/objectstate.hpp | 4 +++- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 946f024b8c..f312a41c7a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -798,27 +798,25 @@ namespace MWClass const ESM::CreatureState& state2 = dynamic_cast (state); - ensureCustomData(ptr); - - // If we do the following instead we get a sizable speedup, but this causes compatibility issues - // with 0.30 savegames, where some state in CreatureStats was not saved yet, - // and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release. - /* - if (!ptr.getRefData().getCustomData()) + if (state.mVersion > 0) { - // Create a CustomData, but don't fill it from ESM records (not needed) - std::auto_ptr data (new CreatureCustomData); + if (!ptr.getRefData().getCustomData()) + { + // Create a CustomData, but don't fill it from ESM records (not needed) + std::auto_ptr data (new CreatureCustomData); - MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->mBase->mFlags & ESM::Creature::Weapon) - data->mContainerStore = new MWWorld::InventoryStore(); - else - data->mContainerStore = new MWWorld::ContainerStore(); + if (ref->mBase->mFlags & ESM::Creature::Weapon) + data->mContainerStore = new MWWorld::InventoryStore(); + else + data->mContainerStore = new MWWorld::ContainerStore(); - ptr.getRefData().setCustomData (data.release()); + ptr.getRefData().setCustomData (data.release()); + } } - */ + else + ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ac0d67269d..c7b407fb88 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1233,18 +1233,17 @@ namespace MWClass const ESM::NpcState& state2 = dynamic_cast (state); - ensureCustomData(ptr); - // If we do the following instead we get a sizable speedup, but this causes compatibility issues - // with 0.30 savegames, where some state in CreatureStats was not saved yet, - // and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release. - /* - if (!ptr.getRefData().getCustomData()) + if (state.mVersion > 0) { - // Create a CustomData, but don't fill it from ESM records (not needed) - std::auto_ptr data (new NpcCustomData); - ptr.getRefData().setCustomData (data.release()); + if (!ptr.getRefData().getCustomData()) + { + // Create a CustomData, but don't fill it from ESM records (not needed) + std::auto_ptr data (new NpcCustomData); + ptr.getRefData().setCustomData (data.release()); + } } - */ + else + ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 9ef1ccf80d..8d73b10c69 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,6 +6,8 @@ void ESM::ObjectState::load (ESMReader &esm) { + mVersion = esm.getVer(); + mRef.loadData(esm); mHasLocals = 0; diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index d1077733a5..674bcb8fc1 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -29,7 +29,9 @@ namespace ESM // Is there any class-specific state following the ObjectState bool mHasCustomState; - ObjectState() : mHasCustomState(true) + unsigned int mVersion; + + ObjectState() : mHasCustomState(true), mVersion(0) {} /// @note Does not load the CellRef ID, it should already be loaded before calling this method From a081d402c571c88ea69d8e6044a862f781fbf3f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:26:33 +0200 Subject: [PATCH 0589/1812] Use the format field instead of version field --- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++--- components/esm/objectstate.cpp | 2 +- components/esm/savedgame.cpp | 1 + components/esm/savedgame.hpp | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 3132790636..2c0540fbce 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -216,11 +216,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot ++iter) writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 - writer.setFormat (ESM::Header::CurrentFormat); - - writer.setVersion(1); + writer.setFormat (ESM::SavedGame::sCurrentFormat); // all unused + writer.setVersion(0); writer.setType(0); writer.setAuthor(""); writer.setDescription(""); diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 8d73b10c69..0ae690ee8a 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,7 +6,7 @@ void ESM::ObjectState::load (ESMReader &esm) { - mVersion = esm.getVer(); + mVersion = esm.getFormat(); mRef.loadData(esm); diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index b5e0810dbc..9cdb28766a 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -6,6 +6,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; +int ESM::SavedGame::sCurrentFormat = 1; void ESM::SavedGame::load (ESMReader &esm) { diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index 3e7cae775a..aa0429657b 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -15,6 +15,8 @@ namespace ESM { static unsigned int sRecordId; + static int sCurrentFormat; + struct TimeStamp { float mGameHour; From 20d03c7e39ebf9f09570be0a5a3e1029a8001bd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:26:42 +0200 Subject: [PATCH 0590/1812] Refuse loading save games of unknown format --- apps/openmw/mwstate/character.cpp | 3 --- apps/openmw/mwstate/statemanagerimp.cpp | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index f190565daf..fcd1ca19e9 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -29,9 +29,6 @@ void MWState::Character::addSlot (const boost::filesystem::path& path, const std ESM::ESMReader reader; reader.open (slot.mPath.string()); - if (reader.getFormat()>ESM::Header::CurrentFormat) - return; // format is too new -> ignore - if (reader.getRecName()!=ESM::REC_SAVE) return; // invalid save file -> ignore diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 2c0540fbce..192ad45fb1 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -325,8 +325,6 @@ void MWState::StateManager::loadGame(const std::string& filepath) // have to peek into the save file to get the player name ESM::ESMReader reader; reader.open (filepath); - if (reader.getFormat()>ESM::Header::CurrentFormat) - return; // format is too new -> ignore if (reader.getRecName()!=ESM::REC_SAVE) return; // invalid save file -> ignore reader.getRecHeader(); @@ -348,6 +346,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str ESM::ESMReader reader; reader.open (filepath); + if (reader.getFormat() > ESM::SavedGame::sCurrentFormat) + throw std::runtime_error("This save file was created using a newer version of OpenMW and is thus not supported. Please upgrade to the newest OpenMW version to load this file."); + std::map contentFileMap = buildContentFileIndexMap (reader); Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From 2065e0fa2d700163bbf9bbeb8eec5e0ccf84976a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 17:43:22 +0200 Subject: [PATCH 0591/1812] Use the correct format specifier for ess-imported savegames --- apps/essimporter/importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 65f318297b..32ad1816cf 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -327,7 +327,7 @@ namespace ESSImport ESM::ESMWriter writer; - writer.setFormat (ESM::Header::CurrentFormat); + writer.setFormat (ESM::SavedGame::sCurrentFormat); std::ofstream stream(mOutFile.c_str(), std::ios::binary); // all unused From 277113f75bac985fe7f7b0c88101bea558a5ea58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 18:05:48 +0200 Subject: [PATCH 0592/1812] Fix number of jobs in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d3b54b1797..0029863d3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j3" + build_command: "make -j2" branch_pattern: coverity_scan matrix: include: From c30936c19b2c4cb12fd5c319f7d65361f48f6fa6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 20:52:03 +0200 Subject: [PATCH 0593/1812] Reduce number of jobs in coverity script further --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0029863d3c..998d0d9d0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j2" + build_command: "make" branch_pattern: coverity_scan matrix: include: From 65ba072dcd69794ec86acb0a0987bede6862e94a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 02:09:13 +0200 Subject: [PATCH 0594/1812] Disable most targets except for OpenMW in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 998d0d9d0e..cbfc5d4890 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake ." + build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 5d2409136429cc870ab9f3c09167dc92358a8f5c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 1 Jul 2015 15:06:38 +0200 Subject: [PATCH 0595/1812] Fix build error and a pair of warnings The error was about casting between osg::Callback* and osg::NodeCallback* The warnings are both about virtual classes with non-virtual destructors --- apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/weaponanimation.hpp | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73079e9a9b..d45d19cf91 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -93,6 +93,7 @@ protected: boost::shared_ptr mTimePtr; public: + virtual ~AnimationTime() { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dc43783ff5..c7b0d3e41b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -721,12 +721,12 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; - osg::NodeCallback* callback = node.getUpdateCallback(); + osg::NodeCallback* callback = dynamic_cast(node.getUpdateCallback()); while (callback) { if ((composite = dynamic_cast(callback))) break; - callback = callback->getNestedCallback(); + callback = dynamic_cast(callback->getNestedCallback()); } if (composite) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 3bf0fb7211..fae4596115 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -19,6 +19,8 @@ namespace MWRender float mStartTime; public: WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} + virtual ~WeaponAnimationTime() { } + void setGroup(const std::string& group); void updateStartTime(); From 1afa22f443e05656c4b36e85c2e1d3eac4ca94e1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 30 Jun 2015 23:35:54 +0300 Subject: [PATCH 0596/1812] Add the RecordType column to the MetaData table --- apps/opencs/model/world/data.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index e999b46506..a92a7ad793 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -479,6 +479,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mMetaData.addColumn (new StringIdColumn (true)); mMetaData.addColumn (new RecordStateColumn); + mMetaData.addColumn (new FixedRecordTypeColumn (UniversalId::Type_MetaData)); mMetaData.addColumn (new FormatColumn); mMetaData.addColumn (new AuthorColumn); mMetaData.addColumn (new FileDescriptionColumn); From 1949fe4bf9e132e208766142400bf0d18d6762ce Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 15:47:12 +0300 Subject: [PATCH 0597/1812] Add the configuration widget for extended commands --- apps/opencs/CMakeLists.txt | 2 +- .../world/extendedcommandconfigurator.cpp | 184 ++++++++++++++++++ .../world/extendedcommandconfigurator.hpp | 68 +++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.cpp create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc042cb997..c933cbf9de 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar + dialoguespinbox recordbuttonbar extendedcommandconfigurator ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp new file mode 100644 index 0000000000..dfdb5f5738 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -0,0 +1,184 @@ +#include "extendedcommandconfigurator.hpp" + +#include +#include +#include +#include + +#include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/universalid.hpp" + +namespace +{ + QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) + { + static const QString title = "Tables affected by "; + QString titleSuffix = "Extended Delete"; + if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) + { + titleSuffix = "Extended Revert"; + } + return title + titleSuffix; + } +} + +CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent) + : QWidget(parent), + mNumUsedCheckBoxes(0), + mMode(Mode_None) +{ + mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + + mPerformButton = new QPushButton("Perform", this); + mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); + + mCancelButton = new QPushButton("Cancel", this); + mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + + mButtonLayout = new QHBoxLayout(); + mButtonLayout->setAlignment(Qt::AlignCenter); + mButtonLayout->addWidget(mPerformButton); + mButtonLayout->addWidget(mCancelButton); + + mTypeGroup = new QGroupBox(this); + + QGridLayout *groupLayout = new QGridLayout(mTypeGroup); + groupLayout->setAlignment(Qt::AlignCenter); + mTypeGroup->setLayout(groupLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mTypeGroup); + mainLayout->addLayout(mButtonLayout); +} + +CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() +{ + delete mButtonLayout; +} + +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mMode = mode; + if (mMode != Mode_None) + { + mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); + setupGroupLayout(); + } +} + +void CSVWorld::ExtendedCommandConfigurator::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + setupGroupLayout(); +} + +void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() +{ + if (mMode == Mode_None) + { + return; + } + + int groupWidth = mTypeGroup->geometry().width(); + QGridLayout *layout = qobject_cast(mTypeGroup->layout()); + + // One row of checkboxes with enough space - the setup is over + if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) + { + return; + } + + // Find the optimal number of rows to place the checkboxes within the available space + int divider = 1; + do + { + while (layout->itemAt(0) != NULL) + { + layout->removeItem(layout->itemAt(0)); + } + + int counter = 0; + int itemsPerRow = mNumUsedCheckBoxes / divider; + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isVisible()) + { + int row = counter / itemsPerRow; + int column = counter - (counter / itemsPerRow) * itemsPerRow; + layout->addWidget(current->first, row, column); + } + ++counter; + } + divider *= 2; + } + while (groupWidth < mTypeGroup->sizeHint().width()); +} + +void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) +{ + // Make sure that we have enough checkboxes + int numTypes = static_cast(types.size()); + int numCheckBoxes = static_cast(mTypeCheckBoxes.size()); + if (numTypes > numCheckBoxes) + { + for (int i = numTypes - numCheckBoxes; i > 0; --i) + { + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + } + } + + // Set up the checkboxes + int counter = 0; + CheckBoxMap::iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (counter < numTypes) + { + CSMWorld::UniversalId type = types[counter]; + current->first->setText(QString::fromUtf8(type.getTypeName().c_str())); + current->first->setChecked(true); + current->second = type; + ++counter; + } + else + { + current->first->hide(); + } + } + mNumUsedCheckBoxes = counter - 1; +} + +void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() +{ + std::vector types; + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isChecked()) + { + types.push_back(current->second); + } + } + + mCommandDispatcher->setExtendedTypes(types); + if (mMode == Mode_Delete) + { + mCommandDispatcher->executeExtendedDelete(); + } + else + { + mCommandDispatcher->executeExtendedRevert(); + } + emit done(); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp new file mode 100644 index 0000000000..2feec14a73 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -0,0 +1,68 @@ +#ifndef CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP +#define CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP + +#include + +#include + +class QPushButton; +class QGroupBox; +class QCheckBox; +class QHBoxLayout; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class CommandDispatcher; + class UniversalId; +} + +namespace CSVWorld +{ + class ExtendedCommandConfigurator : public QWidget + { + Q_OBJECT + + public: + enum Mode { Mode_None, Mode_Delete, Mode_Revert }; + + private: + typedef std::map CheckBoxMap; + + QPushButton *mPerformButton; + QPushButton *mCancelButton; + QHBoxLayout *mButtonLayout; + QGroupBox *mTypeGroup; + CheckBoxMap mTypeCheckBoxes; + int mNumUsedCheckBoxes; + + Mode mMode; + CSMWorld::CommandDispatcher *mCommandDispatcher; + + void setupGroupLayout(); + void setupCheckBoxes(const std::vector &types); + + public: + ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent = 0); + virtual ~ExtendedCommandConfigurator(); + + void configure(Mode mode); + + protected: + virtual void resizeEvent(QResizeEvent *event); + + private slots: + void performExtendedCommand(); + + signals: + void done(); + }; +} + +#endif From ba762ec1c1739bf0c86f727e8875efd7a2f3c4bf Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 17:21:47 +0300 Subject: [PATCH 0598/1812] Add the configuration widget to the bottom box --- apps/opencs/view/world/tablebottombox.cpp | 37 ++++++++++++++++++----- apps/opencs/view/world/tablebottombox.hpp | 17 +++++++++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc764..eab6b07b3e 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,11 +39,19 @@ void CSVWorld::TableBottomBox::updateStatus() } } +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mExtendedConfigurator->configure (mode); + mLayout->setCurrentWidget (mExtendedConfigurator); + mEditMode = EditMode_ExtendedConfig; + setVisible (true); +} + CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -69,11 +77,15 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto { mLayout->addWidget (mCreator); - connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone())); + connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mLayout->addWidget (mExtendedConfigurator); + connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -91,7 +103,7 @@ void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) { - setVisible (show || mCreating); + setVisible (show || (mEditMode != EditMode_None)); mShowStatusBar = show; @@ -105,7 +117,7 @@ bool CSVWorld::TableBottomBox::canCreateAndDelete() const return mCreator; } -void CSVWorld::TableBottomBox::createRequestDone() +void CSVWorld::TableBottomBox::requestDone() { if (!mShowStatusBar) setVisible (false); @@ -113,8 +125,7 @@ void CSVWorld::TableBottomBox::createRequestDone() updateStatus(); mLayout->setCurrentWidget (mStatusBar); - - mCreating = false; + mEditMode = EditMode_None; } void CSVWorld::TableBottomBox::selectionSizeChanged (int size) @@ -158,7 +169,7 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->toggleWidgets(true); mLayout->setCurrentWidget (mCreator); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } @@ -170,6 +181,16 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mLayout->setCurrentWidget(mCreator); mCreator->toggleWidgets(false); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } + +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); +} + +void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); +} diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42d..d2fb865e71 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -4,10 +4,11 @@ #include #include +#include "extendedcommandconfigurator.hpp" + class QLabel; class QStackedLayout; class QStatusBar; -class QUndoStack; namespace CSMDoc { @@ -23,12 +24,17 @@ namespace CSVWorld { Q_OBJECT + enum EditMode { EditMode_None, EditMode_Creation, EditMode_ExtendedConfig }; + bool mShowStatusBar; QLabel *mStatus; QStatusBar *mStatusBar; int mStatusCount[4]; + + EditMode mEditMode; Creator *mCreator; - bool mCreating; + ExtendedCommandConfigurator *mExtendedConfigurator; + QStackedLayout *mLayout; private: @@ -39,6 +45,8 @@ namespace CSVWorld void updateStatus(); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + public: TableBottomBox (const CreatorFactoryBase& creatorFactory, @@ -65,7 +73,7 @@ namespace CSVWorld private slots: - void createRequestDone(); + void requestDone(); ///< \note This slot being called does not imply success. public slots: @@ -80,6 +88,9 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + + void extendedDeleteConfigRequest(); + void extendedRevertConfigRequest(); }; } From 519fb9482aa36e9e07d544f16325aa9fee14dd01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 18:11:24 +0200 Subject: [PATCH 0599/1812] Minor cleanup --- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/player.hpp | 8 +------- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b00f211e1..48d69e4dee 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -28,7 +28,7 @@ namespace MWWorld { - Player::Player (const ESM::NPC *player, const MWBase::World& world) + Player::Player (const ESM::NPC *player) : mCellStore(0), mLastKnownExteriorPosition(0,0,0), mMarkedCell(NULL), diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d5376c40dc..bd5a741870 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -17,12 +17,6 @@ namespace ESM class ESMReader; } -namespace MWBase -{ - class World; - class Ptr; -} - namespace Loading { class Listener; @@ -58,7 +52,7 @@ namespace MWWorld public: - Player(const ESM::NPC *player, const MWBase::World& world); + Player(const ESM::NPC *player); void saveSkillsAttributes(); void restoreSkillsAttributes(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d8f331c625..4b14ea602a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2045,7 +2045,7 @@ namespace MWWorld { const ESM::NPC *player = mStore.get().find("player"); if (!mPlayer) - mPlayer = new MWWorld::Player(player, *this); + mPlayer = new MWWorld::Player(player); else { // Remove the old CharacterController From a1432b0255dd65999d9b148c690b793735c8111b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 19:14:28 +0200 Subject: [PATCH 0600/1812] Move attackingOrSpell flag to the CharacterController --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 3 +++ apps/openmw/mwmechanics/aicombat.cpp | 5 ++--- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++---- apps/openmw/mwmechanics/character.hpp | 5 +++++ apps/openmw/mwmechanics/creaturestats.cpp | 14 +------------- apps/openmw/mwmechanics/creaturestats.hpp | 1 - apps/openmw/mwworld/player.cpp | 13 ++++++++++++- apps/openmw/mwworld/player.hpp | 5 +++++ components/esm/creaturestats.cpp | 8 ++------ components/esm/creaturestats.hpp | 1 - 11 files changed, 41 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7ef26f703c..f472830620 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -207,7 +207,7 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue != 0); + mPlayer->setAttackingOrSpell(currentValue != 0); else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2c53c00b7c..f0b47ac7b7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1086,6 +1086,9 @@ namespace MWMechanics iter->second->getCharacterController()->setActive(inProcessingRange); + if (iter->first == player) + iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell()); + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 56dd11b996..35d1f5376b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -269,8 +269,7 @@ namespace MWMechanics attack = false; } - actorClass.getCreatureStats(actor).setAttackingOrSpell(attack); - + characterController.setAttackingOrSpell(attack); float& actionCooldown = storage.mActionCooldown; actionCooldown -= duration; @@ -476,7 +475,7 @@ namespace MWMechanics movement.mPosition[1] = 0; movement.mPosition[2] = 0; readyToAttack = false; - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + characterController.setAttackingOrSpell(false); return false; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c39b7dcef9..a3d69c059e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -654,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSecondsOfSwimming(0) , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) + , mAttackingOrSpell(false) { if(!mAnimation) return; @@ -937,7 +938,7 @@ bool CharacterController::updateCreatureState() mAnimation->disable(mCurrentWeapon); } - if(stats.getAttackingOrSpell()) + if(mAttackingOrSpell) { if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) { @@ -997,7 +998,7 @@ bool CharacterController::updateCreatureState() } } - stats.setAttackingOrSpell(false); + mAttackingOrSpell = false; } bool animPlaying = mAnimation->getInfo(mCurrentWeapon); @@ -1142,7 +1143,7 @@ bool CharacterController::updateWeaponState() float complete; bool animPlaying; - if(stats.getAttackingOrSpell()) + if(mAttackingOrSpell) { if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) { @@ -1152,7 +1153,7 @@ bool CharacterController::updateWeaponState() { // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation - stats.setAttackingOrSpell(false); + mAttackingOrSpell = false; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -2041,6 +2042,11 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +void CharacterController::setAttackingOrSpell(bool attackingOrSpell) +{ + mAttackingOrSpell = attackingOrSpell; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index be8fb2bf64..0a8771fb48 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -180,6 +180,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning std::string mAttackType; // slash, chop or thrust + + bool mAttackingOrSpell; + void determineAttackType(); void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); @@ -235,6 +238,8 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + void setAttackingOrSpell(bool attackingOrSpell); + /// @see Animation::setActive void setActive(bool active); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 5a09eb4eec..f480efc710 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -16,7 +16,7 @@ namespace MWMechanics CreatureStats::CreatureStats() : mDrawState (DrawState_Nothing), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), - mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), @@ -88,11 +88,6 @@ namespace MWMechanics return mMagicEffects; } - bool CreatureStats::getAttackingOrSpell() const - { - return mAttackingOrSpell; - } - int CreatureStats::getLevel() const { return mLevel; @@ -212,11 +207,6 @@ namespace MWMechanics mMagicEffects.setModifiers(effects); } - void CreatureStats::setAttackingOrSpell(bool attackingOrSpell) - { - mAttackingOrSpell = attackingOrSpell; - } - void CreatureStats::setAiSetting (AiSetting index, Stat value) { mAiSettings[index] = value; @@ -487,7 +477,6 @@ namespace MWMechanics state.mTalkedTo = mTalkedTo; state.mAlarmed = mAlarmed; state.mAttacked = mAttacked; - state.mAttackingOrSpell = mAttackingOrSpell; // TODO: rewrite. does this really need 3 separate bools? state.mKnockdown = mKnockdown; state.mKnockdownOneFrame = mKnockdownOneFrame; @@ -534,7 +523,6 @@ namespace MWMechanics mTalkedTo = state.mTalkedTo; mAlarmed = state.mAlarmed; mAttacked = state.mAttacked; - mAttackingOrSpell = state.mAttackingOrSpell; // TODO: rewrite. does this really need 3 separate bools? mKnockdown = state.mKnockdown; mKnockdownOneFrame = state.mKnockdownOneFrame; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 0e91cd149d..5d22da7cc3 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -40,7 +40,6 @@ namespace MWMechanics bool mTalkedTo; bool mAlarmed; bool mAttacked; - bool mAttackingOrSpell; bool mKnockdown; bool mKnockdownOneFrame; bool mKnockdownOverOneFrame; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 48d69e4dee..b17b8e1f0c 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -36,7 +36,8 @@ namespace MWWorld mForwardBackward(0), mTeleported(false), mCurrentCrimeId(-1), - mPaidCrimeId(-1) + mPaidCrimeId(-1), + mAttackingOrSpell(false) { ESM::CellRef cellRef; cellRef.blank(); @@ -216,6 +217,16 @@ namespace MWWorld mTeleported = teleported; } + void Player::setAttackingOrSpell(bool attackingOrSpell) + { + mAttackingOrSpell = attackingOrSpell; + } + + bool Player::getAttackingOrSpell() const + { + return mAttackingOrSpell; + } + bool Player::isInCombat() { return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0; } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index bd5a741870..f0ae13daa9 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -50,6 +50,8 @@ namespace MWWorld MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; + bool mAttackingOrSpell; + public: Player(const ESM::NPC *player); @@ -98,6 +100,9 @@ namespace MWWorld bool wasTeleported() const; void setTeleported(bool teleported); + void setAttackingOrSpell(bool attackingOrSpell); + bool getAttackingOrSpell() const; + ///Checks all nearby actors to see if anyone has an aipackage against you bool isInCombat(); diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index d0fe4be631..89d865c1dc 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -39,8 +39,8 @@ void ESM::CreatureStats::load (ESMReader &esm) if (esm.isNextSub("HOST")) esm.skipHSub(); // Hostile, no longer used - mAttackingOrSpell = false; - esm.getHNOT (mAttackingOrSpell, "ATCK"); + if (esm.isNextSub("ATCK")) + esm.skipHSub(); // attackingOrSpell, no longer used mKnockdown = false; esm.getHNOT (mKnockdown, "KNCK"); @@ -149,9 +149,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mAttacked) esm.writeHNT ("ATKD", mAttacked); - if (mAttackingOrSpell) - esm.writeHNT ("ATCK", mAttackingOrSpell); - if (mKnockdown) esm.writeHNT ("KNCK", mKnockdown); @@ -232,7 +229,6 @@ void ESM::CreatureStats::blank() mTalkedTo = false; mAlarmed = false; mAttacked = false; - mAttackingOrSpell = false; mKnockdown = false; mKnockdownOneFrame = false; mKnockdownOverOneFrame = false; diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 3b1d199e4b..426e890559 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -45,7 +45,6 @@ namespace ESM bool mTalkedTo; bool mAlarmed; bool mAttacked; - bool mAttackingOrSpell; bool mKnockdown; bool mKnockdownOneFrame; bool mKnockdownOverOneFrame; From 6691891beeca866d13e73e1e7cdb9982f95bf61f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 19:16:44 +0200 Subject: [PATCH 0601/1812] Include cleanup --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f472830620..09e0b638be 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,7 +1,6 @@ #include "inputmanagerimp.hpp" #include -#include #include @@ -22,7 +21,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/statemanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -31,8 +29,6 @@ #include "../mwmechanics/npcstats.hpp" -#include "../mwdialogue/dialoguemanagerimp.hpp" - using namespace ICS; namespace MWInput From fcf69555f4bf382aa808179a5fafb89df7feaaa1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:41:32 +0300 Subject: [PATCH 0602/1812] Add the user setting for enabling the configuration of extended commands --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85ba..cb001fea9b 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -215,6 +215,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "Jump to the added or cloned record."); jumpToAdded->setDefaultValue (defaultValue); jumpToAdded->setDeclaredValues (jumpValues); + + Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", + "Enable configuration of the extended delete/revert"); + extendedConfig->setDefaultValue("false"); + extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " + "the extended delete/revert command"); } declareSection ("report-input", "Report Input"); From b8772c6902ec22f80a3f1d4850db626417c1898b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:44:59 +0300 Subject: [PATCH 0603/1812] Add the ability to configure extended commands for tables --- .../world/extendedcommandconfigurator.cpp | 6 +- .../world/extendedcommandconfigurator.hpp | 2 +- apps/opencs/view/world/table.cpp | 70 +++++++++++++------ apps/opencs/view/world/table.hpp | 10 +++ apps/opencs/view/world/tablebottombox.cpp | 13 ++-- apps/opencs/view/world/tablebottombox.hpp | 7 +- apps/opencs/view/world/tablesubview.cpp | 5 ++ 7 files changed, 79 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index dfdb5f5738..6ba26634bb 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -37,7 +37,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton = new QPushButton("Cancel", this); mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); mButtonLayout = new QHBoxLayout(); mButtonLayout->setAlignment(Qt::AlignCenter); @@ -61,12 +61,14 @@ CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() delete mButtonLayout; } -void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { mMode = mode; if (mMode != Mode_None) { mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2feec14a73..dd2477444f 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -52,7 +52,7 @@ namespace CSVWorld QWidget *parent = 0); virtual ~ExtendedCommandConfigurator(); - void configure(Mode mode); + void configure(Mode mode, const std::vector &selectedIds); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba691131b0..353bd50d29 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -32,28 +32,14 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { // configure dispatcher - QModelIndexList selectedRows = selectionModel()->selectedRows(); - - std::vector records; - - int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); - - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); - ++iter) - { - int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); - - records.push_back (mModel->data ( - mModel->index (row, columnIndex)).toString().toUtf8().constData()); - } - - mDispatcher->setSelection (records); + mDispatcher->setSelection (getSelectedIds()); std::vector extendedTypes = mDispatcher->getExtendedTypes(); mDispatcher->setExtendedTypes (extendedTypes); // create context menu + QModelIndexList selectedRows = selectionModel()->selectedRows(); QMenu menu (this); /// \todo add menu items for select all and clear selection @@ -375,16 +361,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); addAction (mPreviewAction); - /// \todo add a user option, that redirects the extended action to an input panel (in - /// the bottom bar) that lets the user select which record collections should be - /// modified. - mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this); - connect (mExtendedDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedDelete())); + connect (mExtendedDeleteAction, SIGNAL (triggered()), this, SLOT (executeExtendedDelete())); addAction (mExtendedDeleteAction); mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this); - connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); + connect (mExtendedRevertAction, SIGNAL (triggered()), this, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), @@ -430,6 +412,22 @@ CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData()); } +std::vector CSVWorld::Table::getSelectedIds() const +{ + std::vector ids; + QModelIndexList selectedRows = selectionModel()->selectedRows(); + int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter != selectedRows.end(); + ++iter) + { + int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); + ids.push_back (mModel->data (mModel->index (row, columnIndex)).toString().toUtf8().constData()); + } + return ids; +} + void CSVWorld::Table::editRecord() { if (!mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) @@ -562,6 +560,34 @@ void CSVWorld::Table::previewRecord() } } +void CSVWorld::Table::executeExtendedDelete() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedDeleteConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedDelete", Qt::QueuedConnection); + } +} + +void CSVWorld::Table::executeExtendedRevert() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedRevertConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedRevert", Qt::QueuedConnection); + } +} + void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { if (name=="table-input/jump-to-added") diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 38fcd83bd6..7efc3ad346 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -93,6 +93,8 @@ namespace CSVWorld std::vector getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const; + std::vector getSelectedIds() const; + virtual std::vector getDraggedRecords() const; signals: @@ -112,6 +114,10 @@ namespace CSVWorld void closeRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + + void extendedRevertConfigRequest(const std::vector &selectedIds); + private slots: void editCell(); @@ -128,6 +134,10 @@ namespace CSVWorld void previewRecord(); + void executeExtendedDelete(); + + void executeExtendedRevert(); + public slots: void tableSizeUpdate(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eab6b07b3e..bfd56b3262 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,9 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus() } } -void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { - mExtendedConfigurator->configure (mode); + mExtendedConfigurator->configure (mode, selectedIds); mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); @@ -185,12 +186,12 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } -void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); } -void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +void CSVWorld::TableBottomBox::extendedRevertConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert, selectedIds); } diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index d2fb865e71..fded912fec 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -45,7 +45,8 @@ namespace CSVWorld void updateStatus(); - void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds); public: @@ -89,8 +90,8 @@ namespace CSVWorld void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); - void extendedDeleteConfigRequest(); - void extendedRevertConfigRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + void extendedRevertConfigRequest(const std::vector &selectedIds); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c4..abae6115ac 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -71,6 +71,11 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), + mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); + connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), + mBottom, SLOT(extendedRevertConfigRequest(const std::vector &))); } connect (mBottom, SIGNAL (requestFocus (const std::string&)), mTable, SLOT (requestFocus (const std::string&))); From dcb8fbc69ce0948dda528731f7026b872f62c583 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 03:21:39 +0200 Subject: [PATCH 0604/1812] Accurate handling of fog depth/density (Fixes #2752) --- apps/openmw/mwrender/renderingmanager.cpp | 17 ++++++++++++++--- apps/openmw/mwrender/renderingmanager.hpp | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d85c1c0065..c861119b53 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,7 +46,8 @@ namespace MWRender { public: StateUpdater() - : mFogEnd(0.f) + : mFogStart(0.f) + , mFogEnd(0.f) , mWireframe(false) { } @@ -56,7 +57,6 @@ namespace MWRender osg::LightModel* lightModel = new osg::LightModel; stateset->setAttribute(lightModel, osg::StateAttribute::ON); osg::Fog* fog = new osg::Fog; - fog->setStart(1); fog->setMode(osg::Fog::LINEAR); stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); if (mWireframe) @@ -75,6 +75,7 @@ namespace MWRender lightModel->setAmbientIntensity(mAmbientColor); osg::Fog* fog = static_cast(stateset->getAttribute(osg::StateAttribute::FOG)); fog->setColor(mFogColor); + fog->setStart(mFogStart); fog->setEnd(mFogEnd); } @@ -88,6 +89,11 @@ namespace MWRender mFogColor = col; } + void setFogStart(float start) + { + mFogStart = start; + } + void setFogEnd(float end) { mFogEnd = end; @@ -110,6 +116,7 @@ namespace MWRender private: osg::Vec4f mAmbientColor; osg::Vec4f mFogColor; + float mFogStart; float mFogEnd; bool mWireframe; }; @@ -118,6 +125,7 @@ namespace MWRender : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) + , mFogDepth(0.f) , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; @@ -338,8 +346,9 @@ namespace MWRender configureFog (cell->mAmbi.mFogDensity, color); } - void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color) { + mFogDepth = fogDepth; mFogColor = color; } @@ -364,11 +373,13 @@ namespace MWRender if (mWater->isUnderwater(cameraPos)) { setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); + mStateUpdater->setFogStart(0.f); mStateUpdater->setFogEnd(1000); } else { setFogColor(mFogColor); + mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); mStateUpdater->setFogEnd(mViewDistance); } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index fc2f5a4f38..def3ea4bba 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -190,6 +190,7 @@ namespace MWRender osg::ref_ptr mStateUpdater; + float mFogDepth; osg::Vec4f mFogColor; osg::Vec4f mAmbientColor; From bf9c62fa4224722edcc222184e66afe13f7568f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 03:42:04 +0200 Subject: [PATCH 0605/1812] Fix for some coverity scan defects --- apps/openmw/mwgui/mapwindow.hpp | 5 +++++ apps/openmw/mwrender/globalmap.hpp | 3 ++- apps/openmw/mwrender/ripplesimulation.hpp | 4 ---- apps/openmw/mwrender/sky.cpp | 9 ++++++--- components/myguiplatform/myguirendermanager.cpp | 2 ++ components/nifosg/controller.cpp | 2 ++ components/nifosg/particle.cpp | 2 +- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index bea3d33b9f..388103b5d2 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -72,6 +72,11 @@ namespace MWGui { MarkerUserData(MWRender::LocalMap* map) : mLocalMapRender(map) + , interior(false) + , cellX(0) + , cellY(0) + , nX(0.f) + , nY(0.f) { } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 7adb8218a7..91c17c06f1 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -88,7 +88,8 @@ namespace MWRender struct ImageDest { ImageDest() - : mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. + : mX(0), mY(0) + , mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame. { } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 98c8a707dc..8e591a5dbb 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -65,10 +65,6 @@ namespace MWRender osg::ref_ptr mParticleNode; std::vector mEmitters; - - float mRippleLifeTime; - float mRippleRotSpeed; - }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dc43783ff5..db7e5462e8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -162,6 +162,12 @@ protected: class CloudUpdater : public SceneUtil::StateSetUpdater { public: + CloudUpdater() + : mAnimationTimer(0.f) + , mOpacity(0.f) + { + } + void setAnimationTimer(float timer) { mAnimationTimer = timer; @@ -762,9 +768,6 @@ public: mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } - -private: - float mAlpha; }; void SkyManager::createRain() diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 773c58a596..4979d6451b 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -165,6 +165,8 @@ public: Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) + , mWriteTo(0) + , mReadFrom(0) { } diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a314910c5b..5e7e55004e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -407,6 +407,7 @@ FlipController::FlipController(int texSlot, float delta, std::vectorgetNodePath(); path.pop_back(); - osg::MatrixTransform* trans = dynamic_cast(node); + osg::MatrixTransform* trans = static_cast(node); osg::Matrix mat = osg::computeLocalToWorld( path ); mat.orthoNormalize(mat); // don't undo the scale From 631cec7304d0a87bfb980aed1577648f9a6cf65b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 17:19:07 +0200 Subject: [PATCH 0606/1812] Take the radius of lights into account when sorting --- components/sceneutil/lightmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index bcdb4af88e..039d556d11 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -244,7 +244,7 @@ namespace SceneUtil bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) { - return left->mViewBound.center().length2() < right->mViewBound.center().length2(); + return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f; } void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) From 672458577777ed9400f6668889c0dea00d2c4220 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 17:19:30 +0200 Subject: [PATCH 0607/1812] Light magic effect Notable change compared to the old (Ogre) effect: uses the ambient instead of diffuse term (Fixes #2364) --- apps/openmw/mwrender/animation.cpp | 32 ++++++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 9 ++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5955fc4cfd..91f459ff2f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -267,6 +267,8 @@ namespace MWRender Animation::~Animation() { + setLightEffect(0.f); + if (mObjectRoot) mInsert->removeChild(mObjectRoot); } @@ -1224,6 +1226,36 @@ namespace MWRender return found->second; } + void Animation::setLightEffect(float effect) + { + if (effect == 0) + { + if (mGlowLight) + { + mInsert->removeChild(mGlowLight); + mGlowLight = NULL; + } + } + else + { + if (!mGlowLight) + { + mGlowLight = new SceneUtil::LightSource; + mGlowLight->setLight(new osg::Light); + osg::Light* light = mGlowLight->getLight(); + light->setDiffuse(osg::Vec4f(0,0,0,0)); + light->setSpecular(osg::Vec4f(0,0,0,0)); + light->setAmbient(osg::Vec4f(1.5f,1.5f,1.5f,1.f)); + mInsert->addChild(mGlowLight); + } + + effect += 3; + osg::Light* light = mGlowLight->getLight(); + mGlowLight->setRadius(effect * 66.f); + light->setLinearAttenuation(0.5f/effect); + } + } + void Animation::addControllers() { mHeadController = NULL; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73079e9a9b..d23a629549 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -21,6 +21,11 @@ namespace NifOsg class KeyframeController; } +namespace SceneUtil +{ + class LightSource; +} + namespace MWRender { @@ -202,6 +207,8 @@ protected: float mHeadYawRadians; float mHeadPitchRadians; + osg::ref_ptr mGlowLight; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -377,7 +384,7 @@ public: // TODO: move outside of this class /// Makes this object glow, by placing a Light in its center. /// @param effect Controls the radius and intensity of the light. - virtual void setLightEffect(float effect) {} + virtual void setLightEffect(float effect); virtual void setHeadPitch(float pitchRadians); virtual void setHeadYaw(float yawRadians); From 12bf3694bdd5320dcc843a82b75d244e0e9ed975 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 22:05:45 +0300 Subject: [PATCH 0608/1812] Rework widget layout of ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 36 ++++++++----------- .../world/extendedcommandconfigurator.hpp | 4 +-- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 6ba26634bb..9f067545c1 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "../../model/world/commanddispatcher.hpp" @@ -39,10 +40,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mButtonLayout = new QHBoxLayout(); - mButtonLayout->setAlignment(Qt::AlignCenter); - mButtonLayout->addWidget(mPerformButton); - mButtonLayout->addWidget(mCancelButton); + mCommandTitle = new QLabel(this); + mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mTypeGroup = new QGroupBox(this); @@ -50,15 +49,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum groupLayout->setAlignment(Qt::AlignCenter); mTypeGroup->setLayout(groupLayout); - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); - mainLayout->addLayout(mButtonLayout); -} - -CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() -{ - delete mButtonLayout; + mainLayout->addWidget(mPerformButton); + mainLayout->addWidget(mCancelButton); } void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, @@ -67,7 +63,9 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; + title.append(" from:"); + mCommandTitle->setText(title); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); @@ -90,12 +88,6 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() int groupWidth = mTypeGroup->geometry().width(); QGridLayout *layout = qobject_cast(mTypeGroup->layout()); - // One row of checkboxes with enough space - the setup is over - if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) - { - return; - } - // Find the optimal number of rows to place the checkboxes within the available space int divider = 1; do @@ -111,7 +103,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); for (; current != end; ++current) { - if (current->first->isVisible()) + if (counter < mNumUsedCheckBoxes) { int row = counter / itemsPerRow; int column = counter - (counter / itemsPerRow) * itemsPerRow; @@ -121,7 +113,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() } divider *= 2; } - while (groupWidth < mTypeGroup->sizeHint().width()); + while (groupWidth < mTypeGroup->sizeHint().width() && divider <= mNumUsedCheckBoxes); } void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) @@ -133,7 +125,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); } } @@ -156,7 +148,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = counter - 1; + mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index dd2477444f..8efe36fa73 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -8,6 +8,7 @@ class QPushButton; class QGroupBox; class QCheckBox; +class QLabel; class QHBoxLayout; namespace CSMDoc @@ -35,7 +36,7 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QHBoxLayout *mButtonLayout; + QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; @@ -50,7 +51,6 @@ namespace CSVWorld ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent = 0); - virtual ~ExtendedCommandConfigurator(); void configure(Mode mode, const std::vector &selectedIds); From 520a832a9a7072b8bf306d94bc9b1d1666e615d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 22:24:23 +0200 Subject: [PATCH 0609/1812] Remove an already resolved todo comment --- apps/openmw/mwmechanics/aicombat.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 35d1f5376b..88d4167abd 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -333,9 +333,6 @@ namespace MWMechanics // Get weapon characteristics if (actorClass.hasInventoryStore(actor)) { - // TODO: Check equipped weapon and equip a different one if we can't attack with it - // (e.g. no ammunition, or wrong type of ammunition equipped, etc. autoEquip is not very smart in this regard)) - //Get weapon speed and range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); From d07b176b368ac0fd7df95c3240e27b97b6a13813 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 2 Jul 2015 22:25:19 +0200 Subject: [PATCH 0610/1812] Take into account hit recovery, knockdown and other animations for AiCombat attack timing --- apps/openmw/mwmechanics/aicombat.cpp | 10 +--------- apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwmechanics/character.hpp | 2 ++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 88d4167abd..d8b2dc9acc 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -300,10 +300,6 @@ namespace MWMechanics currentCell = actor.getCell(); } - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(actor); - if (!anim) // shouldn't happen - return false; - actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); if (actionCooldown > 0) @@ -312,11 +308,7 @@ namespace MWMechanics float rangeAttack = 0; float rangeFollow = 0; boost::shared_ptr& currentAction = storage.mCurrentAction; - // TODO: upperBodyReady() works fine for checking if we can start an attack, - // but doesn't work properly for checking if the attack is finished (as things like hit recovery or knockdown also play on the upper body) - // Only a minor problem, but can mess with the actionCooldown timer. - // To fix this the AI needs to be brought closer to the CharacterController, so we can simply check if a weapon animation is playing. - if (anim->upperBodyReady()) + if (characterController.readyToPrepareAttack()) { currentAction = prepareNextAction(actor, target); actionCooldown = currentAction->getActionCooldown(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a3d69c059e..ec1e0e81b8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2047,6 +2047,11 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell) mAttackingOrSpell = attackingOrSpell; } +bool CharacterController::readyToPrepareAttack() const +{ + return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0a8771fb48..6a5e0593df 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -240,6 +240,8 @@ public: void setAttackingOrSpell(bool attackingOrSpell); + bool readyToPrepareAttack() const; + /// @see Animation::setActive void setActive(bool active); From 82740c164501a629ec08213cad2c49b52a919b33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 02:29:42 +0200 Subject: [PATCH 0611/1812] Remove completely broken code --- apps/openmw/mwmechanics/aicombat.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index d8b2dc9acc..85a88e5465 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -640,24 +640,6 @@ namespace MWMechanics } } - // TODO: Add a parameter to vary DURATION_SAME_SPOT? - if((distToTarget > rangeAttack || followTarget) && - mObstacleCheck.check(actor, tReaction)) // check if evasive action needed - { - // probably walking into another NPC TODO: untested in combat situation - // TODO: diagonal should have same animation as walk forward - // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - if(mPathFinder.isPathConstructed()) - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); - - if(followTarget) - followTarget = false; - // FIXME: can fool actors to stay behind doors, etc. - // Related to Bug#1102 and to some degree #1155 as well - } return false; } From 2385938485a1e4638151df2d0fd52515cf9e0b41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 02:42:40 +0200 Subject: [PATCH 0612/1812] Fix a typo --- apps/opencs/model/world/columns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index d6e27caeb1..7aec68309c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -92,7 +92,7 @@ namespace CSMWorld { ColumnId_Trainer, "Trainer" }, { ColumnId_Spellmaking, "Spellmaking" }, { ColumnId_EnchantingService, "Enchanting Service" }, - { ColumnId_RepairService, "Repair Serivce" }, + { ColumnId_RepairService, "Repair Service" }, { ColumnId_ApparatusType, "Apparatus Type" }, { ColumnId_ArmorType, "Armor Type" }, { ColumnId_Health, "Health" }, From 741e5db862d23f845dd93b96605093055b31f236 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 05:37:18 +0200 Subject: [PATCH 0613/1812] Fix for non-bipedal creatures that use weapons, e.g. rieklings --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec1e0e81b8..cf963e8aa3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1789,7 +1789,8 @@ void CharacterController::update(float duration) } } - if(cls.isBipedal(mPtr)) + // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. + if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) forcestateupdate = updateWeaponState() || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; From a7bd050928b746386d5ba35425eb0d1c040a4896 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 3 Jul 2015 05:58:12 +0200 Subject: [PATCH 0614/1812] Accurate attack timings in AiCombat --- apps/openmw/mwmechanics/aicombat.cpp | 173 +++----------------------- apps/openmw/mwmechanics/character.cpp | 18 +++ apps/openmw/mwmechanics/character.hpp | 4 +- 3 files changed, 38 insertions(+), 157 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 85a88e5465..c0d2bc90d4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -31,8 +31,6 @@ namespace //chooses an attack depending on probability to avoid uniformity ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); - void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]); - osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength); @@ -83,7 +81,6 @@ namespace MWMechanics /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase { - float mTimerAttack; float mTimerReact; float mTimerCombatMove; bool mReadyToAttack; @@ -95,15 +92,12 @@ namespace MWMechanics boost::shared_ptr mCurrentAction; float mActionCooldown; float mStrength; - float mMinMaxAttackDuration[3][2]; - bool mMinMaxAttackDurationInitialised; bool mForceNoShortcut; ESM::Position mShortcutFailPos; osg::Vec3f mLastActorPos; MWMechanics::Movement mMovement; AiCombatStorage(): - mTimerAttack(0), mTimerReact(0), mTimerCombatMove(0), mReadyToAttack(false), @@ -115,7 +109,6 @@ namespace MWMechanics mCurrentAction(), mActionCooldown(0), mStrength(), - mMinMaxAttackDurationInitialised(false), mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} @@ -233,41 +226,12 @@ namespace MWMechanics { if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; } - - float attacksPeriod = 1.0f; - - ESM::Weapon::AttackType attackType; - - - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; - float& timerAttack = storage.mTimerAttack; - - bool& minMaxAttackDurationInitialised = storage.mMinMaxAttackDurationInitialised; - float (&minMaxAttackDuration)[3][2] = storage.mMinMaxAttackDuration; - - if(readyToAttack) - { - if (!minMaxAttackDurationInitialised) - { - // TODO: this must be updated when a different weapon is equipped - // TODO: it would be much easier to ask the CharacterController about the current % completion of the weapon wind-up animation - getMinMaxAttackDuration(actor, minMaxAttackDuration); - minMaxAttackDurationInitialised = true; - } - - if (timerAttack < 0) attack = false; - - timerAttack -= duration; - } - else - { - timerAttack = -attacksPeriod; + if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; - } characterController.setAttackingOrSpell(attack); @@ -372,32 +336,26 @@ namespace MWMechanics } - float& strength = storage.mStrength; + float& strength = storage.mStrength; // start new attack - if(readyToAttack) + if(readyToAttack && characterController.readyToStartAttack()) { - if(timerAttack <= -attacksPeriod) + attack = true; // attack starts just now + characterController.setAttackingOrSpell(attack); + + if (!distantCombat) + chooseBestAttack(weapon, movement); + + strength = Misc::Rng::rollClosedProbability(); + + //say a provoking combat phrase + if (actor.getClass().isNpc()) { - attack = true; // attack starts just now - - if (!distantCombat) attackType = chooseBestAttack(weapon, movement); - else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - - strength = Misc::Rng::rollClosedProbability(); - - // Note: may be 0 for some animations - timerAttack = minMaxAttackDuration[attackType][0] + - (minMaxAttackDuration[attackType][1] - minMaxAttackDuration[attackType][0]) * strength; - - //say a provoking combat phrase - if (actor.getClass().isNpc()) + const MWWorld::ESMStore &store = world->getStore(); + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) { - const MWWorld::ESMStore &store = world->getStore(); - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } } } @@ -607,39 +565,6 @@ namespace MWMechanics readyToAttack = false; } - if(!isStuck && distToTarget > rangeAttack && !distantCombat) - { - //special run attack; it shouldn't affect melee combat tactics - if(actorClass.getMovementSettings(actor).mPosition[1] == 1) - { - /* check if actor can overcome the distance = distToTarget - attackerWeapRange - less than in time of swinging with weapon (t_swing), then start attacking - */ - float speed1 = actorClass.getSpeed(actor); - float speed2 = target.getClass().getSpeed(target); - if(target.getClass().getMovementSettings(target).mPosition[0] == 0 - && target.getClass().getMovementSettings(target).mPosition[1] == 0) - speed2 = 0; - - float s1 = distToTarget - weapRange; - float t = s1/speed1; - float s2 = speed2 * t; - float t_swing = - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability(); - - if (t + s2/speed1 <= t_swing) - { - readyToAttack = true; - if(timerAttack <= -attacksPeriod) - { - timerAttack = t_swing; - attack = true; - } - } - } - } - return false; } @@ -765,70 +690,6 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: return attackType; } -void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) -{ - if (!actor.getClass().hasInventoryStore(actor)) // creatures - { - fMinMaxDurations[0][0] = fMinMaxDurations[0][1] = 0.1f; - fMinMaxDurations[1][0] = fMinMaxDurations[1][1] = 0.1f; - fMinMaxDurations[2][0] = fMinMaxDurations[2][1] = 0.1f; - - return; - } - - // get weapon information: type and speed - const ESM::Weapon *weapon = NULL; - MWMechanics::WeaponType weaptype = MWMechanics::WeapType_None; - - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(actor.getClass().getCreatureStats(actor), actor.getClass().getInventoryStore(actor), &weaptype); - - float weapSpeed; - if (weaptype != MWMechanics::WeapType_HandToHand - && weaptype != MWMechanics::WeapType_Spell - && weaptype != MWMechanics::WeapType_None) - { - weapon = weaponSlot->get()->mBase; - weapSpeed = weapon->mData.mSpeed; - } - else weapSpeed = 1.0f; - - MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(actor); - - std::string weapGroup; - MWMechanics::getWeaponGroup(weaptype, weapGroup); - weapGroup = weapGroup + ": "; - - bool bRangedWeap = (weaptype >= MWMechanics::WeapType_BowAndArrow && weaptype <= MWMechanics::WeapType_Thrown); - - const char *attackType[] = {"chop ", "slash ", "thrust ", "shoot "}; - - std::string textKey = "start"; - std::string textKey2; - - // get durations for each attack type - for (int i = 0; i < (bRangedWeap ? 1 : 3); i++) - { - float start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey); - - if (start1 < 0) - { - fMinMaxDurations[i][0] = fMinMaxDurations[i][1] = 0.1f; - continue; - } - - textKey2 = "min attack"; - float start2 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); - - fMinMaxDurations[i][0] = (start2 - start1) / weapSpeed; - - textKey2 = "max attack"; - start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); - - fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; - } -} - osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos, float duration, int weapType, float strength) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf963e8aa3..4b2ce9f4cb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1259,6 +1259,8 @@ bool CharacterController::updateWeaponState() } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + mAttackStrength = complete; } else { @@ -2053,6 +2055,22 @@ bool CharacterController::readyToPrepareAttack() const return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; } +bool CharacterController::readyToStartAttack() const +{ + if (mHitState != CharState_None) + return false; + + if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) + return mUpperBodyState == UpperCharState_WeapEquiped; + else + return mUpperBodyState == UpperCharState_Nothing; +} + +float CharacterController::getAttackStrength() const +{ + return mAttackStrength; +} + void CharacterController::setActive(bool active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6a5e0593df..b239b4a925 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,9 @@ public: void setAttackingOrSpell(bool attackingOrSpell); bool readyToPrepareAttack() const; + bool readyToStartAttack() const; + + float getAttackStrength() const; /// @see Animation::setActive void setActive(bool active); @@ -249,7 +252,6 @@ public: void setHeadTrackTarget(const MWWorld::Ptr& target); }; - void getWeaponGroup(WeaponType weaptype, std::string &group); MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); } From 382cdb8c60536a4808b08e3af294d965dfa8f71c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 3 Jul 2015 10:45:08 +0200 Subject: [PATCH 0615/1812] implemented sorting in report views (Fixes #2540) --- apps/opencs/view/tools/reporttable.cpp | 59 ++++++++++++++++++-------- apps/opencs/view/tools/reporttable.hpp | 17 +++++--- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index ca6b0dabfb..550c53969e 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../../model/tools/reportmodel.hpp" @@ -23,7 +24,7 @@ namespace CSVTools public: RichTextDelegate (QObject *parent = 0); - + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; @@ -63,7 +64,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + QString hint = mProxyModel->data (mProxyModel->index (iter->row(), 2)).toString(); if (!hint.isEmpty() && hint[0]=='R') { @@ -78,7 +79,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) if (mRefreshAction) menu.addAction (mRefreshAction); - + menu.exec (event->globalPos()); } @@ -106,14 +107,14 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) event->accept(); return; } - + switch (iter->second) { case Action_None: event->accept(); break; - + case Action_Edit: event->accept(); @@ -152,7 +153,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); - setModel (mModel); + mProxyModel = new QSortFilterProxyModel (this); + mProxyModel->setSourceModel (mModel); + + setModel (mProxyModel); setColumnHidden (2, true); mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0, @@ -162,7 +166,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, if (richTextDescription) setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this)); - + mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); @@ -182,10 +186,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); addAction (mRefreshAction); } - + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); - mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); + mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -197,7 +201,7 @@ std::vector CSVTools::ReportTable::getDraggedRecords() co for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - ids.push_back (mModel->getUniversalId (iter->row())); + ids.push_back (mModel->getUniversalId (mProxyModel->mapToSource (*iter).row())); } return ids; @@ -234,7 +238,7 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mDoubleClickActions[modifiers] = action; return; - } + } } std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const @@ -245,13 +249,22 @@ std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const { QModelIndexList selectedRows = selectionModel()->selectedRows(); + std::vector rows; + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { - QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + rows.push_back (mProxyModel->mapToSource (*iter).row()); + } + + std::sort (rows.begin(), rows.end()); + + for (std::vector::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) + { + QString hint = mModel->data (mModel->index (*iter, 2)).toString(); if (!hint.isEmpty() && hint[0]=='R') - indices.push_back (iter->row()); + indices.push_back (*iter); } } else @@ -272,25 +285,35 @@ void CSVTools::ReportTable::flagAsReplaced (int index) { mModel->flagAsReplaced (index); } - + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - emit editRequest (mModel->getUniversalId (iter->row()), mModel->getHint (iter->row())); + { + int row = mProxyModel->mapToSource (*iter).row(); + emit editRequest (mModel->getUniversalId (row), mModel->getHint (row)); + } } void CSVTools::ReportTable::removeSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); - std::reverse (selectedRows.begin(), selectedRows.end()); + std::vector rows; - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + for (QModelIndexList::iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - mModel->removeRows (iter->row(), 1); + { + rows.push_back (mProxyModel->mapToSource (*iter).row()); + } + + std::sort (rows.begin(), rows.end()); + + for (std::vector::const_reverse_iterator iter (rows.rbegin()); iter!=rows.rend(); ++iter) + mProxyModel->removeRows (*iter, 1); selectionModel()->clear(); } diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index e19b327e45..c847b2d478 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -6,6 +6,7 @@ #include "../world/dragrecordtable.hpp" class QAction; +class QSortFilterProxyModel; namespace CSMTools { @@ -30,7 +31,8 @@ namespace CSVTools Action_Remove, Action_EditAndRemove }; - + + QSortFilterProxyModel *mProxyModel; CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; @@ -63,11 +65,14 @@ namespace CSVTools void clear(); - // Return indices of rows that are suitable for replacement. - // - // \param selection Only list selected rows. + /// Return indices of rows that are suitable for replacement. + /// + /// \param selection Only list selected rows. + /// + /// \return rows in the original model std::vector getReplaceIndices (bool selection) const; + /// \param index row in the original model void flagAsReplaced (int index); private slots: @@ -78,8 +83,8 @@ namespace CSVTools public slots: - void stateChanged (int state, CSMDoc::Document *document); - + void stateChanged (int state, CSMDoc::Document *document); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 47b66b57ae52972ff514509270b1d12cd0a23beb Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 15:37:10 +0300 Subject: [PATCH 0616/1812] Create a context menu handler for dialogue editors with ID information --- apps/opencs/view/world/dialoguesubview.cpp | 69 ++++++++++++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 24 ++++++++ 2 files changed, 93 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 1d3eb53139..70a3cd37c0 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -314,6 +315,74 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() } } + +CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display) + : QObject(widget), + mWidget(widget), + mIdType(CSMWorld::TableMimeData::convertEnums(display)) +{ + Q_ASSERT(mWidget != NULL); + Q_ASSERT(CSMWorld::ColumnBase::isId(display)); + Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); + + mWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(mWidget, + SIGNAL(customContextMenuRequested(const QPoint &)), + this, + SLOT(showContextMenu(const QPoint &))); + + mEditIdAction = new QAction(this); + + QLineEdit *lineEdit = qobject_cast(mWidget); + if (lineEdit != NULL) + { + mContextMenu = lineEdit->createStandardContextMenu(); + mContextMenu->setParent(mWidget); + + QAction *action = mContextMenu->actions().first(); + mContextMenu->insertAction(action, mEditIdAction); + mContextMenu->insertSeparator(action); + } + else + { + mContextMenu = new QMenu(mWidget); + mContextMenu->addAction(mEditIdAction); + } +} + +QString CSVWorld::IdContextMenu::getWidgetValue() const +{ + static QLineEdit *lineEdit = qobject_cast(mWidget); + static QLabel *label = qobject_cast(mWidget); + + QString value = ""; + if (lineEdit != NULL) + { + value = lineEdit->text(); + } + else if (label != NULL) + { + value = label->text(); + } + return value; +} + +void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) +{ + QString value = getWidgetValue(); + if (!value.isEmpty()) + { + mEditIdAction->setText("Edit '" + value + "'"); + + QAction *selectedAction = mContextMenu->exec(mWidget->mapToGlobal(pos)); + if (selectedAction != NULL && selectedAction == mEditIdAction) + { + CSMWorld::UniversalId editId(mIdType, value.toUtf8().constData()); + emit editIdRequest(editId, ""); + } + } +} + /* =============================================================EditWidget===================================================== */ diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index be58be5ade..f33c6d9d2a 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -11,12 +11,14 @@ #include "../../model/world/columnbase.hpp" #include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/universalid.hpp" class QDataWidgetMapper; class QSize; class QEvent; class QLabel; class QVBoxLayout; +class QMenu; namespace CSMWorld { @@ -149,6 +151,28 @@ namespace CSVWorld CSMWorld::ColumnBase::Display display); }; + class IdContextMenu : public QObject + { + Q_OBJECT + + QWidget *mWidget; + CSMWorld::UniversalId::Type mIdType; + + QMenu *mContextMenu; + QAction *mEditIdAction; + + QString getWidgetValue() const; + + public: + IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); + + private slots: + void showContextMenu(const QPoint &pos); + + signals: + void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); + }; + class EditWidget : public QScrollArea { Q_OBJECT From e8e34f37dd04e25d6fa6ffe26d286a5e95dc5edf Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 16:24:08 +0300 Subject: [PATCH 0617/1812] Edit 'ID' action is available in dialogue sub-views (for LineEdits and Labels) --- apps/opencs/view/world/dialoguesubview.cpp | 33 ++++++++++++++++------ apps/opencs/view/world/dialoguesubview.hpp | 4 +++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 70a3cd37c0..da325f6c3e 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -332,6 +332,7 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di SLOT(showContextMenu(const QPoint &))); mEditIdAction = new QAction(this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editIdRequest())); QLineEdit *lineEdit = qobject_cast(mWidget); if (lineEdit != NULL) @@ -352,8 +353,8 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di QString CSVWorld::IdContextMenu::getWidgetValue() const { - static QLineEdit *lineEdit = qobject_cast(mWidget); - static QLabel *label = qobject_cast(mWidget); + QLineEdit *lineEdit = qobject_cast(mWidget); + QLabel *label = qobject_cast(mWidget); QString value = ""; if (lineEdit != NULL) @@ -373,16 +374,16 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) if (!value.isEmpty()) { mEditIdAction->setText("Edit '" + value + "'"); - - QAction *selectedAction = mContextMenu->exec(mWidget->mapToGlobal(pos)); - if (selectedAction != NULL && selectedAction == mEditIdAction) - { - CSMWorld::UniversalId editId(mIdType, value.toUtf8().constData()); - emit editIdRequest(editId, ""); - } + mContextMenu->exec(mWidget->mapToGlobal(pos)); } } +void CSVWorld::IdContextMenu::editIdRequest() +{ + CSMWorld::UniversalId editId(mIdType, getWidgetValue().toUtf8().constData()); + emit editIdRequest(editId, ""); +} + /* =============================================================EditWidget===================================================== */ @@ -557,6 +558,15 @@ void CSVWorld::EditWidget::remake(int row) editor->setEnabled(false); label->setEnabled(false); } + + if (CSMWorld::ColumnBase::isId(display)) + { + IdContextMenu *menu = new IdContextMenu(editor, display); + connect(menu, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); + } } } else @@ -676,6 +686,11 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); + + connect(mEditWidget, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(focusId(const CSMWorld::UniversalId &, const std::string &))); } void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f33c6d9d2a..f4331abb25 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -168,6 +168,7 @@ namespace CSVWorld private slots: void showContextMenu(const QPoint &pos); + void editIdRequest(); signals: void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); @@ -195,6 +196,9 @@ namespace CSVWorld virtual ~EditWidget(); void remake(int row); + + signals: + void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint); }; class SimpleDialogueSubView : public CSVDoc::SubView From 149cb9d00489bd43631f4ec14e03189487aa4498 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 16:51:47 +0300 Subject: [PATCH 0618/1812] IdContextMenu: if the ID field is empty show the standard context menu (if available) --- apps/opencs/view/world/dialoguesubview.cpp | 48 ++++++++++++++++++---- apps/opencs/view/world/dialoguesubview.hpp | 2 + 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index da325f6c3e..bfd01b14cf 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -338,16 +338,10 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di if (lineEdit != NULL) { mContextMenu = lineEdit->createStandardContextMenu(); - mContextMenu->setParent(mWidget); - - QAction *action = mContextMenu->actions().first(); - mContextMenu->insertAction(action, mEditIdAction); - mContextMenu->insertSeparator(action); } else { mContextMenu = new QMenu(mWidget); - mContextMenu->addAction(mEditIdAction); } } @@ -368,12 +362,52 @@ QString CSVWorld::IdContextMenu::getWidgetValue() const return value; } +void CSVWorld::IdContextMenu::addEditIdActionToMenu(const QString &text) +{ + mEditIdAction->setText(text); + if (mContextMenu->actions().isEmpty()) + { + mContextMenu->addAction(mEditIdAction); + } + else + { + QAction *action = mContextMenu->actions().first(); + mContextMenu->insertAction(action, mEditIdAction); + mContextMenu->insertSeparator(action); + } +} + +void CSVWorld::IdContextMenu::removeEditIdActionFromMenu() +{ + if (mContextMenu->actions().isEmpty()) + { + return; + } + + if (mContextMenu->actions().first() == mEditIdAction) + { + mContextMenu->removeAction(mEditIdAction); + if (!mContextMenu->actions().isEmpty() && mContextMenu->actions().first()->isSeparator()) + { + mContextMenu->removeAction(mContextMenu->actions().first()); + } + } +} + void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { QString value = getWidgetValue(); if (!value.isEmpty()) { - mEditIdAction->setText("Edit '" + value + "'"); + addEditIdActionToMenu("Edit '" + value + "'"); + } + else + { + removeEditIdActionFromMenu(); + } + + if (!mContextMenu->actions().isEmpty()) + { mContextMenu->exec(mWidget->mapToGlobal(pos)); } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f4331abb25..ddb6e50566 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -162,6 +162,8 @@ namespace CSVWorld QAction *mEditIdAction; QString getWidgetValue() const; + void addEditIdActionToMenu(const QString &text); + void removeEditIdActionFromMenu(); public: IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); From 61ab0ba4821a18c77ba732707f4c370b463f6e12 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 18:48:13 +0300 Subject: [PATCH 0619/1812] Prevent the Edit 'ID' action for the current ID of the dialogue subview --- apps/opencs/view/world/dialoguesubview.cpp | 13 ++++++++++++- apps/opencs/view/world/dialoguesubview.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index bfd01b14cf..505f842273 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -345,6 +345,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di } } +void CSVWorld::IdContextMenu::excludeId(const std::string &id) +{ + mExcludedIds.insert(id); +} + QString CSVWorld::IdContextMenu::getWidgetValue() const { QLineEdit *lineEdit = qobject_cast(mWidget); @@ -397,7 +402,8 @@ void CSVWorld::IdContextMenu::removeEditIdActionFromMenu() void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { QString value = getWidgetValue(); - if (!value.isEmpty()) + bool isExcludedId = mExcludedIds.find(value.toUtf8().constData()) != mExcludedIds.end(); + if (!value.isEmpty() && !isExcludedId) { addEditIdActionToMenu("Edit '" + value + "'"); } @@ -595,7 +601,12 @@ void CSVWorld::EditWidget::remake(int row) if (CSMWorld::ColumnBase::isId(display)) { + int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + QString id = mTable->data(mTable->index(row, idColumn)).toString(); + IdContextMenu *menu = new IdContextMenu(editor, display); + // Current ID is already opened, so no need to create Edit 'ID' action for it + menu->excludeId(id.toUtf8().constData()); connect(menu, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), this, diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index ddb6e50566..91be5588f4 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -1,6 +1,7 @@ #ifndef CSV_WORLD_DIALOGUESUBVIEW_H #define CSV_WORLD_DIALOGUESUBVIEW_H +#include #include #include @@ -151,12 +152,15 @@ namespace CSVWorld CSMWorld::ColumnBase::Display display); }; + /// A context menu with "Edit 'ID'" action for editors in the dialogue subview class IdContextMenu : public QObject { Q_OBJECT QWidget *mWidget; CSMWorld::UniversalId::Type mIdType; + std::set mExcludedIds; + ///< A list of IDs that should not have the Edit 'ID' action. QMenu *mContextMenu; QAction *mEditIdAction; @@ -168,6 +172,8 @@ namespace CSVWorld public: IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display); + void excludeId(const std::string &id); + private slots: void showContextMenu(const QPoint &pos); void editIdRequest(); From d73fd471c3948b1e6b3db1eefa75a7273869f9c3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 19:07:44 +0300 Subject: [PATCH 0620/1812] IdContextMenu: don't add Edit action if it's already in the context menu --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 505f842273..283cdfa58a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -374,7 +374,7 @@ void CSVWorld::IdContextMenu::addEditIdActionToMenu(const QString &text) { mContextMenu->addAction(mEditIdAction); } - else + else if (mContextMenu->actions().first() != mEditIdAction) { QAction *action = mContextMenu->actions().first(); mContextMenu->insertAction(action, mEditIdAction); From 260f6f22aecfa6722e103620ed657c33549de597 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:07:37 +0300 Subject: [PATCH 0621/1812] TableBottomBox adjusts its size according to the current widget size --- apps/opencs/view/world/tablebottombox.cpp | 22 ++++++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index bfd56b3262..eee25b1bf4 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -9,6 +9,20 @@ #include "creator.hpp" +void CSVWorld::TableBottomBox::updateSize() +{ + // Make sure that the size of the bottom box is determined by the currently visible widget + for (int i = 0; i < mLayout->count(); ++i) + { + QSizePolicy::Policy verPolicy = QSizePolicy::Ignored; + if (mLayout->widget(i) == mLayout->currentWidget()) + { + verPolicy = QSizePolicy::Expanding; + } + mLayout->widget(i)->setSizePolicy(QSizePolicy::Expanding, verPolicy); + } +} + void CSVWorld::TableBottomBox::updateStatus() { if (mShowStatusBar) @@ -61,6 +75,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mLayout = new QStackedLayout; mLayout->setContentsMargins (0, 0, 0, 0); + connect (mLayout, SIGNAL (currentChanged (int)), this, SLOT (currentWidgetChanged (int))); mStatus = new QLabel; @@ -87,6 +102,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); + + updateSize(); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -129,6 +146,11 @@ void CSVWorld::TableBottomBox::requestDone() mEditMode = EditMode_None; } +void CSVWorld::TableBottomBox::currentWidgetChanged(int /*index*/) +{ + updateSize(); +} + void CSVWorld::TableBottomBox::selectionSizeChanged (int size) { if (mStatusCount[3]!=size) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index fded912fec..15ae2924c5 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -43,6 +43,8 @@ namespace CSVWorld TableBottomBox (const TableBottomBox&); TableBottomBox& operator= (const TableBottomBox&); + void updateSize(); + void updateStatus(); void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, @@ -77,6 +79,8 @@ namespace CSVWorld void requestDone(); ///< \note This slot being called does not imply success. + void currentWidgetChanged(int index); + public slots: void selectionSizeChanged (int size); From 95d16b24c05142943b22c31162bebc1b7b46a82f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:25:56 +0300 Subject: [PATCH 0622/1812] ExtendedCommandConfigurator: disable the perform button when all tables are unchecked --- .../world/extendedcommandconfigurator.cpp | 24 +++++++++++++++++-- .../world/extendedcommandconfigurator.hpp | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 9f067545c1..257e9c4f09 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -28,6 +28,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QWidget *parent) : QWidget(parent), mNumUsedCheckBoxes(0), + mNumChecked(0), mMode(Mode_None) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -125,7 +126,9 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); + QCheckBox *checkBox = new QCheckBox(mTypeGroup); + connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int))); + mTypeCheckBoxes.insert(std::make_pair(checkBox, CSMWorld::UniversalId::Type_None)); } } @@ -148,7 +151,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = numTypes; + mNumChecked = mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() @@ -176,3 +179,20 @@ void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() } emit done(); } + +void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) +{ + switch (state) + { + case Qt::Unchecked: + --mNumChecked; + break; + case Qt::Checked: + ++mNumChecked; + break; + case Qt::PartiallyChecked: // Not used + break; + } + + mPerformButton->setEnabled(mNumChecked > 0); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 8efe36fa73..6a5e1e2e7c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -40,6 +40,7 @@ namespace CSVWorld QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; + int mNumChecked; Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; @@ -59,6 +60,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); + void checkBoxStateChanged(int state); signals: void done(); From 05cc130212162195f2f09143000f1fb49d38442f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:31:38 +0300 Subject: [PATCH 0623/1812] The configuration panel gets a focus when opening --- apps/opencs/view/world/tablebottombox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eee25b1bf4..3a7fa8e8ab 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -60,6 +60,7 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); + mExtendedConfigurator->setFocus(); } CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, From e664ef75785929d5657986bd2cacace7779c627b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:15:26 +0300 Subject: [PATCH 0624/1812] ExtendedCommandConfigurator: the perform button takes the name of the command that is executed --- .../world/extendedcommandconfigurator.cpp | 24 ++----------------- .../world/extendedcommandconfigurator.hpp | 1 - 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 257e9c4f09..36bff7d595 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -9,20 +9,6 @@ #include "../../model/world/commanddispatcher.hpp" #include "../../model/world/universalid.hpp" -namespace -{ - QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) - { - static const QString title = "Tables affected by "; - QString titleSuffix = "Extended Delete"; - if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) - { - titleSuffix = "Extended Revert"; - } - return title + titleSuffix; - } -} - CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent) @@ -33,7 +19,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); - mPerformButton = new QPushButton("Perform", this); + mPerformButton = new QPushButton(this); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); @@ -41,9 +27,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mCommandTitle = new QLabel(this); - mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); @@ -52,7 +35,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); - mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); @@ -64,9 +46,7 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; - title.append(" from:"); - mCommandTitle->setText(title); + mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 6a5e1e2e7c..9ed16aa1e4 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -36,7 +36,6 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; From ff3c9a6fb28bcddfdc73da2b0a3eaa23e8ffd0b0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:35:00 +0300 Subject: [PATCH 0625/1812] ExtendedCommandConfigurator: the perform button is now the default for the widget --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 36bff7d595..85c5a2bda6 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,6 +20,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); mPerformButton = new QPushButton(this); + mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); From 1f826476ff6fc3627c9968cc78912d3dde087b1b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 02:02:22 +0300 Subject: [PATCH 0626/1812] Fix build error --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 - apps/opencs/view/world/extendedcommandconfigurator.hpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 85c5a2bda6..d3b97b1273 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -7,7 +7,6 @@ #include #include "../../model/world/commanddispatcher.hpp" -#include "../../model/world/universalid.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 9ed16aa1e4..590cabab16 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/universalid.hpp" + class QPushButton; class QGroupBox; class QCheckBox; @@ -19,7 +21,6 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; - class UniversalId; } namespace CSVWorld From 6bcea21e144467b0e0cc2709341e66917aab49f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Jul 2015 05:19:05 +0200 Subject: [PATCH 0627/1812] Use fCombatDelayCreature, fCombatDelayNpc for random delays between aicombat attacks (Bug #1876) --- apps/openmw/mwmechanics/aicombat.cpp | 38 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c0d2bc90d4..4eeea6f1f6 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -81,6 +81,7 @@ namespace MWMechanics /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive. struct AiCombatStorage : AiTemporaryBase { + float mAttackCooldown; float mTimerReact; float mTimerCombatMove; bool mReadyToAttack; @@ -98,6 +99,7 @@ namespace MWMechanics MWMechanics::Movement mMovement; AiCombatStorage(): + mAttackCooldown(0), mTimerReact(0), mTimerCombatMove(0), mReadyToAttack(false), @@ -340,24 +342,34 @@ namespace MWMechanics // start new attack if(readyToAttack && characterController.readyToStartAttack()) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); - - if (!distantCombat) - chooseBestAttack(weapon, movement); - - strength = Misc::Rng::rollClosedProbability(); - - //say a provoking combat phrase - if (actor.getClass().isNpc()) + if (storage.mAttackCooldown <= 0) { + attack = true; // attack starts just now + characterController.setAttackingOrSpell(attack); + + if (!distantCombat) + chooseBestAttack(weapon, movement); + + strength = Misc::Rng::rollClosedProbability(); + const MWWorld::ESMStore &store = world->getStore(); - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) + + //say a provoking combat phrase + if (actor.getClass().isNpc()) { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } } + float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + if (actor.getClass().isNpc()) + baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } + else + storage.mAttackCooldown -= tReaction; } From 164994f3d33c9554022502aee976164d303df843 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 18:47:26 +1200 Subject: [PATCH 0628/1812] Made PathFinder::buildPath() private. Now all paths are built by calling PathFinder::buildSyncedPath(). Also removed useless comment. --- apps/openmw/mwmechanics/aiwander.cpp | 11 ++--------- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 41cfb9df4f..298cda961c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -410,7 +410,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); if(storage.mPathFinder.isPathConstructed()) { @@ -510,17 +510,10 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); if(storage.mPathFinder.isPathConstructed()) { - // buildPath inserts dest in case it is not a pathgraph point - // index which is a duplicate for AiWander. However below code - // does not work since getPath() returns a copy of path not a - // reference - //if(storage.mPathFinder.getPathSize() > 1) - //storage.mPathFinder.getPath().pop_back(); - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; mAllowedNodes.erase(mAllowedNodes.begin() + randNode); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 6de4db1d00..45d9dd9731 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -35,9 +35,6 @@ namespace MWMechanics void clearPath(); - void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. @@ -92,6 +89,8 @@ namespace MWMechanics } private: + void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, + const MWWorld::CellStore* cell, bool allowShortcuts = true); std::list mPath; From 46a654286b2ebc21931e0486504d7872cf2d5270 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 18:57:56 +1200 Subject: [PATCH 0629/1812] Remove fix for #1317 Expanding the AiWander distance for path grid nodes causes bigger problems than it solved. --- apps/openmw/mwmechanics/aiwander.cpp | 26 -------------------------- apps/openmw/mwmechanics/aiwander.hpp | 7 ------- 2 files changed, 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 298cda961c..6c529f925a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -719,36 +719,10 @@ namespace MWMechanics mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); } - - // In vanilla Morrowind, sometimes distance is too small to include at least two points, - // in which case, we will take the two closest points regardless of the wander distance - // This is a backup option, as std::sort is potentially O(n^2) in time. - if (mAllowedNodes.empty()) - { - // Start with list of PathGrid nodes, sorted by distance from actor - std::vector nodeDistances; - for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) - { - float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2(); - nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); - } - std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); - - // make closest node the current node - mCurrentNode = *nodeDistances[0].second; - - // give Actor a 2nd node to walk to - mAllowedNodes.push_back(*nodeDistances[1].second); - } mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } - bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right) - { - return left.first < right.first; - } - void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 13e3e571f7..75b2230942 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -120,13 +120,6 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; - - /// record distances of pathgrid point nodes to actor - /// first value is distance between actor and node, second value is PathGrid node - typedef std::pair PathDistance; - - /// used to sort array of PathDistance objects into ascending order - static bool sortByDistance(const PathDistance& left, const PathDistance& right); }; From fae93e3d8235ef4f745a75a37092cf04d46cacd5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 4 Jul 2015 19:00:27 +1200 Subject: [PATCH 0630/1812] Bugfix: was not resetting mStuckCount. --- apps/openmw/mwmechanics/aiwander.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6c529f925a..f32636b23e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -267,6 +267,7 @@ namespace MWMechanics moveNow = false; walking = false; chooseAction = true; + mStuckCount = 0; } //#endif } From 6b348451686674e48aa1140628514afc505d8b0f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 18:49:32 +0300 Subject: [PATCH 0631/1812] Create a separate class for Edit 'ID' action to use in tables' context menus --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/tableeditidaction.cpp | 42 ++++++++++++++++++++ apps/opencs/view/world/tableeditidaction.hpp | 31 +++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/tableeditidaction.cpp create mode 100644 apps/opencs/view/world/tableeditidaction.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc042cb997..4c7801d461 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar + dialoguespinbox recordbuttonbar tableeditidaction ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/tableeditidaction.cpp b/apps/opencs/view/world/tableeditidaction.cpp new file mode 100644 index 0000000000..7ce726e412 --- /dev/null +++ b/apps/opencs/view/world/tableeditidaction.cpp @@ -0,0 +1,42 @@ +#include "tableeditidaction.hpp" + +#include + +#include "../../model/world/tablemimedata.hpp" + +CSVWorld::TableEditIdAction::CellData CSVWorld::TableEditIdAction::getCellData(int row, int column) const +{ + QModelIndex index = mTable.model()->index(row, column); + if (index.isValid()) + { + QVariant display = mTable.model()->data(index, CSMWorld::ColumnBase::Role_Display); + QString value = mTable.model()->data(index).toString(); + return std::make_pair(static_cast(display.toInt()), value); + } + return std::make_pair(CSMWorld::ColumnBase::Display_None, ""); +} + +CSVWorld::TableEditIdAction::TableEditIdAction(const QTableView &table, QWidget *parent) + : QAction(parent), + mTable(table), + mCurrentId(CSMWorld::UniversalId::Type_None) +{} + +void CSVWorld::TableEditIdAction::setCell(int row, int column) +{ + CellData data = getCellData(row, column); + mCurrentId = CSMWorld::UniversalId(CSMWorld::TableMimeData::convertEnums(data.first), + data.second.toUtf8().constData()); + setText("Edit '" + data.second + "'"); +} + +CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const +{ + return mCurrentId; +} + +bool CSVWorld::TableEditIdAction::isValidIdCell(int row, int column) const +{ + CellData data = getCellData(row, column); + return CSMWorld::ColumnBase::isId(data.first) && !data.second.isEmpty(); +} diff --git a/apps/opencs/view/world/tableeditidaction.hpp b/apps/opencs/view/world/tableeditidaction.hpp new file mode 100644 index 0000000000..f2cf0b7bd0 --- /dev/null +++ b/apps/opencs/view/world/tableeditidaction.hpp @@ -0,0 +1,31 @@ +#ifndef CSVWORLD_TABLEEDITIDACTION_HPP +#define CSVWORLD_TABLEEDITIDACTION_HPP + +#include + +#include "../../model/world/columnbase.hpp" +#include "../../model/world/universalid.hpp" + +class QTableView; + +namespace CSVWorld +{ + class TableEditIdAction : public QAction + { + const QTableView &mTable; + CSMWorld::UniversalId mCurrentId; + + typedef std::pair CellData; + CellData getCellData(int row, int column) const; + + public: + TableEditIdAction(const QTableView &table, QWidget *parent = 0); + + void setCell(int row, int column); + + CSMWorld::UniversalId getCurrentId() const; + bool isValidIdCell(int row, int column) const; + }; +} + +#endif From 464e674a817e9ecb5c034953977cdeee6c6037db Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 18:51:39 +0300 Subject: [PATCH 0632/1812] Rework Table (view) code to use a TableEditIdAction --- apps/opencs/view/world/table.cpp | 43 +++++++++----------------------- apps/opencs/view/world/table.hpp | 4 +-- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba691131b0..74343a5f63 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -27,6 +27,7 @@ #include "../../model/settings/usersettings.hpp" #include "recordstatusdelegate.hpp" +#include "tableeditidaction.hpp" #include "util.hpp" void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) @@ -58,33 +59,13 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) /// \todo add menu items for select all and clear selection + int currentRow = rowAt(event->y()); + int currentColumn = columnAt(event->x()); + if (mEditIdAction->isValidIdCell(currentRow, currentColumn)) { - // Request UniversalId editing from table columns. - - int currRow = rowAt( event->y() ), - currCol = columnAt( event->x() ); - - currRow = mProxyModel->mapToSource(mProxyModel->index( currRow, 0 )).row(); - - CSMWorld::ColumnBase::Display colDisplay = - static_cast( - mModel->headerData( - currCol, - Qt::Horizontal, - CSMWorld::ColumnBase::Role_Display ).toInt()); - - QString cellData = mModel->data(mModel->index( currRow, currCol )).toString(); - CSMWorld::UniversalId::Type colType = CSMWorld::TableMimeData::convertEnums( colDisplay ); - - if ( !cellData.isEmpty() - && colType != CSMWorld::UniversalId::Type_None ) - { - mEditCellAction->setText(tr("Edit '").append(cellData).append("'")); - - menu.addAction( mEditCellAction ); - - mEditCellId = CSMWorld::UniversalId( colType, cellData.toUtf8().constData() ); - } + mEditIdAction->setCell(currentRow, currentColumn); + menu.addAction(mEditIdAction); + menu.addSeparator(); } if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) @@ -363,10 +344,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord())); addAction (mMoveDownAction); - mEditCellAction = new QAction( tr("Edit Cell"), this ); - connect( mEditCellAction, SIGNAL(triggered()), this, SLOT(editCell()) ); - addAction( mEditCellAction ); - mViewAction = new QAction (tr ("View"), this); connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord())); addAction (mViewAction); @@ -387,6 +364,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); + mEditIdAction = new TableEditIdAction (*this, this); + connect (mEditIdAction, SIGNAL (triggered()), this, SLOT (editCell())); + addAction (mEditIdAction); + connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); @@ -522,7 +503,7 @@ void CSVWorld::Table::moveDownRecord() void CSVWorld::Table::editCell() { - emit editRequest( mEditCellId, std::string() ); + emit editRequest(mEditIdAction->getCurrentId(), ""); } void CSVWorld::Table::viewRecord() diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 38fcd83bd6..adacd3a9d7 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -30,6 +30,7 @@ namespace CSMWorld namespace CSVWorld { class CommandDelegate; + class TableEditIdAction; ///< Table widget class Table : public DragRecordTable @@ -57,15 +58,14 @@ namespace CSVWorld QAction *mMoveUpAction; QAction *mMoveDownAction; QAction *mViewAction; - QAction *mEditCellAction; QAction *mPreviewAction; QAction *mExtendedDeleteAction; QAction *mExtendedRevertAction; + TableEditIdAction *mEditIdAction; CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTableBase *mModel; int mRecordStatusDisplay; CSMWorld::CommandDispatcher *mDispatcher; - CSMWorld::UniversalId mEditCellId; std::map mDoubleClickActions; bool mJumpToAddedRecord; bool mUnselectAfterJump; From 86dc5a2c6702c28b9d3a89c2655db115b4bfe92e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:27:42 +0300 Subject: [PATCH 0633/1812] Add Edit 'ID' action for nested tables --- apps/opencs/view/world/dialoguesubview.cpp | 5 ++++ apps/opencs/view/world/nestedtable.cpp | 30 ++++++++++++++++++---- apps/opencs/view/world/nestedtable.hpp | 8 ++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 283cdfa58a..4a463ecaa5 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -565,6 +565,11 @@ void CSVWorld::EditWidget::remake(int row) tablesLayout->addWidget(label); tablesLayout->addWidget(table); + + connect(table, + SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 92df59a5fc..0876b2ce78 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,15 +1,18 @@ #include "nestedtable.hpp" -#include "../../model/world/nestedtableproxymodel.hpp" -#include "../../model/world/universalid.hpp" -#include "../../model/world/commands.hpp" -#include "../../model/world/commanddispatcher.hpp" -#include "util.hpp" #include #include #include #include +#include "../../model/world/nestedtableproxymodel.hpp" +#include "../../model/world/universalid.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/commanddispatcher.hpp" + +#include "tableeditidaction.hpp" +#include "util.hpp" + CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, @@ -55,6 +58,9 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, connect(mRemoveRowAction, SIGNAL(triggered()), this, SLOT(removeRowActionTriggered())); + + mEditIdAction = new TableEditIdAction(*this, this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); } std::vector CSVWorld::NestedTable::getDraggedRecords() const @@ -69,6 +75,15 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) QMenu menu(this); + int currentRow = rowAt(event->y()); + int currentColumn = columnAt(event->x()); + if (mEditIdAction->isValidIdCell(currentRow, currentColumn)) + { + mEditIdAction->setCell(currentRow, currentColumn); + menu.addAction(mEditIdAction); + menu.addSeparator(); + } + if (selectionModel()->selectedRows().size() == 1) menu.addAction(mRemoveRowAction); @@ -92,3 +107,8 @@ void CSVWorld::NestedTable::addNewRowActionTriggered() selectionModel()->selectedRows().size(), mModel->getParentColumn())); } + +void CSVWorld::NestedTable::editCell() +{ + emit editRequest(mEditIdAction->getCurrentId(), ""); +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 1129204011..ba8b6c0e32 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -22,12 +22,15 @@ namespace CSMDoc namespace CSVWorld { + class TableEditIdAction; + class NestedTable : public DragRecordTable { Q_OBJECT QAction *mAddNewRowAction; QAction *mRemoveRowAction; + TableEditIdAction *mEditIdAction; CSMWorld::NestedTableProxyModel* mModel; CSMWorld::CommandDispatcher *mDispatcher; @@ -46,6 +49,11 @@ namespace CSVWorld void removeRowActionTriggered(); void addNewRowActionTriggered(); + + void editCell(); + + signals: + void editRequest(const CSMWorld::UniversalId &id, const std::string &hint); }; } From 30fd711a4799310dcdfd031c863c956d27b8f9ce Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:39:53 +0300 Subject: [PATCH 0634/1812] TableEditIdAction: prevent creation of a UniversalId with Type_None --- apps/opencs/view/world/tableeditidaction.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/tableeditidaction.cpp b/apps/opencs/view/world/tableeditidaction.cpp index 7ce726e412..4dfc537cc8 100644 --- a/apps/opencs/view/world/tableeditidaction.cpp +++ b/apps/opencs/view/world/tableeditidaction.cpp @@ -25,9 +25,13 @@ CSVWorld::TableEditIdAction::TableEditIdAction(const QTableView &table, QWidget void CSVWorld::TableEditIdAction::setCell(int row, int column) { CellData data = getCellData(row, column); - mCurrentId = CSMWorld::UniversalId(CSMWorld::TableMimeData::convertEnums(data.first), - data.second.toUtf8().constData()); - setText("Edit '" + data.second + "'"); + CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first); + + if (idType != CSMWorld::UniversalId::Type_None) + { + mCurrentId = CSMWorld::UniversalId(idType, data.second.toUtf8().constData()); + setText("Edit '" + data.second + "'"); + } } CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const @@ -38,5 +42,8 @@ CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const bool CSVWorld::TableEditIdAction::isValidIdCell(int row, int column) const { CellData data = getCellData(row, column); - return CSMWorld::ColumnBase::isId(data.first) && !data.second.isEmpty(); + CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first); + return CSMWorld::ColumnBase::isId(data.first) && + idType != CSMWorld::UniversalId::Type_None && + !data.second.isEmpty(); } From c1b06538dc26cc915276f154d087abc1c1549b9e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 19:55:48 +0300 Subject: [PATCH 0635/1812] Add Edit 'ID' action for nested fields --- apps/opencs/view/world/dialoguesubview.cpp | 38 ++++++++++++++-------- apps/opencs/view/world/dialoguesubview.hpp | 3 ++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4a463ecaa5..ed50b81cd7 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -428,6 +428,28 @@ void CSVWorld::IdContextMenu::editIdRequest() =============================================================EditWidget===================================================== */ +void CSVWorld::EditWidget::createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, + int currentRow) const +{ + Q_ASSERT(editor != NULL); + + if (CSMWorld::ColumnBase::isId(display) && + CSMWorld::TableMimeData::convertEnums(display) != CSMWorld::UniversalId::Type_None) + { + int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + QString id = mTable->data(mTable->index(currentRow, idColumn)).toString(); + + IdContextMenu *menu = new IdContextMenu(editor, display); + // Current ID is already opened, so no need to create Edit 'ID' action for it + menu->excludeId(id.toUtf8().constData()); + connect(menu, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), + this, + SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); + } +} + CSVWorld::EditWidget::~EditWidget() { for (unsigned i = 0; i < mNestedModels.size(); ++i) @@ -604,19 +626,7 @@ void CSVWorld::EditWidget::remake(int row) label->setEnabled(false); } - if (CSMWorld::ColumnBase::isId(display)) - { - int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id); - QString id = mTable->data(mTable->index(row, idColumn)).toString(); - - IdContextMenu *menu = new IdContextMenu(editor, display); - // Current ID is already opened, so no need to create Edit 'ID' action for it - menu->excludeId(id.toUtf8().constData()); - connect(menu, - SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), - this, - SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); - } + createEditorContextMenu(editor, display, row); } } else @@ -668,6 +678,8 @@ void CSVWorld::EditWidget::remake(int row) editor->setEnabled(false); label->setEnabled(false); } + + createEditorContextMenu(editor, display, row); } } mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i))); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 91be5588f4..d82936e459 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,6 +195,9 @@ namespace CSVWorld CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + void createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, + int currentRow) const; public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, From 880bc31ddf0bb287aff8252e9b04eb17d26236b4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:30:02 +0300 Subject: [PATCH 0636/1812] TableBottomBox: Creator/Configurator can be closed via Escape --- apps/opencs/view/world/tablebottombox.cpp | 18 ++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 3a7fa8e8ab..d02b76fdcd 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "creator.hpp" @@ -92,6 +94,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto if (mCreator) { + mCreator->installEventFilter(this); mLayout->addWidget (mCreator); connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); @@ -101,6 +104,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto } mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mExtendedConfigurator->installEventFilter(this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); @@ -118,6 +122,20 @@ CSVWorld::TableBottomBox::~TableBottomBox() delete mCreator; } +bool CSVWorld::TableBottomBox::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) + { + requestDone(); + return true; + } + } + return QWidget::eventFilter(object, event); +} + void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 15ae2924c5..a24844890b 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -59,6 +59,8 @@ namespace CSVWorld virtual ~TableBottomBox(); + virtual bool eventFilter(QObject *object, QEvent *event); + void setEditLock (bool locked); void setStatusBar (bool show); From 4fbd24206b49e4dd981caaae47d3f39b62edeb97 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:47:10 +0300 Subject: [PATCH 0637/1812] ExtendedCommandConfigurator: layout changes --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d3b97b1273..b9b2fa10c6 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -30,11 +30,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); - groupLayout->setAlignment(Qt::AlignCenter); + groupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mTypeGroup->setLayout(groupLayout); QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); From c90841d64952cc245c1e8f10d7e61fbef78d01b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Jul 2015 21:00:01 +0200 Subject: [PATCH 0638/1812] Fix head tracking for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index becfd8f6ea..6252d392bf 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -850,7 +850,6 @@ void NpcAnimation::addControllers() Animation::addControllers(); mFirstPersonNeckController = NULL; - mHeadController = NULL; WeaponAnimation::deleteControllers(); if (mViewMode == VM_FirstPerson) From 9a02a85a244fc5738dd12de0307256ff81285c47 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:07:14 +1200 Subject: [PATCH 0639/1812] Pulled duplicate code into function. --- apps/openmw/mwmechanics/aiwander.cpp | 24 +++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 3 +++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f32636b23e..3c69a2f5eb 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -498,14 +498,8 @@ namespace MWMechanics { assert(mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - // NOTE: initially constructed with local (i.e. cell) co-ordinates - // convert dest to use world co-ordinates ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - if (currentCell->getCell()->isExterior()) - { - dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, currentCell->getCell()); // actor position is already in world co-ordinates ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); @@ -537,6 +531,15 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) + { + if (cell->isExterior()) + { + point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; + point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + void AiWander::trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder) { @@ -643,12 +646,7 @@ namespace MWMechanics // apply a slight offset to prevent overcrowding dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); - - if (actor.getCell()->isExterior()) - { - dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 75b2230942..d69a72585f 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,9 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + /// convert point from local (i.e. cell) to world co-ordinates + void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From f942db2b2761483b9e262fbdfd50302f9c2903b5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:08:09 +1200 Subject: [PATCH 0640/1812] Simplified code. --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3c69a2f5eb..1567f48f6f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -682,19 +682,14 @@ namespace MWMechanics // ... pathgrids don't usually include water, so swimmers ignore them if (mDistance && !actor.getClass().isPureWaterCreature(actor)) { - float cellXOffset = 0; - float cellYOffset = 0; + // get NPC's position in local (i.e. cell) co-ordinates + osg::Vec3f npcPos(mInitialActorPosition); if(cell->isExterior()) { - cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); + npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } - // convert npcPos to local (i.e. cell) co-ordinates - osg::Vec3f npcPos(mInitialActorPosition); - npcPos[0] = npcPos[0] - cellXOffset; - npcPos[1] = npcPos[1] - cellYOffset; - // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) From 0095737c407e9513cea0b294338ce84807be8704 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:09:14 +1200 Subject: [PATCH 0641/1812] Use correct type of variable. Remove unnecessary casts. --- apps/openmw/mwmechanics/pathgrid.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 4e9bc89048..66af864ea1 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -313,27 +313,27 @@ namespace MWMechanics return path; // for some reason couldn't build a path // reconstruct path to return, using world co-ordinates - float xCell = 0; - float yCell = 0; + int xCell = 0; + int yCell = 0; if (mIsExterior) { - xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); + xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; + yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); return path; } From 76f20b8b2024ca59ba0349f9c9988c4abafa81fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:10:02 +1200 Subject: [PATCH 0642/1812] fix 'WIN32_LEAN_AND_MEAN' macro redefinition warning. --- apps/openmw/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index dc58daed9a..85a0dbe55d 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -14,7 +14,9 @@ #if defined(_WIN32) // For OutputDebugString +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include // makes __argc and __argv available on windows #include From eb2aa965b9fece4dbae0b414e0a737a8ca6e43f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:17:18 +1200 Subject: [PATCH 0643/1812] Extracted function SetCurrentNodeToClosestAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 33 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1567f48f6f..6f2c6969c3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,5 +1,7 @@ #include "aiwander.hpp" +#include + #include #include @@ -700,23 +702,30 @@ namespace MWMechanics } if(!mAllowedNodes.empty()) { - osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0])); - float closestNode = (npcPos - firstNodePos).length2(); - unsigned int index = 0; - for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) - { - osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); - float tempDist = (npcPos - nodePos).length2(); - if(tempDist < closestNode) - index = counterThree; - } - mCurrentNode = mAllowedNodes[index]; - mAllowedNodes.erase(mAllowedNodes.begin() + index); + SetCurrentNodeToClosestAllowedNode(npcPos); } mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) + { + float distanceToClosestNode = FLT_MAX; + unsigned int index = 0; + for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) + { + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); + float tempDist = (npcPos - nodePos).length2(); + if (tempDist < distanceToClosestNode) + { + index = counterThree; + distanceToClosestNode = tempDist; + } + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d69a72585f..94758afc8d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -121,6 +121,8 @@ namespace MWMechanics /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From 1239667cb415835d2d4cb6f3aba941c92e4fecaa Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:21:35 +1200 Subject: [PATCH 0644/1812] AiWander uses points between PathGrid points (Fixes #1317) When there is only on PathGrid point within a NPC's wander distance, expand possible wander destinations by using positions between PathGrid points. --- apps/openmw/mwmechanics/aiwander.cpp | 44 ++++++++++++++++++++++++- apps/openmw/mwmechanics/aiwander.hpp | 4 +++ apps/openmw/mwmechanics/pathfinding.hpp | 4 ++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6f2c6969c3..25ed4694b9 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { stopWalking(actor, storage); moveNow = false; @@ -694,11 +694,19 @@ namespace MWMechanics // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates + int pointIndex = 0; for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); if((npcPos - nodePos).length2() <= mDistance * mDistance) + { mAllowedNodes.push_back(pathgrid->mPoints[counter]); + pointIndex = counter; + } + } + if (mAllowedNodes.size() == 1) + { + AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex); } if(!mAllowedNodes.empty()) { @@ -708,6 +716,40 @@ namespace MWMechanics } } + // When only one path grid point in wander distance, + // additional points for NPC to wander to are: + // 1. NPC's initial location + // 2. Partway along the path between the point and its connected points. + void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex) + { + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos)); + for (std::vector::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it) + { + if (it->mV0 == pointIndex) + { + AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]); + } + } + } + + void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end) + { + osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start); + osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart; + float length = delta.length(); + delta.normalize(); + + // destination must be far enough away that NPC will need to move to get there. + const int threshold = PathFinder::PathTolerance * 2; + int distance = std::max(mDistance / 2, threshold); + + // must not travel more than 1/2 way between waypoints, + // otherwise, NPC goes to far endpoint then comes back. Looks weird. + distance = std::min(distance, static_cast(length / 2)); + delta *= distance; + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); + } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { float distanceToClosestNode = FLT_MAX; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 94758afc8d..18f98cfd51 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -123,6 +123,10 @@ namespace MWMechanics void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex); + + void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 45d9dd9731..a4886a8400 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -19,6 +19,8 @@ namespace MWMechanics public: PathFinder(); + static const int PathTolerance = 32; + static float sgn(float val) { if(val > 0) @@ -35,7 +37,7 @@ namespace MWMechanics void clearPath(); - bool checkPathCompleted(float x, float y, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. /// In degrees From 3ffa0aa1858c6b5ab9c1cb871a09fbc4d1601336 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 15:36:41 +0300 Subject: [PATCH 0645/1812] Count of nested columns can be retrieved for a collection with no records --- apps/opencs/model/world/nestedidcollection.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 792a13b7db..56b1123659 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -161,8 +161,19 @@ namespace CSMWorld template int NestedIdCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getColumnsCount( - Collection::getRecord(row)); + const ColumnBase &nestedColumn = Collection::getColumn(column); + int numRecords = Collection::getSize(); + if (row >= 0 && row < numRecords) + { + const Record& record = Collection::getRecord(row); + return getAdapter(nestedColumn).getColumnsCount(record); + } + else + { + // If the row is invalid (or there no records), retrieve the column count using a blank record + const Record record; + return getAdapter(nestedColumn).getColumnsCount(record); + } } template From 531bca1273e7b9dbd98b34a5f3747a3099467d71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 5 Jul 2015 18:09:13 +0200 Subject: [PATCH 0646/1812] Add a threshold for changing aicombat targets (Fixes #2755) --- apps/openmw/mwmechanics/aisequence.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 3e1f896245..fb6450d16a 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -184,6 +184,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac const ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (targetPos.asVec3() - vActorPos).length(); + + // Small threshold for changing target + if (it == mPackages.begin()) + distTo = std::max(0.f, distTo - 50.f); + if (distTo < nearestDist) { nearestDist = distTo; From ceb3dea55cc70d3518d1253b00ff45ecc21ffc5f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 20:11:21 +0300 Subject: [PATCH 0647/1812] Rewording of the user setting for extended configuration --- apps/opencs/model/settings/usersettings.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index cb001fea9b..05b06d5626 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,10 +217,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", - "Enable configuration of the extended delete/revert"); + "Manually specify affected record types for an extended delete/revert"); extendedConfig->setDefaultValue("false"); - extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " - "the extended delete/revert command"); + extendedConfig->setToolTip("Delete and revert commands have an extended form that also affects " + "associated records.\n\n" + "If this option is enabled, types of affected records are selected " + "manually before a command execution.\nOtherwise, all associated " + "records are deleted/reverted immediately."); } declareSection ("report-input", "Report Input"); From 3c6bc7406219e1fec46fe79fa9fde76a7dc999c5 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:10:37 +0300 Subject: [PATCH 0648/1812] Close the extended configurator when all respective records were removed outside --- .../world/extendedcommandconfigurator.cpp | 40 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 ++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index b9b2fa10c6..d243ff2562 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -1,12 +1,17 @@ #include "extendedcommandconfigurator.hpp" +#include + #include #include #include #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/data.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, @@ -14,10 +19,13 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum : QWidget(parent), mNumUsedCheckBoxes(0), mNumChecked(0), - mMode(Mode_None) + mMode(Mode_None), + mData(document.getData()) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + connect(&mData, SIGNAL(idListChanged()), this, SLOT(dataIdListChanged())); + mPerformButton = new QPushButton(this); mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -48,7 +56,8 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC if (mMode != Mode_None) { mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); - mCommandDispatcher->setSelection(selectedIds); + mSelectedIds = selectedIds; + mCommandDispatcher->setSelection(mSelectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } @@ -177,3 +186,30 @@ void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) mPerformButton->setEnabled(mNumChecked > 0); } + +void CSVWorld::ExtendedCommandConfigurator::dataIdListChanged() +{ + bool idsRemoved = false; + for (int i = 0; i < static_cast(mSelectedIds.size()); ++i) + { + if (!mData.hasId(mSelectedIds[i])) + { + std::swap(mSelectedIds[i], mSelectedIds.back()); + mSelectedIds.pop_back(); + idsRemoved = true; + --i; + } + } + + // If all selected IDs were removed, cancel the configurator + if (mSelectedIds.empty()) + { + emit done(); + return; + } + + if (idsRemoved) + { + mCommandDispatcher->setSelection(mSelectedIds); + } +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 590cabab16..2e06e9c9c9 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -21,6 +21,7 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; + class Data; } namespace CSVWorld @@ -44,6 +45,8 @@ namespace CSVWorld Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; + CSMWorld::Data &mData; + std::vector mSelectedIds; void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); @@ -61,6 +64,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); void checkBoxStateChanged(int state); + void dataIdListChanged(); signals: void done(); From 47d21ff4b34c1192746ba7533d6c0815e7afc194 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:49:48 +0300 Subject: [PATCH 0649/1812] Add edit locking to ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 26 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 +++ apps/opencs/view/world/tablebottombox.cpp | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d243ff2562..2cf6222a6e 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,7 +20,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mNumUsedCheckBoxes(0), mNumChecked(0), mMode(Mode_None), - mData(document.getData()) + mData(document.getData()), + mEditLock(false) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -58,8 +59,19 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mSelectedIds = selectedIds; mCommandDispatcher->setSelection(mSelectedIds); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); + lockWidgets(mEditLock); + } +} + +void CSVWorld::ExtendedCommandConfigurator::setEditLock(bool locked) +{ + if (mEditLock != locked) + { + mEditLock = locked; + lockWidgets(mEditLock); } } @@ -144,6 +156,18 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorsetEnabled(!mEditLock && mNumChecked > 0); + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (int i = 0; current != end && i < mNumUsedCheckBoxes; ++current, ++i) + { + current->first->setEnabled(!mEditLock); + } +} + void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() { std::vector types; diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2e06e9c9c9..641b4a5241 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -48,8 +48,11 @@ namespace CSVWorld CSMWorld::Data &mData; std::vector mSelectedIds; + bool mEditLock; + void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); + void lockWidgets(bool locked); public: ExtendedCommandConfigurator(CSMDoc::Document &document, @@ -57,6 +60,7 @@ namespace CSVWorld QWidget *parent = 0); void configure(Mode mode, const std::vector &selectedIds); + void setEditLock(bool locked); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index d02b76fdcd..225ff32a49 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -115,6 +115,7 @@ void CSVWorld::TableBottomBox::setEditLock (bool locked) { if (mCreator) mCreator->setEditLock (locked); + mExtendedConfigurator->setEditLock (locked); } CSVWorld::TableBottomBox::~TableBottomBox() From aaaee74a4db0cc3ba1c5760b91efff1066d99b4f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 5 Jul 2015 21:44:17 +0200 Subject: [PATCH 0650/1812] Fix the comments --- apps/openmw/mwrender/animation.hpp | 1 - apps/openmw/mwrender/sky.cpp | 9 +++++++-- apps/openmw/mwrender/weaponanimation.hpp | 2 -- components/sceneutil/controller.hpp | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d45d19cf91..73079e9a9b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -93,7 +93,6 @@ protected: boost::shared_ptr mTimePtr; public: - virtual ~AnimationTime() { } void setTimePtr(boost::shared_ptr time) { mTimePtr = time; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c7b0d3e41b..d9a2128897 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -721,12 +722,16 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; - osg::NodeCallback* callback = dynamic_cast(node.getUpdateCallback()); +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + osg::Callback* callback = node.getUpdateCallback(); +#else + osg::NodeCallback* callback = node.getUpdateCallback(); +#endif while (callback) { if ((composite = dynamic_cast(callback))) break; - callback = dynamic_cast(callback->getNestedCallback()); + callback = callback->getNestedCallback(); } if (composite) diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index fae4596115..3bf0fb7211 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -19,8 +19,6 @@ namespace MWRender float mStartTime; public: WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} - virtual ~WeaponAnimationTime() { } - void setGroup(const std::string& group); void updateStartTime(); diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 0ef1356e77..7399ecad58 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -11,6 +11,7 @@ namespace SceneUtil class ControllerSource { public: + virtual ~ControllerSource() { } virtual float getValue(osg::NodeVisitor* nv) = 0; }; From 13f289d1a513735bd3bd13b865f02f3a3b912b56 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 6 Jul 2015 16:35:45 +0200 Subject: [PATCH 0651/1812] Fix calculation of selected blocks in ScriptEdit --- apps/opencs/view/world/scriptedit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index ad2cddbf84..25f4fd0777 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -276,11 +276,11 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event) if(textCursor().hasSelection()) { QString str = textCursor().selection().toPlainText(); - int selectedLines = str.count("\n")+1; + int offset = str.count("\n"); if(textCursor().position() < textCursor().anchor()) - endBlock += selectedLines; + endBlock += offset; else - startBlock -= selectedLines; + startBlock -= offset; } painter.setBackgroundMode(Qt::OpaqueMode); QFont font = painter.font(); From 3655ef16af864b7c50c003e2c8905f06b7bb15cf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 19:16:32 +0200 Subject: [PATCH 0652/1812] Explicitly instantiate ESM::StatState --- apps/essimporter/convertplayer.cpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/quickkeysmenu.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++ apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/creaturestats.cpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 1 + apps/openmw/mwmechanics/stat.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 1 + apps/openmw/mwworld/projectilemanager.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 3 ++ components/esm/creaturestats.cpp | 2 + components/esm/statstate.cpp | 52 +++++++++++++++++++ components/esm/statstate.hpp | 48 ++--------------- 16 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 components/esm/statstate.cpp diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index af0119a460..5718201f74 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -1,5 +1,7 @@ #include "convertplayer.hpp" +#include + namespace ESSImport { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 139862a5a2..042267ebeb 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 3ecfc64b2b..52ff2ee10e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3e855c4d03..442fbeb081 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 01d0a339b9..8c919e8bd5 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 515265bd92..9cf9575227 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -22,6 +22,9 @@ #include +#include +#include + #include #include diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f0b47ac7b7..5f8b706519 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -4,6 +4,8 @@ #include +#include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index f480efc710..48374c173c 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7bc6a34ae8..fef99dc616 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -6,6 +6,7 @@ #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 64cc665206..0820d20152 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H +#include #include #include diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4e6c6f116b..b33a6f8db8 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index f083bcb4aa..6295ed159c 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602a..ff82160d16 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,9 @@ #include #include +#include +#include + #include #include diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 89d865c1dc..9bdbf96685 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -1,4 +1,6 @@ #include "creaturestats.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" void ESM::CreatureStats::load (ESMReader &esm) { diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp new file mode 100644 index 0000000000..e95295cc9e --- /dev/null +++ b/components/esm/statstate.cpp @@ -0,0 +1,52 @@ +#include "statstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + template + StatState::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {} + + template + void StatState::load(ESMReader &esm) + { + esm.getHNT(mBase, "STBA"); + + mMod = 0; + esm.getHNOT(mMod, "STMO"); + mCurrent = 0; + esm.getHNOT(mCurrent, "STCU"); + + // mDamage was changed to a float; ensure backwards compatibility + T oldDamage = 0; + esm.getHNOT(oldDamage, "STDA"); + mDamage = static_cast(oldDamage); + + esm.getHNOT(mDamage, "STDF"); + + mProgress = 0; + esm.getHNOT(mProgress, "STPR"); + } + + template + void StatState::save(ESMWriter &esm) const + { + esm.writeHNT("STBA", mBase); + + if (mMod != 0) + esm.writeHNT("STMO", mMod); + + if (mCurrent) + esm.writeHNT("STCU", mCurrent); + + if (mDamage) + esm.writeHNT("STDF", mDamage); + + if (mProgress) + esm.writeHNT("STPR", mProgress); + } + + template class StatState; + template class StatState; +} diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index f57ba9f30e..47aeb0331d 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -1,11 +1,11 @@ #ifndef OPENMW_ESM_STATSTATE_H #define OPENMW_ESM_STATSTATE_H -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { + class ESMReader; + class ESMWriter; + // format 0, saved games only template @@ -23,48 +23,6 @@ namespace ESM void load (ESMReader &esm); void save (ESMWriter &esm) const; }; - - template - StatState::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {} - - template - void StatState::load (ESMReader &esm) - { - esm.getHNT (mBase, "STBA"); - - mMod = 0; - esm.getHNOT (mMod, "STMO"); - mCurrent = 0; - esm.getHNOT (mCurrent, "STCU"); - - // mDamage was changed to a float; ensure backwards compatibility - T oldDamage = 0; - esm.getHNOT(oldDamage, "STDA"); - mDamage = static_cast(oldDamage); - - esm.getHNOT (mDamage, "STDF"); - - mProgress = 0; - esm.getHNOT (mProgress, "STPR"); - } - - template - void StatState::save (ESMWriter &esm) const - { - esm.writeHNT ("STBA", mBase); - - if (mMod != 0) - esm.writeHNT ("STMO", mMod); - - if (mCurrent) - esm.writeHNT ("STCU", mCurrent); - - if (mDamage) - esm.writeHNT ("STDF", mDamage); - - if (mProgress) - esm.writeHNT ("STPR", mProgress); - } } #endif From 52cf8541f5d02677a893bfda0542267df1249568 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 18:41:03 +1200 Subject: [PATCH 0653/1812] End point tolerance restored to 64 units. Corrected problem pointed out by Scrawl. Destination needs tolerance of 64 to avoid overcrowding. --- apps/openmw/mwmechanics/aiwander.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 8 ++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 25ed4694b9..31687edf2a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) { stopWalking(actor, storage); moveNow = false; @@ -645,9 +645,8 @@ namespace MWMechanics int index = Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; - // apply a slight offset to prevent overcrowding - dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); - dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); + dest.mX += OffsetToPreventOvercrowding(); + dest.mY += OffsetToPreventOvercrowding(); ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), @@ -658,6 +657,11 @@ namespace MWMechanics mStoredAvailableNodes = false; } + int AiWander::OffsetToPreventOvercrowding() + { + return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + } + void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) { if (!mStoredInitialActorPosition) @@ -739,13 +743,10 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - // destination must be far enough away that NPC will need to move to get there. - const int threshold = PathFinder::PathTolerance * 2; - int distance = std::max(mDistance / 2, threshold); + int distance = std::max(mDistance / 2, MinimumWanderDistance); - // must not travel more than 1/2 way between waypoints, - // otherwise, NPC goes to far endpoint then comes back. Looks weird. - distance = std::min(distance, static_cast(length / 2)); + // must not travel longer than distance between waypoints or NPC goes past waypoint + distance = std::min(distance, static_cast(length)); delta *= distance; mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 18f98cfd51..c15ec7c3cd 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,12 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + // to prevent overcrowding + static const int DestinationTolerance = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MinimumWanderDistance = DestinationTolerance * 2; + /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); @@ -129,6 +135,8 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + static int OffsetToPreventOvercrowding(); }; From f1774ee7c37b89ad03508fa040b482d0662aee6b Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 19:34:33 +1200 Subject: [PATCH 0654/1812] Fixed compile failing on OSX and Linux. --- apps/openmw/mwmechanics/aiwander.cpp | 12 +++++++++--- apps/openmw/mwmechanics/aiwander.hpp | 6 ------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 31687edf2a..4aef8f8ba4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -30,6 +30,12 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + // to prevent overcrowding + static const int DESTINATION_TOLERANCE = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = { std::string("idle2"), @@ -216,7 +222,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); moveNow = false; @@ -659,7 +665,7 @@ namespace MWMechanics int AiWander::OffsetToPreventOvercrowding() { - return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + return static_cast(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) @@ -743,7 +749,7 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - int distance = std::max(mDistance / 2, MinimumWanderDistance); + int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE); // must not travel longer than distance between waypoints or NPC goes past waypoint distance = std::min(distance, static_cast(length)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c15ec7c3cd..926017b46a 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,12 +118,6 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; - // to prevent overcrowding - static const int DestinationTolerance = 64; - - // distance must be long enough that NPC will need to move to get there. - static const int MinimumWanderDistance = DestinationTolerance * 2; - /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); From b1cc74dd9a6b05d6bbe728b7601afd0cda972c62 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 14:41:37 +0200 Subject: [PATCH 0655/1812] Explicity instantiate MWMechanics::Stat --- apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/stat.cpp | 294 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/stat.hpp | 213 ++++--------------- apps/openmw/mwworld/worldimp.cpp | 1 + 5 files changed, 320 insertions(+), 191 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 52ff2ee10e..392a4a84ae 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,6 +16,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5f8b706519..d9a8ce72ff 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 1b909d579c..6eb5e0246d 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -1,28 +1,276 @@ - #include "stat.hpp" -void MWMechanics::AttributeValue::writeState (ESM::StatState& state) const +#include + +namespace MWMechanics { - state.mBase = mBase; - state.mMod = mModifier; - state.mDamage = mDamage; + template + Stat::Stat() : mBase (0), mModified (0) {} + template + Stat::Stat(T base) : mBase (base), mModified (base) {} + template + Stat::Stat(T base, T modified) : mBase (base), mModified (modified) {} + + template + const T& Stat::getBase() const + { + return mBase; + } + + template + T Stat::getModified() const + { + return std::max(static_cast(0), mModified); + } + template + T Stat::getModifier() const + { + return mModified-mBase; + } + template + void Stat::set (const T& value) + { + mBase = mModified = value; + } + template + void Stat::modify(const T& diff) + { + mBase += diff; + if(mBase >= static_cast(0)) + mModified += diff; + else + { + mModified += diff - mBase; + mBase = static_cast(0); + } + } + template + void Stat::setBase (const T& value) + { + T diff = value - mBase; + mBase = value; + mModified += diff; + } + template + void Stat::setModified (T value, const T& min, const T& max) + { + T diff = value - mModified; + + if (mBase+diffmax) + { + value = max + (mModified - mBase); + diff = value - mModified; + } + + mModified = value; + mBase += diff; + } + template + void Stat::setModifier (const T& modifier) + { + mModified = mBase + modifier; + } + + template + void Stat::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModified; + } + template + void Stat::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModified = state.mMod; + } + + + template + DynamicStat::DynamicStat() : mStatic (0), mCurrent (0) {} + template + DynamicStat::DynamicStat(T base) : mStatic (base), mCurrent (base) {} + template + DynamicStat::DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} + template + DynamicStat::DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} + + + template + const T& DynamicStat::getBase() const + { + return mStatic.getBase(); + } + template + T DynamicStat::getModified() const + { + return mStatic.getModified(); + } + template + const T& DynamicStat::getCurrent() const + { + return mCurrent; + } + + template + void DynamicStat::set (const T& value) + { + mStatic.set (value); + mCurrent = value; + } + template + void DynamicStat::setBase (const T& value) + { + mStatic.setBase (value); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::setModified (T value, const T& min, const T& max) + { + mStatic.setModified (value, min, max); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::modify (const T& diff, bool allowCurrentDecreaseBelowZero) + { + mStatic.modify (diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + template + void DynamicStat::setCurrent (const T& value, bool allowDecreaseBelowZero) + { + if (value > mCurrent) + { + // increase + mCurrent = value; + + if (mCurrent > getModified()) + mCurrent = getModified(); + } + else if (value > 0 || allowDecreaseBelowZero) + { + // allowed decrease + mCurrent = value; + } + else if (mCurrent > 0) + { + // capped decrease + mCurrent = 0; + } + } + template + void DynamicStat::setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero) + { + T diff = modifier - mStatic.getModifier(); + mStatic.setModifier (modifier); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + + template + void DynamicStat::writeState (ESM::StatState& state) const + { + mStatic.writeState (state); + state.mCurrent = mCurrent; + } + template + void DynamicStat::readState (const ESM::StatState& state) + { + mStatic.readState (state); + mCurrent = state.mCurrent; + } + + AttributeValue::AttributeValue() : + mBase(0), mModifier(0), mDamage(0) + { + } + + int AttributeValue::getModified() const + { + return std::max(0, mBase - (int) mDamage + mModifier); + } + int AttributeValue::getBase() const + { + return mBase; + } + int AttributeValue::getModifier() const + { + return mModifier; + } + + void AttributeValue::setBase(int base) + { + mBase = std::max(0, base); + } + + void AttributeValue::setModifier(int mod) + { + mModifier = mod; + } + + void AttributeValue::damage(float damage) + { + mDamage += std::min(damage, (float)getModified()); + } + void AttributeValue::restore(float amount) + { + mDamage -= std::min(mDamage, amount); + } + + float AttributeValue::getDamage() const + { + return mDamage; + } + + void AttributeValue::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModifier; + state.mDamage = mDamage; + } + + void AttributeValue::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModifier = state.mMod; + mDamage = state.mDamage; + } + + SkillValue::SkillValue() : + mProgress(0) + { + } + + float SkillValue::getProgress() const + { + return mProgress; + } + void SkillValue::setProgress(float progress) + { + mProgress = progress; + } + + void SkillValue::writeState (ESM::StatState& state) const + { + AttributeValue::writeState (state); + state.mProgress = mProgress; + } + + void SkillValue::readState (const ESM::StatState& state) + { + AttributeValue::readState (state); + mProgress = state.mProgress; + } } -void MWMechanics::AttributeValue::readState (const ESM::StatState& state) -{ - mBase = state.mBase; - mModifier = state.mMod; - mDamage = state.mDamage; -} - -void MWMechanics::SkillValue::writeState (ESM::StatState& state) const -{ - AttributeValue::writeState (state); - state.mProgress = mProgress; -} - -void MWMechanics::SkillValue::readState (const ESM::StatState& state) -{ - AttributeValue::readState (state); - mProgress = state.mProgress; -} +template class MWMechanics::Stat; +template class MWMechanics::Stat; +template class MWMechanics::DynamicStat; +template class MWMechanics::DynamicStat; diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 0820d20152..c075f5fa7b 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -4,7 +4,11 @@ #include #include -#include +namespace ESM +{ + template + struct StatState; +} namespace MWMechanics { @@ -17,87 +21,28 @@ namespace MWMechanics public: typedef T Type; - Stat() : mBase (0), mModified (0) {} - Stat(T base) : mBase (base), mModified (base) {} - Stat(T base, T modified) : mBase (base), mModified (modified) {} + Stat(); + Stat(T base); + Stat(T base, T modified); - const T& getBase() const - { - return mBase; - } + const T& getBase() const; - T getModified() const - { - return std::max(static_cast(0), mModified); - } - - T getModifier() const - { - return mModified-mBase; - } + T getModified() const; + T getModifier() const; /// Set base and modified to \a value. - void set (const T& value) - { - mBase = mModified = value; - } - - void modify(const T& diff) - { - mBase += diff; - if(mBase >= static_cast(0)) - mModified += diff; - else - { - mModified += diff - mBase; - mBase = static_cast(0); - } - } + void set (const T& value); + void modify(const T& diff); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - T diff = value - mBase; - mBase = value; - mModified += diff; - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - T diff = value - mModified; + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); + void setModifier (const T& modifier); - if (mBase+diffmax) - { - value = max + (mModified - mBase); - diff = value - mModified; - } - - mModified = value; - mBase += diff; - } - - void setModifier (const T& modifier) - { - mModified = mBase + modifier; - } - - void writeState (ESM::StatState& state) const - { - state.mBase = mBase; - state.mMod = mModified; - } - - void readState (const ESM::StatState& state) - { - mBase = state.mBase; - mModified = state.mMod; - } + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -122,98 +67,32 @@ namespace MWMechanics public: typedef T Type; - DynamicStat() : mStatic (0), mCurrent (0) {} - DynamicStat(T base) : mStatic (base), mCurrent (base) {} - DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} - DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} + DynamicStat(); + DynamicStat(T base); + DynamicStat(T base, T modified, T current); + DynamicStat(const Stat &stat, T current); - const T& getBase() const - { - return mStatic.getBase(); - } - - T getModified() const - { - return mStatic.getModified(); - } - - const T& getCurrent() const - { - return mCurrent; - } + const T& getBase() const; + T getModified() const; + const T& getCurrent() const; /// Set base, modified and current to \a value. - void set (const T& value) - { - mStatic.set (value); - mCurrent = value; - } + void set (const T& value); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - mStatic.setBase (value); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - mStatic.setModified (value, min, max); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); /// Change modified relatively. - void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) - { - mStatic.modify (diff); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false); - void setCurrent (const T& value, bool allowDecreaseBelowZero = false) - { - if (value > mCurrent) - { - // increase - mCurrent = value; + void setCurrent (const T& value, bool allowDecreaseBelowZero = false); + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false); - if (mCurrent > getModified()) - mCurrent = getModified(); - } - else if (value > 0 || allowDecreaseBelowZero) - { - // allowed decrease - mCurrent = value; - } - else if (mCurrent > 0) - { - // capped decrease - mCurrent = 0; - } - } - - void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) - { - T diff = modifier - mStatic.getModifier(); - mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } - - void writeState (ESM::StatState& state) const - { - mStatic.writeState (state); - state.mCurrent = mCurrent; - } - - void readState (const ESM::StatState& state) - { - mStatic.readState (state); - mCurrent = state.mCurrent; - } + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -237,26 +116,25 @@ namespace MWMechanics float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue(); - int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } - int getBase() const { return mBase; } - int getModifier() const { return mModifier; } + int getModified() const; + int getBase() const; + int getModifier() const; - void setBase(int base) { mBase = std::max(0, base); } + void setBase(int base); - void setModifier(int mod) { mModifier = mod; } + void setModifier(int mod); // Maximum attribute damage is limited to the modified value. // Note: I think MW applies damage directly to mModified, since you can also // "restore" drained attributes. We need to rewrite the magic effect system to support this. - void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } - void restore(float amount) { mDamage -= std::min(mDamage, amount); } + void damage(float damage); + void restore(float amount); - float getDamage() const { return mDamage; } + float getDamage() const; void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; @@ -264,12 +142,11 @@ namespace MWMechanics { float mProgress; public: - SkillValue() : mProgress(0) {} - float getProgress() const { return mProgress; } - void setProgress(float progress) { mProgress = progress; } + SkillValue(); + float getProgress() const; + void setProgress(float progress); void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ff82160d16..3b57e22c5d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From b3b55a584265b8a7e0a7453ddc3448277633d276 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 19:22:04 +0200 Subject: [PATCH 0656/1812] Explicitly instantiate MWWorld::Store --- apps/openmw/mwmechanics/spells.cpp | 1 + apps/openmw/mwscript/globalscripts.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/cells.cpp | 1 + apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/esmstore.hpp | 1 + apps/openmw/mwworld/inventorystore.cpp | 1 + apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/store.cpp | 1199 ++++++++++++++++++++--- apps/openmw/mwworld/store.hpp | 934 +++--------------- apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/worldimp.hpp | 5 + 12 files changed, 1215 insertions(+), 933 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e3646d8294..fe0f892db1 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index a6ad2cc11a..44d96e949c 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 192ad45fb1..ac8dc863a1 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2aa817fa50..b096301fd6 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5d9beecb65..dea468d22b 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace MWWorld { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 05b6339566..a14f6368e4 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWWORLD_ESMSTORE_H #define OPENMW_MWWORLD_ESMSTORE_H +#include #include #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3fe86a511a..6c283bb3ea 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db26b4f2a4..8029cb7733 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cdcc00b4d3..96c7118964 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -2,126 +2,1105 @@ #include "esmstore.hpp" #include +#include -namespace MWWorld { +#include +#include -void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) +#include +#include + +namespace { - //Handling MovedCellRefs, there is no way to do it inside loadcell - while (esm.isNextSub("MVRF")) { - ESM::CellRef ref; - ESM::MovedCellRef cMRef; - cell->getNextMVRF(esm, cMRef); - - ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - - // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following - // implementation when the oher implementation works as well. - bool deleted = false; - cell->getNextRef(esm, ref, deleted); - - // Add data required to make reference appear in the correct cell. - // We should not need to test for duplicates, as this part of the code is pre-cell merge. - cell->mMovedRefs.push_back(cMRef); - // But there may be duplicates here! - if (!deleted) - { - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; - } - } -} - -void Store::load(ESM::ESMReader &esm, const std::string &id) -{ - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded at least partially! - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell cell; - cell.mName = id; - - // Load the (x,y) coordinates of the cell, if it is an exterior cell, - // so we can find the cell we need to merge with - cell.loadData(esm); - - if(cell.mData.mFlags & ESM::Cell::Interior) + template + class GetRecords { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // merge new cell into old cell - // push the new references on the list of references to manage (saveContext = true) - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) - oldcell->loadCell(esm, true); - } else + const std::string mFind; + std::vector *mRecords; + + public: + GetRecords(const std::string &str, std::vector *records) + : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) + { } + + void operator()(const T *item) { - // spawn a new cell - cell.loadCell(esm, true); - - mInt[idLower] = cell; + if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) + mRecords->push_back(item); } - } - else + }; + + struct Compare { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); - if (oldcell) { - // merge new cell into old cell - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; - oldcell->loadCell(esm, false); - - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - - // push the new references on the list of references to manage - oldcell->postLoad(esm); - - // merge lists of leased references, use newer data in case of conflict - for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { - // remove reference from current leased ref tracker and add it to new cell - ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); - if (itold != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = *itold; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); - wipecell->mLeasedRefs.erase(it_lease); - *itold = *it; - } - else - oldcell->mMovedRefs.push_back(*it); + bool operator()(const ESM::Land *x, const ESM::Land *y) { + if (x->mX == y->mX) { + return x->mY < y->mY; } - - // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a - // reference to this cell, so the list for the new cell should be empty. The list for oldcell, - // however, could have leased refs in it and so should be kept. - } else - { - // spawn a new cell - cell.loadCell(esm, false); - - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - - // push the new references on the list of references to manage - cell.postLoad(esm); - - mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + return x->mX < y->mX; } + }; +} + +namespace MWWorld +{ + template + IndexedStore::IndexedStore() + { + } + template + typename IndexedStore::iterator IndexedStore::begin() const + { + return mStatic.begin(); + } + template + typename IndexedStore::iterator IndexedStore::end() const + { + return mStatic.end(); + } + template + void IndexedStore::load(ESM::ESMReader &esm) + { + T record; + record.load(esm); + + // Try to overwrite existing record + std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); + if (!ret.second) + ret.first->second = record; + } + template + int IndexedStore::getSize() const + { + return mStatic.size(); + } + template + void IndexedStore::setUp() + { + } + template + const T *IndexedStore::search(int index) const + { + typename Static::const_iterator it = mStatic.find(index); + if (it != mStatic.end()) + return &(it->second); + return NULL; + } + template + const T *IndexedStore::find(int index) const + { + const T *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + // Need to instantiate these before they're used + template class IndexedStore; + template class IndexedStore; + + template + Store::Store() + { + } + + template + Store::Store(const Store& orig) + : mStatic(orig.mStatic) + { + } + + template + void Store::clearDynamic() + { + // remove the dynamic part of mShared + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + mDynamic.clear(); + } + + template + const T *Store::search(const std::string &id) const + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename Dynamic::const_iterator dit = mDynamic.find(item.mId); + if (dit != mDynamic.end()) { + return &dit->second; + } + + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + return &(it->second); + } + + return 0; + } + template + bool Store::isDynamic(const std::string &id) const + { + typename Dynamic::const_iterator dit = mDynamic.find(id); + return (dit != mDynamic.end()); + } + template + const T *Store::searchRandom(const std::string &id) const + { + std::vector results; + std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); + if(!results.empty()) + return results[Misc::Rng::rollDice(results.size())]; + return NULL; + } + template + const T *Store::find(const std::string &id) const + { + const T *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + template + const T *Store::findRandom(const std::string &id) const + { + const T *ptr = searchRandom(id); + if(ptr == 0) + { + std::ostringstream msg; + msg << T::getRecordType() << " starting with '"< + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); + } + template + void Store::setUp() + { + } + + template + typename Store::iterator Store::begin() const + { + return mShared.begin(); + } + template + typename Store::iterator Store::end() const + { + return mShared.end(); + } + + template + size_t Store::getSize() const + { + return mShared.size(); + } + + template + int Store::getDynamicSize() const + { + return mDynamic.size(); + } + template + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + getSize()); + typename std::vector::const_iterator it = mShared.begin(); + for (; it != mShared.end(); ++it) { + list.push_back((*it)->mId); + } + } + template + T *Store::insert(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mDynamic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + T *Store::insertStatic(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mStatic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + bool Store::eraseStatic(const std::string &id) + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename std::map::iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + typename std::vector::iterator end = sharedIter + mStatic.size(); + + while (sharedIter != mShared.end() && sharedIter != end) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); + break; + } + ++sharedIter; + } + mStatic.erase(it); + } + + return true; + } + + template + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + typename Dynamic::iterator it = mDynamic.find(key); + if (it == mDynamic.end()) { + return false; + } + mDynamic.erase(it); + + // have to reinit the whole shared part + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { + mShared.push_back(&it->second); + } + return true; + } + template + bool Store::erase(const T &item) + { + return erase(item.mId); + } + template + void Store::write (ESM::ESMWriter& writer, Loading::Listener& progress) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + writer.writeHNString ("NAME", iter->second.mId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + template + void Store::read(ESM::ESMReader& reader, const std::string& id) + { + T record; + record.mId = id; + record.load (reader); + insert (record); + } + + + // LandTexture + //========================================================================= + Store::Store() + { + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); + } + const ESM::LandTexture *Store::search(size_t index, size_t plugin) const + { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); + } + const ESM::LandTexture *Store::find(size_t index, size_t plugin) const + { + const ESM::LandTexture *ptr = search(index, plugin); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land texture with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + size_t Store::getSize() const + { + return mStatic.size(); + } + size_t Store::getSize(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } + void Store::load(ESM::ESMReader &esm, const std::string &id, size_t plugin) + { + ESM::LandTexture lt; + lt.load(esm); + lt.mId = id; + + // Make sure we have room for the structure + if (plugin >= mStatic.size()) { + mStatic.resize(plugin+1); + } + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + load(esm, id, esm.getIndex()); + } + Store::iterator Store::begin(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + Store::iterator Store::end(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); + } + + + // Land + //========================================================================= + Store::~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return iterator(mStatic.begin()); + } + Store::iterator Store::end() const + { + return iterator(mStatic.end()); + } + ESM::Land *Store::search(int x, int y) const + { + ESM::Land land; + land.mX = x, land.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); + + if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { + return const_cast(*it); + } + return 0; + } + ESM::Land *Store::find(int x, int y) const + { + ESM::Land *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Land *ptr = new ESM::Land(); + ptr->load(esm); + + // Same area defined in multiple plugins? -> last plugin wins + // Can't use search() because we aren't sorted yet - is there any other way to speed this up? + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) + { + delete *it; + mStatic.erase(it); + break; + } + } + + mStatic.push_back(ptr); + } + void Store::setUp() + { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + + + // Cell + //========================================================================= + + const ESM::Cell *Store::search(const ESM::Cell &cell) const + { + if (cell.isExterior()) { + return search(cell.getGridX(), cell.getGridY()); + } + return search(cell.mName); + } + void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) + { + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + bool deleted = false; + cell->getNextRef(esm, ref, deleted); + + // Add data required to make reference appear in the correct cell. + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + if (!deleted) + { + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; + } + } + } + const ESM::Cell *Store::search(const std::string &id) const + { + ESM::Cell cell; + cell.mName = Misc::StringUtils::lowerCase(id); + + std::map::const_iterator it = mInt.find(cell.mName); + + if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { + return &(it->second); + } + + DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); + if (dit != mDynamicInt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::search(int x, int y) const + { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::searchOrCreate(int x, int y) + { + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + ESM::Cell newCell; + newCell.mData.mX = x; + newCell.mData.mY = y; + newCell.mData.mFlags = ESM::Cell::HasWater; + newCell.mAmbi.mAmbient = 0; + newCell.mAmbi.mSunlight = 0; + newCell.mAmbi.mFog = 0; + newCell.mAmbi.mFogDensity = 0; + return &mExt.insert(std::make_pair(key, newCell)).first->second; + } + const ESM::Cell *Store::find(const std::string &id) const + { + const ESM::Cell *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << "Interior cell '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + const ESM::Cell *Store::find(int x, int y) const + { + const ESM::Cell *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Exterior at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + typedef DynamicExt::iterator ExtIterator; + typedef std::map::iterator IntIterator; + + mSharedInt.clear(); + mSharedInt.reserve(mInt.size()); + for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(it->second)); + } + + mSharedExt.clear(); + mSharedExt.reserve(mExt.size()); + for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(it->second)); + } + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded at least partially! + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell cell; + cell.mName = id; + + // Load the (x,y) coordinates of the cell, if it is an exterior cell, + // so we can find the cell we need to merge with + cell.loadData(esm); + + if(cell.mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // merge new cell into old cell + // push the new references on the list of references to manage (saveContext = true) + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) + oldcell->loadCell(esm, true); + } else + { + // spawn a new cell + cell.loadCell(esm, true); + + mInt[idLower] = cell; + } + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); + if (oldcell) { + // merge new cell into old cell + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; + oldcell->loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + oldcell->postLoad(esm); + + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { + // remove reference from current leased ref tracker and add it to new cell + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + else + oldcell->mMovedRefs.push_back(*it); + } + + // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a + // reference to this cell, so the list for the new cell should be empty. The list for oldcell, + // however, could have leased refs in it and so should be kept. + } else + { + // spawn a new cell + cell.loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + cell.postLoad(esm); + + mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + } + } + } + Store::iterator Store::intBegin() const + { + return iterator(mSharedInt.begin()); + } + Store::iterator Store::intEnd() const + { + return iterator(mSharedInt.end()); + } + Store::iterator Store::extBegin() const + { + return iterator(mSharedExt.begin()); + } + Store::iterator Store::extEnd() const + { + return iterator(mSharedExt.end()); + } + const ESM::Cell *Store::searchExtByName(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mName, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } + } + } + return cell; + } + const ESM::Cell *Store::searchExtByRegion(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } + } + } + return cell; + } + size_t Store::getSize() const + { + return mSharedInt.size() + mSharedExt.size(); + } + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + mSharedInt.size()); + + std::vector::const_iterator it = mSharedInt.begin(); + for (; it != mSharedInt.end(); ++it) { + list.push_back((*it)->mName); + } + } + ESM::Cell *Store::insert(const ESM::Cell &cell) + { + if (search(cell) != 0) { + std::ostringstream msg; + msg << "Failed to create "; + msg << ((cell.isExterior()) ? "exterior" : "interior"); + msg << " cell"; + + throw std::runtime_error(msg.str()); + } + ESM::Cell *ptr; + if (cell.isExterior()) { + std::pair key(cell.getGridX(), cell.getGridY()); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicExt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedExt.push_back(ptr); + } else { + std::string key = Misc::StringUtils::lowerCase(cell.mName); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicInt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedInt.push_back(ptr); + } + return ptr; + } + bool Store::erase(const ESM::Cell &cell) + { + if (cell.isExterior()) { + return erase(cell.getGridX(), cell.getGridY()); + } + return erase(cell.mName); + } + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + DynamicInt::iterator it = mDynamicInt.find(key); + + if (it == mDynamicInt.end()) { + return false; + } + mDynamicInt.erase(it); + mSharedInt.erase( + mSharedInt.begin() + mSharedInt.size(), + mSharedInt.end() + ); + + for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { + mSharedInt.push_back(&it->second); + } + + return true; + } + bool Store::erase(int x, int y) + { + std::pair key(x, y); + DynamicExt::iterator it = mDynamicExt.find(key); + + if (it == mDynamicExt.end()) { + return false; + } + mDynamicExt.erase(it); + mSharedExt.erase( + mSharedExt.begin() + mSharedExt.size(), + mSharedExt.end() + ); + + for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { + mSharedExt.push_back(&it->second); + } + + return true; + } + + + // Pathgrid + //========================================================================= + + Store::Store() + : mCells(NULL) + { + } + + void Store::setCells(Store& cells) + { + mCells = &cells; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Pathgrid pathgrid; + pathgrid.load(esm); + + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. + // A proper fix should be made for future versions of the file format. + bool interior = mCells->search(pathgrid.mCell) != NULL; + + // Try to overwrite existing record + if (interior) + { + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + else + { + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + } + size_t Store::getSize() const + { + return mInt.size() + mExt.size(); + } + void Store::setUp() + { + } + const ESM::Pathgrid *Store::search(int x, int y) const + { + Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); + if (it != mExt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::search(const std::string& name) const + { + Interior::const_iterator it = mInt.find(name); + if (it != mInt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::find(int x, int y) const + { + const ESM::Pathgrid* pathgrid = search(x,y); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << x << " " << y << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid* Store::find(const std::string& name) const + { + const ESM::Pathgrid* pathgrid = search(name); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid *Store::search(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return search(cell.mData.mX, cell.mData.mY); + else + return search(cell.mName); + } + const ESM::Pathgrid *Store::find(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return find(cell.mData.mX, cell.mData.mY); + else + return find(cell.mName); + } + + + // Skill + //========================================================================= + + Store::Store() + { + } + + + // Magic effect + //========================================================================= + + Store::Store() + { + } + + + // Attribute + //========================================================================= + + Store::Store() + { + mStatic.reserve(ESM::Attribute::Length); + } + const ESM::Attribute *Store::search(size_t index) const + { + if (index >= mStatic.size()) { + return 0; + } + return &mStatic.at(index); + } + + const ESM::Attribute *Store::find(size_t index) const + { + const ESM::Attribute *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Attribute with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + for (int i = 0; i < ESM::Attribute::Length; ++i) { + mStatic.push_back( + ESM::Attribute( + ESM::Attribute::sAttributeIds[i], + ESM::Attribute::sGmstAttributeIds[i], + ESM::Attribute::sGmstAttributeDescIds[i] + ) + ); + } + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return mStatic.begin(); + } + Store::iterator Store::end() const + { + return mStatic.end(); + } + + + // Dialogue + //========================================================================= + + + template<> + inline void Store::setUp() + { + // DialInfos marked as deleted are kept during the loading phase, so that the linked list + // structure is kept intact for inserting further INFOs. Delete them now that loading is done. + for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + ESM::Dialogue& dial = it->second; + dial.clearDeletedInfos(); + } + + mShared.clear(); + mShared.reserve(mStatic.size()); + std::map::iterator it = mStatic.begin(); + for (; it != mStatic.end(); ++it) { + mShared.push_back(&(it->second)); + } + } + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed + } + + it->second.load(esm); + } + + + // Script + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + ESM::Script scpt; + scpt.load(esm); + Misc::StringUtils::toLower(scpt.mId); + + std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = scpt; + } + + + // StartScript + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; } } -void Store::load(ESM::ESMReader &esm, const std::string &id) -{ - load(esm, id, esm.getIndex()); -} +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; -} diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2d73d5312e..02fb983cda 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -4,17 +4,19 @@ #include #include #include -#include -#include - -#include - -#include - -#include #include "recordcmp.hpp" +namespace ESM +{ + struct Land; +} + +namespace Loading +{ + class Listener; +} + namespace MWWorld { struct StoreBase @@ -37,6 +39,30 @@ namespace MWWorld ///< Read into dynamic storage }; + template + class IndexedStore + { + protected: + typedef typename std::map Static; + Static mStatic; + + public: + typedef typename std::map::const_iterator iterator; + + IndexedStore(); + + iterator begin() const; + iterator end() const; + + void load(ESM::ESMReader &esm); + + int getSize() const; + void setUp(); + + const T *search(int index) const; + const T *find(int index) const; + }; + template class SharedIterator { @@ -110,275 +136,54 @@ namespace MWWorld typedef std::map Dynamic; typedef std::map Static; - class GetRecords { - const std::string mFind; - std::vector *mRecords; - - public: - GetRecords(const std::string &str, std::vector *records) - : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) - { } - - void operator()(const T *item) - { - if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) - mRecords->push_back(item); - } - }; - - friend class ESMStore; public: - Store() - {} - - Store(const Store &orig) - : mStatic(orig.mData) - {} + Store(); + Store(const Store &orig); typedef SharedIterator iterator; // setUp needs to be called again after - virtual void clearDynamic() - { - // remove the dynamic part of mShared - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - mDynamic.clear(); - } + virtual void clearDynamic(); + void setUp(); - const T *search(const std::string &id) const { - T item; - item.mId = Misc::StringUtils::lowerCase(id); - - typename Dynamic::const_iterator dit = mDynamic.find(item.mId); - if (dit != mDynamic.end()) { - return &dit->second; - } - - typename std::map::const_iterator it = mStatic.find(item.mId); - - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - return &(it->second); - } - - return 0; - } + const T *search(const std::string &id) const; /** * Does the record with this ID come from the dynamic store? */ - bool isDynamic(const std::string &id) const { - typename Dynamic::const_iterator dit = mDynamic.find(id); - return (dit != mDynamic.end()); - } + bool isDynamic(const std::string &id) const; /** Returns a random record that starts with the named ID, or NULL if not found. */ - const T *searchRandom(const std::string &id) const - { - std::vector results; - std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); - if(!results.empty()) - return results[Misc::Rng::rollDice(results.size())]; - return NULL; - } + const T *searchRandom(const std::string &id) const; - const T *find(const std::string &id) const { - const T *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + const T *find(const std::string &id) const; /** Returns a random record that starts with the named ID. An exception is thrown if none * are found. */ - const T *findRandom(const std::string &id) const - { - const T *ptr = searchRandom(id); - if(ptr == 0) - { - std::ostringstream msg; - msg << T::getRecordType() << " starting with '"< inserted = mStatic.insert(std::make_pair(idLower, T())); - if (inserted.second) - mShared.push_back(&inserted.first->second); + size_t getSize() const; + int getDynamicSize() const; - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); - } + void listIdentifier(std::vector &list) const; - void setUp() { - } + T *insert(const T &item); + T *insertStatic(const T &item); - iterator begin() const { - return mShared.begin(); - } + bool eraseStatic(const std::string &id); + bool erase(const std::string &id); + bool erase(const T &item); - iterator end() const { - return mShared.end(); - } - - size_t getSize() const { - return mShared.size(); - } - - int getDynamicSize() const - { - return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 - } - - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + getSize()); - typename std::vector::const_iterator it = mShared.begin(); - for (; it != mShared.end(); ++it) { - list.push_back((*it)->mId); - } - } - - T *insert(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mDynamic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - T *insertStatic(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mStatic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - - bool eraseStatic(const std::string &id) { - T item; - item.mId = Misc::StringUtils::lowerCase(id); - - typename std::map::iterator it = mStatic.find(item.mId); - - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - // delete from the static part of mShared - typename std::vector::iterator sharedIter = mShared.begin(); - typename std::vector::iterator end = sharedIter + mStatic.size(); - - while (sharedIter != mShared.end() && sharedIter != end) { - if((*sharedIter)->mId == item.mId) { - mShared.erase(sharedIter); - break; - } - ++sharedIter; - } - mStatic.erase(it); - } - - return true; - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - typename Dynamic::iterator it = mDynamic.find(key); - if (it == mDynamic.end()) { - return false; - } - mDynamic.erase(it); - - // have to reinit the whole shared part - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { - mShared.push_back(&it->second); - } - return true; - } - - bool erase(const T &item) { - return erase(item.mId); - } - - void write (ESM::ESMWriter& writer, Loading::Listener& progress) const - { - for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); - ++iter) - { - writer.startRecord (T::sRecordId); - writer.writeHNString ("NAME", iter->second.mId); - iter->second.save (writer); - writer.endRecord (T::sRecordId); - } - } - - void read (ESM::ESMReader& reader, const std::string& id) - { - T record; - record.mId = id; - record.load (reader); - insert (record); - } + void load(ESM::ESMReader &esm, const std::string &id); + void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; + void read(ESM::ESMReader& reader, const std::string& id); }; - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); - - std::map::iterator it = mStatic.find(idLower); - if (it == mStatic.end()) { - it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed - } - - it->second.load(esm); - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::Script scpt; - scpt.load(esm); - Misc::StringUtils::toLower(scpt.mId); - - std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = scpt; - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) - { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mId); - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { @@ -387,73 +192,23 @@ namespace MWWorld std::vector mStatic; public: - Store() { - mStatic.push_back(LandTextureList()); - LandTextureList <exl = mStatic[0]; - // More than enough to hold Morrowind.esm. Extra lists for plugins will we - // added on-the-fly in a different method. - ltexl.reserve(128); - } + Store(); typedef std::vector::const_iterator iterator; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::LandTexture can never be modified or inserted/erased - const ESM::LandTexture *search(size_t index, size_t plugin) const { - assert(plugin < mStatic.size()); - const LandTextureList <exl = mStatic[plugin]; + const ESM::LandTexture *search(size_t index, size_t plugin) const; + const ESM::LandTexture *find(size_t index, size_t plugin) const; - assert(index < ltexl.size()); - return <exl.at(index); - } - - const ESM::LandTexture *find(size_t index, size_t plugin) const { - const ESM::LandTexture *ptr = search(index, plugin); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land texture with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - size_t getSize() const { - return mStatic.size(); - } - - size_t getSize(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].size(); - } - - void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { - ESM::LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if (plugin >= mStatic.size()) { - mStatic.resize(plugin+1); - } - LandTextureList <exl = mStatic[plugin]; - if(lt.mIndex + 1 > (int)ltexl.size()) - ltexl.resize(lt.mIndex+1); - - // Store it - ltexl[lt.mIndex] = lt; - } + size_t getSize() const; + size_t getSize(size_t plugin) const; + void load(ESM::ESMReader &esm, const std::string &id, size_t plugin); void load(ESM::ESMReader &esm, const std::string &id); - iterator begin(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].begin(); - } - - iterator end(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].end(); - } + iterator begin(size_t plugin) const; + iterator end(size_t plugin) const; }; template <> @@ -461,88 +216,22 @@ namespace MWWorld { std::vector mStatic; - struct Compare - { - bool operator()(const ESM::Land *x, const ESM::Land *y) { - if (x->mX == y->mX) { - return x->mY < y->mY; - } - return x->mX < y->mX; - } - }; - public: typedef SharedIterator iterator; - virtual ~Store() - { - for (std::vector::const_iterator it = - mStatic.begin(); it != mStatic.end(); ++it) - { - delete *it; - } + virtual ~Store(); - } - - size_t getSize() const { - return mStatic.size(); - } - - iterator begin() const { - return iterator(mStatic.begin()); - } - - iterator end() const { - return iterator(mStatic.end()); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::Land can never be modified or inserted/erased - ESM::Land *search(int x, int y) const { - ESM::Land land; - land.mX = x, land.mY = y; + ESM::Land *search(int x, int y) const; + ESM::Land *find(int x, int y) const; - std::vector::const_iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); - - if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { - return const_cast(*it); - } - return 0; - } - - ESM::Land *find(int x, int y) const{ - ESM::Land *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Land *ptr = new ESM::Land(); - ptr->load(esm); - - // Same area defined in multiple plugins? -> last plugin wins - // Can't use search() because we aren't sorted yet - is there any other way to speed this up? - for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) - { - delete *it; - mStatic.erase(it); - break; - } - } - - mStatic.push_back(ptr); - } - - void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); - } + void load(ESM::ESMReader &esm, const std::string &id); + void setUp(); }; template <> @@ -576,261 +265,44 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - const ESM::Cell *search(const ESM::Cell &cell) const { - if (cell.isExterior()) { - return search(cell.getGridX(), cell.getGridY()); - } - return search(cell.mName); - } - + const ESM::Cell *search(const ESM::Cell &cell) const; void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); public: typedef SharedIterator iterator; - const ESM::Cell *search(const std::string &id) const { - ESM::Cell cell; - cell.mName = Misc::StringUtils::lowerCase(id); + const ESM::Cell *search(const std::string &id) const; + const ESM::Cell *search(int x, int y) const; + const ESM::Cell *searchOrCreate(int x, int y); - std::map::const_iterator it = mInt.find(cell.mName); + const ESM::Cell *find(const std::string &id) const; + const ESM::Cell *find(int x, int y) const; - if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { - return &(it->second); - } + void setUp(); - DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); - if (dit != mDynamicInt.end()) { - return &dit->second; - } - - return 0; - } - - const ESM::Cell *search(int x, int y) const { - ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; - - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } - - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - return 0; - } - - const ESM::Cell *searchOrCreate(int x, int y) { - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } - - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - ESM::Cell newCell; - newCell.mData.mX = x; - newCell.mData.mY = y; - newCell.mData.mFlags = ESM::Cell::HasWater; - newCell.mAmbi.mAmbient = 0; - newCell.mAmbi.mSunlight = 0; - newCell.mAmbi.mFog = 0; - newCell.mAmbi.mFogDensity = 0; - return &mExt.insert(std::make_pair(key, newCell)).first->second; - } - - const ESM::Cell *find(const std::string &id) const { - const ESM::Cell *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << "Interior cell '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - const ESM::Cell *find(int x, int y) const { - const ESM::Cell *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Exterior at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void setUp() { - typedef DynamicExt::iterator ExtIterator; - typedef std::map::iterator IntIterator; - - mSharedInt.clear(); - mSharedInt.reserve(mInt.size()); - for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(it->second)); - } - - mSharedExt.clear(); - mSharedExt.reserve(mExt.size()); - for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(it->second)); - } - } - - // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get - // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. - // There some nasty three-way cyclic header dependency involved, which I could only fix by moving - // this method. void load(ESM::ESMReader &esm, const std::string &id); - iterator intBegin() const { - return iterator(mSharedInt.begin()); - } - - iterator intEnd() const { - return iterator(mSharedInt.end()); - } - - iterator extBegin() const { - return iterator(mSharedExt.begin()); - } - - iterator extEnd() const { - return iterator(mSharedExt.end()); - } + iterator intBegin() const; + iterator intEnd() const; + iterator extBegin() const; + iterator extEnd() const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByName(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } + const ESM::Cell *searchExtByName(const std::string &id) const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByRegion(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } + const ESM::Cell *searchExtByRegion(const std::string &id) const; - size_t getSize() const { - return mSharedInt.size() + mSharedExt.size(); - } + size_t getSize() const; - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + mSharedInt.size()); + void listIdentifier(std::vector &list) const; - std::vector::const_iterator it = mSharedInt.begin(); - for (; it != mSharedInt.end(); ++it) { - list.push_back((*it)->mName); - } - } + ESM::Cell *insert(const ESM::Cell &cell); - ESM::Cell *insert(const ESM::Cell &cell) { - if (search(cell) != 0) { - std::ostringstream msg; - msg << "Failed to create "; - msg << ((cell.isExterior()) ? "exterior" : "interior"); - msg << " cell"; + bool erase(const ESM::Cell &cell); + bool erase(const std::string &id); - throw std::runtime_error(msg.str()); - } - ESM::Cell *ptr; - if (cell.isExterior()) { - std::pair key(cell.getGridX(), cell.getGridY()); - - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicExt.insert(std::make_pair(key, cell)); - - ptr = &result.first->second; - mSharedExt.push_back(ptr); - } else { - std::string key = Misc::StringUtils::lowerCase(cell.mName); - - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicInt.insert(std::make_pair(key, cell)); - - ptr = &result.first->second; - mSharedInt.push_back(ptr); - } - return ptr; - } - - bool erase(const ESM::Cell &cell) { - if (cell.isExterior()) { - return erase(cell.getGridX(), cell.getGridY()); - } - return erase(cell.mName); - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - DynamicInt::iterator it = mDynamicInt.find(key); - - if (it == mDynamicInt.end()) { - return false; - } - mDynamicInt.erase(it); - mSharedInt.erase( - mSharedInt.begin() + mSharedInt.size(), - mSharedInt.end() - ); - - for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { - mSharedInt.push_back(&it->second); - } - - return true; - } - - bool erase(int x, int y) { - std::pair key(x, y); - DynamicExt::iterator it = mDynamicExt.find(key); - - if (it == mDynamicExt.end()) { - return false; - } - mDynamicExt.erase(it); - mSharedExt.erase( - mSharedExt.begin() + mSharedExt.size(), - mSharedExt.end() - ); - - for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { - mSharedExt.push_back(&it->second); - } - - return true; - } + bool erase(int x, int y); }; template <> @@ -847,165 +319,33 @@ namespace MWWorld public: - Store() - : mCells(NULL) - { - } + Store(); - void setCells(Store& cells) - { - mCells = &cells; - } + void setCells(Store& cells); + void load(ESM::ESMReader &esm, const std::string &id); + size_t getSize() const; - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Pathgrid pathgrid; - pathgrid.load(esm); + void setUp(); - // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. - // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. - // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. - // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. - // A proper fix should be made for future versions of the file format. - bool interior = mCells->search(pathgrid.mCell) != NULL; - - // Try to overwrite existing record - if (interior) - { - std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - else - { - std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - } - - size_t getSize() const { - return mInt.size() + mExt.size(); - } - - void setUp() { - } - - const ESM::Pathgrid *search(int x, int y) const { - Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); - if (it != mExt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *search(const std::string& name) const { - Interior::const_iterator it = mInt.find(name); - if (it != mInt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *find(int x, int y) const { - const ESM::Pathgrid* pathgrid = search(x,y); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << x << " " << y << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } - - const ESM::Pathgrid* find(const std::string& name) const { - const ESM::Pathgrid* pathgrid = search(name); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } - - const ESM::Pathgrid *search(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return search(cell.mData.mX, cell.mData.mY); - else - return search(cell.mName); - } - - const ESM::Pathgrid *find(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return find(cell.mData.mX, cell.mData.mY); - else - return find(cell.mName); - } + const ESM::Pathgrid *search(int x, int y) const; + const ESM::Pathgrid *search(const std::string& name) const; + const ESM::Pathgrid *find(int x, int y) const; + const ESM::Pathgrid* find(const std::string& name) const; + const ESM::Pathgrid *search(const ESM::Cell &cell) const; + const ESM::Pathgrid *find(const ESM::Cell &cell) const; }; - template - class IndexedStore - { - protected: - typedef typename std::map Static; - Static mStatic; - - public: - typedef typename std::map::const_iterator iterator; - - IndexedStore() {} - - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } - - void load(ESM::ESMReader &esm) { - T record; - record.load(esm); - - // Try to overwrite existing record - std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); - if (!ret.second) - ret.first->second = record; - } - - int getSize() const { - return mStatic.size(); - } - - void setUp() { - } - - const T *search(int index) const { - typename Static::const_iterator it = mStatic.find(index); - if (it != mStatic.end()) - return &(it->second); - return NULL; - } - - const T *find(int index) const { - const T *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> @@ -1016,70 +356,18 @@ namespace MWWorld public: typedef std::vector::const_iterator iterator; - Store() { - mStatic.reserve(ESM::Attribute::Length); - } + Store(); - const ESM::Attribute *search(size_t index) const { - if (index >= mStatic.size()) { - return 0; - } - return &mStatic.at(index); - } + const ESM::Attribute *search(size_t index) const; + const ESM::Attribute *find(size_t index) const; - const ESM::Attribute *find(size_t index) const { - const ESM::Attribute *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << "Attribute with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + void setUp(); - void setUp() { - for (int i = 0; i < ESM::Attribute::Length; ++i) { - mStatic.push_back( - ESM::Attribute( - ESM::Attribute::sAttributeIds[i], - ESM::Attribute::sGmstAttributeIds[i], - ESM::Attribute::sGmstAttributeDescIds[i] - ) - ); - } - } - - size_t getSize() const { - return mStatic.size(); - } - - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; }; - template<> - inline void Store::setUp() - { - // DialInfos marked as deleted are kept during the loading phase, so that the linked list - // structure is kept intact for inserting further INFOs. Delete them now that loading is done. - for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - ESM::Dialogue& dial = it->second; - dial.clearDeletedInfos(); - } - - mShared.clear(); - mShared.reserve(mStatic.size()); - std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } - } } //end namespace diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36e..f51cfd59bf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,6 +5,7 @@ #include +#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7964edf459..5251427c52 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -52,6 +52,11 @@ namespace MWRender class Camera; } +namespace ToUTF8 +{ + class Utf8Encoder; +} + struct ContentLoader; namespace MWWorld From 3a0293480e73b29a2548b76ea3da5ecf8e2cbab9 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 9 Jul 2015 15:32:15 -0400 Subject: [PATCH 0657/1812] Update boost in travis-ci to fix build failure --- CI/before_install.linux.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 2408a58221..2efb6e2bbf 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -10,9 +10,10 @@ fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw +echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev +sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 From 2bebfea38da9d1cdfa0613a96a4d5d18bc2c33ee Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 22:45:25 +0200 Subject: [PATCH 0658/1812] Instantiate struct as a struct --- components/esm/statstate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp index e95295cc9e..c17bedd817 100644 --- a/components/esm/statstate.cpp +++ b/components/esm/statstate.cpp @@ -46,7 +46,7 @@ namespace ESM if (mProgress) esm.writeHNT("STPR", mProgress); } - - template class StatState; - template class StatState; } + +template struct ESM::StatState; +template struct ESM::StatState; From 926c825d0c7f0a373fb6bd22d88d0df850407f3c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 15:37:42 +0300 Subject: [PATCH 0659/1812] Add NAME and DELE handling to ESM records. Changed records are those where DELE is located after NAME sub-record. And DELE is the last sub-record. --- components/esm/loadacti.cpp | 15 +++++++++++++++ components/esm/loadacti.hpp | 2 ++ components/esm/loadalch.cpp | 16 ++++++++++++++++ components/esm/loadalch.hpp | 2 ++ components/esm/loadappa.cpp | 15 +++++++++++++++ components/esm/loadappa.hpp | 2 ++ components/esm/loadarmo.cpp | 16 ++++++++++++++++ components/esm/loadarmo.hpp | 2 ++ components/esm/loadbody.cpp | 16 ++++++++++++++++ components/esm/loadbody.hpp | 2 ++ components/esm/loadbook.cpp | 15 +++++++++++++++ components/esm/loadbook.hpp | 2 ++ components/esm/loadclas.cpp | 16 ++++++++++++++++ components/esm/loadclas.hpp | 2 ++ components/esm/loadclot.cpp | 16 ++++++++++++++++ components/esm/loadclot.hpp | 2 ++ components/esm/loadcont.cpp | 16 ++++++++++++++++ components/esm/loadcont.hpp | 2 ++ components/esm/loadcrea.cpp | 15 +++++++++++++++ components/esm/loadcrea.hpp | 3 ++- components/esm/loaddoor.cpp | 15 +++++++++++++++ components/esm/loaddoor.hpp | 2 ++ components/esm/loadench.cpp | 17 +++++++++++++++++ components/esm/loadench.hpp | 2 ++ components/esm/loadfact.cpp | 16 ++++++++++++++++ components/esm/loadfact.hpp | 2 ++ components/esm/loadingr.cpp | 16 ++++++++++++++++ components/esm/loadingr.hpp | 2 ++ components/esm/loadlevlist.cpp | 15 +++++++++++++++ components/esm/loadlevlist.hpp | 2 ++ components/esm/loadligh.cpp | 15 +++++++++++++++ components/esm/loadligh.hpp | 2 ++ components/esm/loadlock.cpp | 15 +++++++++++++++ components/esm/loadlock.hpp | 2 ++ components/esm/loadmisc.cpp | 15 +++++++++++++++ components/esm/loadmisc.hpp | 2 ++ components/esm/loadnpc.cpp | 15 +++++++++++++++ components/esm/loadnpc.hpp | 2 ++ components/esm/loadprob.cpp | 15 +++++++++++++++ components/esm/loadprob.hpp | 2 ++ components/esm/loadrepa.cpp | 15 +++++++++++++++ components/esm/loadrepa.hpp | 2 ++ components/esm/loadsndg.cpp | 15 +++++++++++++++ components/esm/loadsndg.hpp | 2 ++ components/esm/loadsoun.cpp | 16 ++++++++++++++++ components/esm/loadsoun.hpp | 2 ++ components/esm/loadspel.cpp | 17 +++++++++++++++++ components/esm/loadspel.hpp | 2 ++ components/esm/loadstat.cpp | 15 +++++++++++++++ components/esm/loadstat.hpp | 2 ++ components/esm/loadweap.cpp | 16 ++++++++++++++++ components/esm/loadweap.hpp | 2 ++ components/esm/util.cpp | 20 ++++++++++++++++++++ components/esm/util.hpp | 9 +++++++++ 54 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 components/esm/util.cpp diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index b5adce5509..295d35f7e9 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Activator::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -32,6 +39,13 @@ namespace ESM } void Activator::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -42,5 +56,6 @@ namespace ESM mName.clear(); mScript.clear(); mModel.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index d9a55023bc..406512a225 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -17,6 +17,8 @@ struct Activator std::string mId, mName, mScript, mModel; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 18db512c0c..12078a5f7e 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Potion::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -46,6 +54,13 @@ namespace ESM } void Potion::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("TEXT", mIcon); esm.writeHNOCString("SCRI", mScript); @@ -64,5 +79,6 @@ namespace ESM mIcon.clear(); mScript.clear(); mEffects.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index b90a7c448d..3d1e6dee71 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -33,6 +33,8 @@ struct Potion std::string mId, mName, mModel, mIcon, mScript; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index f2c82aacfb..9107e5a8eb 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Apparatus::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ void Apparatus::load(ESMReader &esm) void Apparatus::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); esm.writeHNT("AADT", mData, 16); @@ -60,5 +74,6 @@ void Apparatus::save(ESMWriter &esm) const mIcon.clear(); mScript.clear(); mName.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index f18b046486..62d8561a1d 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -38,6 +38,8 @@ struct Apparatus AADTstruct mData; std::string mId, mModel, mIcon, mScript, mName; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 066551d6fe..626893d00f 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -41,6 +42,13 @@ namespace ESM void Armor::load(ESMReader &esm) { mParts.mParts.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -80,6 +88,13 @@ namespace ESM void Armor::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -103,5 +118,6 @@ namespace ESM mIcon.clear(); mScript.clear(); mEnchant.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 54416fd318..eb911254fd 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -96,6 +96,8 @@ struct Armor std::string mId, mName, mModel, mIcon, mScript, mEnchant; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index ed24ded57b..644eb3b502 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,12 @@ namespace ESM void BodyPart::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -38,6 +45,13 @@ void BodyPart::load(ESMReader &esm) } void BodyPart::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mRace); esm.writeHNT("BYDT", mData, 4); @@ -52,5 +66,7 @@ void BodyPart::save(ESMWriter &esm) const mModel.clear(); mRace.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c48c313056..8e1e81f827 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -60,6 +60,8 @@ struct BodyPart BYDTstruct mData; std::string mId, mModel, mRace; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 47f52fc31a..aec361873d 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Book::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -48,6 +55,13 @@ namespace ESM } void Book::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("BKDT", mData, 20); @@ -70,5 +84,6 @@ namespace ESM mScript.clear(); mEnchant.clear(); mText.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 6211b3e457..2f374c4b2e 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -28,6 +28,8 @@ struct Book std::string mName, mModel, mIcon, mScript, mEnchant, mText; std::string mId; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 66acaea721..df47a1a337 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -5,6 +5,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -41,6 +42,12 @@ namespace ESM void Class::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -69,6 +76,13 @@ namespace ESM } void Class::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); esm.writeHNT("CLDT", mData, 60); esm.writeHNOString("DESC", mDescription); @@ -87,5 +101,7 @@ namespace ESM for (int i=0; i<5; ++i) for (int i2=0; i2<2; ++i2) mData.mSkills[i][i2] = 0; + + mIsDeleted = false; } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 972b48e889..b619137345 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -73,6 +73,8 @@ struct Class std::string mId, mName, mDescription; CLDTstruct mData; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 5f49b5e709..1c73c4f21f 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -50,6 +58,13 @@ namespace ESM void Clothing::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("CTDT", mData, 12); @@ -74,5 +89,6 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 6945f224a4..8b4a8b3bb2 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -48,6 +48,8 @@ struct Clothing std::string mId, mName, mModel, mIcon, mEnchant, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 3481189c37..f54fe66e25 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -27,6 +28,13 @@ namespace ESM void Container::load(ESMReader &esm) { mInventory.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasWeight = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -71,6 +79,13 @@ namespace ESM void Container::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("CNDT", mWeight, 4); @@ -89,5 +104,6 @@ namespace ESM mWeight = 0; mFlags = 0x8; // set default flag value mInventory.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index ab587f9353..51166b8d47 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -52,6 +52,8 @@ struct Container int mFlags; InventoryList mInventory; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 50c47349ca..6da32eed78 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -17,6 +18,12 @@ namespace ESM { mSpells.mList.clear(); mTransport.mList.clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mScale = 1.f; mHasAI = false; bool hasNpdt = false; @@ -84,6 +91,13 @@ namespace ESM { void Creature::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("CNAM", mOriginal); esm.writeHNOCString("FNAM", mName); @@ -127,6 +141,7 @@ namespace ESM { mAiData.mServices = 0; mAiPackage.mList.clear(); mTransport.mList.clear(); + mIsDeleted = false; } const std::vector& Creature::getTransport() const diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 47e5954a5f..fb43f6272d 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -91,12 +91,13 @@ struct Creature InventoryList mInventory; SpellList mSpells; - bool mHasAI; AIData mAiData; AIPackageList mAiPackage; Transport mTransport; + bool mIsDeleted; + const std::vector& getTransport() const; void load(ESMReader &esm); diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index f446eed611..6ee43fd1ac 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Door::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -39,6 +46,13 @@ namespace ESM void Door::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("SCRI", mScript); @@ -53,5 +67,6 @@ namespace ESM mScript.clear(); mOpenSound.clear(); mCloseSound.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 3073f4e9de..b0326a744a 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -17,6 +17,8 @@ struct Door std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 54690d9a0b..88d9e0f2e4 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Enchantment::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -36,6 +44,13 @@ void Enchantment::load(ESMReader &esm) void Enchantment::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("ENDT", mData, 16); mEffects.save(esm); } @@ -48,5 +63,7 @@ void Enchantment::save(ESMWriter &esm) const mData.mAutocalc = 0; mEffects.mList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index cfcdd4edce..c9b19e31b3 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -42,6 +42,8 @@ struct Enchantment ENDTstruct mData; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 006ca0ce00..9149c2a30e 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -5,6 +5,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -32,6 +33,12 @@ void Faction::load(ESMReader &esm) for (int i=0;i<10;++i) mRanks[i].clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + int rankCounter=0; bool hasData = false; while (esm.hasMoreSubs()) @@ -71,6 +78,13 @@ void Faction::load(ESMReader &esm) } void Faction::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); for (int i = 0; i < 10; i++) @@ -109,5 +123,7 @@ void Faction::save(ESMWriter &esm) const mData.mSkills[i] = 0; mReactions.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 8645e23fd8..fec13b1ca0 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -62,6 +62,8 @@ struct Faction // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 7e0cc3168d..8bf0278f7a 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Ingredient::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -67,6 +74,13 @@ namespace ESM void Ingredient::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("IRDT", mData, 56); @@ -89,5 +103,7 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 5846a97809..69a6501800 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -31,6 +31,8 @@ struct Ingredient IRDTstruct mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index ca5c5d74d8..c8cb110a6e 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -3,12 +3,19 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { void LevelledListBase::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); @@ -42,6 +49,13 @@ namespace ESM } void LevelledListBase::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mFlags); esm.writeHNT("NNAM", mChanceNone); esm.writeHNT("INDX", mList.size()); @@ -58,6 +72,7 @@ namespace ESM mFlags = 0; mChanceNone = 0; mList.clear(); + mIsDeleted = false; } unsigned int CreatureLevList::sRecordId = REC_LEVC; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index dc6fcda5ec..4165275b21 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -36,6 +36,8 @@ struct LevelledListBase std::vector mList; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 26d70d964a..bd91e096ce 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Light::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -45,6 +52,13 @@ namespace ESM } void Light::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("ITEX", mIcon); @@ -66,5 +80,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mName.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index ed8c36665c..76274e6f4e 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -47,6 +47,8 @@ struct Light std::string mSound, mScript, mModel, mIcon, mName, mId; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 2747a6f787..c1e866b585 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Lockpick::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ namespace ESM void Lockpick::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index 0d678cd64c..af18773ed8 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -27,6 +27,8 @@ struct Lockpick Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 81c094f2bc..11d2f2a058 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Miscellaneous::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -41,6 +48,13 @@ namespace ESM void Miscellaneous::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("MCDT", mData, 12); @@ -57,5 +71,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 6e0b4e01b8..5d5e9f66f7 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -32,6 +32,8 @@ struct Miscellaneous std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 44d2987853..280db07911 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -17,6 +18,12 @@ namespace ESM mTransport.mList.clear(); mAiPackage.mList.clear(); + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasNpdt = false; bool hasFlags = false; mHasAI = false; @@ -103,6 +110,13 @@ namespace ESM } void NPC::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNCString("RNAM", mRace); @@ -178,6 +192,7 @@ namespace ESM mScript.clear(); mHair.clear(); mHead.clear(); + mIsDeleted = false; } int NPC::getFactionRank() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 9bda9560e1..7b75cb178a 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -130,6 +130,8 @@ struct NPC // body parts std::string mHair, mHead; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index c5f80c5844..12f7ad00a6 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Probe::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ namespace ESM void Probe::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index c737757aa3..9daab6b1ba 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -27,6 +27,8 @@ struct Probe Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index f90f9e39dc..608536f02b 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Repair::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = true; while (esm.hasMoreSubs()) { @@ -43,6 +50,13 @@ void Repair::load(ESMReader &esm) void Repair::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); @@ -61,5 +75,6 @@ void Repair::save(ESMWriter &esm) const mModel.clear(); mIcon.clear(); mScript.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index e765bc93a5..a660574be0 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -27,6 +27,8 @@ struct Repair Data mData; std::string mId, mName, mModel, mIcon, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 5ee6f5245c..f92c4eee83 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void SoundGenerator::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -36,6 +43,13 @@ namespace ESM } void SoundGenerator::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); @@ -46,5 +60,6 @@ namespace ESM mType = LeftFoot; mCreature.clear(); mSound.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 056958f0a8..e486976f51 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -36,6 +36,8 @@ struct SoundGenerator std::string mId, mCreature, mSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 690c1b4484..19e8a5d804 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Sound::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -34,6 +41,13 @@ namespace ESM void Sound::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mSound); esm.writeHNT("DATA", mData, 3); } @@ -45,5 +59,7 @@ namespace ESM mData.mVolume = 128; mData.mMinRange = 0; mData.mMaxRange = 255; + + mIsDeleted = false; } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index ff2202ca7d..95c89b29d3 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -23,6 +23,8 @@ struct Sound SOUNstruct mData; std::string mId, mSound; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 96c048e0a9..cac06b2001 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,13 @@ namespace ESM void Spell::load(ESMReader &esm) { mEffects.mList.clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -39,6 +47,13 @@ namespace ESM void Spell::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNOCString("FNAM", mName); esm.writeHNT("SPDT", mData, 12); mEffects.save(esm); @@ -53,5 +68,7 @@ namespace ESM mName.clear(); mEffects.mList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 491da1d179..2aba131add 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -45,6 +45,8 @@ struct Spell std::string mId, mName; EffectList mEffects; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index b0ab89bedd..a49caba897 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,15 +11,29 @@ namespace ESM void Static::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mModel = esm.getHNString("MODL"); } void Static::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); } void Static::blank() { mModel.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index aa4fe67b8f..c4306ad8fd 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -28,6 +28,8 @@ struct Static std::string mId, mModel; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 981a5815a2..66d65d0f51 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,12 @@ namespace ESM void Weapon::load(ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + bool hasData = false; while (esm.hasMoreSubs()) { @@ -45,6 +52,13 @@ namespace ESM } void Weapon::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + esm.writeHNCString("MODL", mModel); esm.writeHNOCString("FNAM", mName); esm.writeHNT("WPDT", mData, 32); @@ -72,5 +86,7 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index f66e9f3a68..30dfbc92af 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -69,6 +69,8 @@ struct Weapon std::string mId, mName, mModel, mIcon, mEnchant, mScript; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/util.cpp b/components/esm/util.cpp new file mode 100644 index 0000000000..c20bd4d518 --- /dev/null +++ b/components/esm/util.cpp @@ -0,0 +1,20 @@ +#include "util.hpp" + +namespace ESM +{ + bool readDeleSubRecord(ESMReader &esm) + { + if (esm.isNextSub("DELE")) + { + esm.getSubName(); + esm.skipHSub(); + return true; + } + return false; + } + + void writeDeleSubRecord(ESMWriter &esm) + { + esm.writeHNString("DELE", ""); + } +} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index a80df2456f..c670fb23af 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,9 +1,15 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H +#include + #include #include +#include "esmreader.hpp" +#include "esmwriter.hpp" +#include "loadbsgn.hpp" + namespace ESM { @@ -48,6 +54,9 @@ struct Vector3 } }; +bool readDeleSubRecord(ESMReader &esm); +void writeDeleSubRecord(ESMWriter &esm); + } #endif From 9ac20a33552e61182dbb90c5e2f0b34683720583 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 15:49:55 +0300 Subject: [PATCH 0660/1812] Add NAME and DELE handling to ESM records. Changed records are those where DELE is inserted at the beginning of a record (before NAME). The record has all required sub-records in this case. --- components/esm/loadbsgn.cpp | 11 +++++++++++ components/esm/loadbsgn.hpp | 2 ++ components/esm/loadltex.cpp | 9 +++++++++ components/esm/loadltex.hpp | 2 ++ components/esm/loadregn.cpp | 10 ++++++++++ components/esm/loadregn.hpp | 2 ++ 6 files changed, 36 insertions(+) diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index e0cd83ea07..7892bfc68c 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -11,6 +12,10 @@ namespace ESM void BirthSign::load(ESMReader &esm) { mPowers.mList.clear(); + + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + while (esm.hasMoreSubs()) { esm.getSubName(); @@ -37,6 +42,11 @@ void BirthSign::load(ESMReader &esm) void BirthSign::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); esm.writeHNOCString("DESC", mDescription); @@ -50,6 +60,7 @@ void BirthSign::save(ESMWriter &esm) const mDescription.clear(); mTexture.clear(); mPowers.mList.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index f91f91c974..41c70fb248 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -22,6 +22,8 @@ struct BirthSign // List of powers and abilities that come with this birth sign. SpellList mPowers; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index c3e2d50ff5..0ee30b11cd 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,11 +11,18 @@ namespace ESM void LandTexture::load(ESMReader &esm) { + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); esm.getHNT(mIndex, "INTV"); mTexture = esm.getHNString("DATA"); } void LandTexture::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); esm.writeHNT("INTV", mIndex); esm.writeHNCString("DATA", mTexture); } @@ -23,6 +31,7 @@ void LandTexture::blank() { mTexture.clear(); mIndex = -1; + mIsDeleted = false; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 50a7881054..e019e269e1 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -34,6 +34,8 @@ struct LandTexture std::string mId, mTexture; int mIndex; + bool mIsDeleted; + void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 1b08b72172..b0adc6f58e 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -10,6 +11,8 @@ namespace ESM void Region::load(ESMReader &esm) { + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); mName = esm.getHNOString("FNAM"); esm.getSubNameIs("WEAT"); @@ -49,6 +52,11 @@ void Region::load(ESMReader &esm) } void Region::save(ESMWriter &esm) const { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); if (esm.getVersion() == VER_12) @@ -77,5 +85,7 @@ void Region::save(ESMWriter &esm) const mName.clear(); mSleepList.clear(); mSoundList.clear(); + + mIsDeleted = false; } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 1e241fffbe..921ab887b6 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -51,6 +51,8 @@ struct Region std::vector mSoundList; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From d2c15647a3f1a03ad3c34dd7eaf6fe6cfbcd35ab Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 17:00:40 +0300 Subject: [PATCH 0661/1812] Add NAME and DELE handling to Script record --- components/esm/loadscpt.cpp | 12 ++++++++++++ components/esm/loadscpt.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index fd807ddd37..67c1b8f6ff 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" #include @@ -65,6 +66,10 @@ namespace ESM mData = data.mData; mId = data.mName.toString(); + // In scripts DELE sub-record appears after a header. + // The script data is following after DELE in this case. + mIsDeleted = readDeleSubRecord(esm); + mVarNames.clear(); while (esm.hasMoreSubs()) @@ -106,6 +111,11 @@ namespace ESM esm.writeHNT("SCHD", data, 52); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + if (!mVarNames.empty()) { esm.startSubRecord("SCVR"); @@ -136,6 +146,8 @@ namespace ESM mScriptText = "Begin \"" + mId + "\"\n\nEnd " + mId + "\n"; else mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; + + mIsDeleted = false; } } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 56390f3841..401dfe1050 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -50,6 +50,8 @@ public: /// Script source code std::string mScriptText; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From 19ac4e942a9efb329143415a46aabaaf51cbe8ef Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:18:42 +0300 Subject: [PATCH 0662/1812] Change DELE sub-record value to 0 (4 bytes) --- components/esm/util.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esm/util.cpp b/components/esm/util.cpp index c20bd4d518..892113cda1 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -1,5 +1,7 @@ #include "util.hpp" +#include + namespace ESM { bool readDeleSubRecord(ESMReader &esm) @@ -15,6 +17,6 @@ namespace ESM void writeDeleSubRecord(ESMWriter &esm) { - esm.writeHNString("DELE", ""); + esm.writeHNT("DELE", static_cast(0)); } } From 0b537186e5b513cf7d6045a7c88e8c6b4d4afc7c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:42:24 +0300 Subject: [PATCH 0663/1812] Add NAME and DELE handling to Dialogue record --- components/esm/loaddial.cpp | 27 +++++++++++++++++---------- components/esm/loaddial.hpp | 5 +++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index f2da8f3775..77a04ca013 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -2,9 +2,12 @@ #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -12,18 +15,19 @@ namespace ESM void Dialogue::load(ESMReader &esm) { + mIsDeleted = false; + + mId = esm.getHNString("NAME"); esm.getSubNameIs("DATA"); esm.getSubHeader(); int si = esm.getSubSize(); if (si == 1) esm.getT(mType); - else if (si == 4) + else if (si == 4) // The dialogue is deleted { - // These are just markers, their values are not used. - int i; - esm.getT(i); - esm.getHNT(i, "DELE"); - mType = Deleted; + int32_t empty; + esm.getT(empty); // Skip an empty DATA + mIsDeleted = readDeleSubRecord(esm); } else esm.fail("Unknown sub record size"); @@ -31,12 +35,15 @@ void Dialogue::load(ESMReader &esm) void Dialogue::save(ESMWriter &esm) const { - if (mType != Deleted) - esm.writeHNT("DATA", mType); + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + esm.writeHNT("DATA", static_cast(0)); + writeDeleSubRecord(esm); + } else { - esm.writeHNT("DATA", (int)1); - esm.writeHNT("DELE", (int)1); + esm.writeHNT("DATA", mType); } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 58598d3536..ab8cf4bff0 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,8 +30,7 @@ struct Dialogue Voice = 1, Greeting = 2, Persuasion = 3, - Journal = 4, - Deleted = -1 + Journal = 4 }; std::string mId; @@ -46,6 +45,8 @@ struct Dialogue // This is only used during the loading phase to speed up DialInfo merging. LookupMap mLookup; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From 847614c26f372d5483bb96a3b30e90dd9358b28f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 19:57:08 +0300 Subject: [PATCH 0664/1812] Add DELE handling to Info record --- components/esm/loadinfo.cpp | 21 ++++++++++++++++++--- components/esm/loadinfo.hpp | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index a2bade1c5e..3394ddbad5 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -3,6 +3,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -19,11 +20,18 @@ void DialInfo::load(ESMReader &esm) // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings mSelects.clear(); - // Not present if deleted - if (esm.isNextSub("DATA")) { - esm.getHT(mData, 12); + // If the info is deleted, NAME and DELE sub-records are followed after NNAM + if (esm.isNextSub("NAME")) + { + esm.getSubName(); + mResponse = esm.getHString(); + mIsDeleted = readDeleSubRecord(esm); + return; } + esm.getSubNameIs("DATA"); + esm.getHT(mData, 12); + if (!esm.hasMoreSubs()) return; @@ -131,6 +139,13 @@ void DialInfo::save(ESMWriter &esm) const { esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) + { + esm.writeHNCString("NAME", mResponse); + writeDeleSubRecord(esm); + return; + } + esm.writeHNT("DATA", mData, 12); esm.writeHNOCString("ONAM", mActor); esm.writeHNOCString("RNAM", mRace); diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 54003b0d96..8b4fae761f 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -106,6 +106,8 @@ struct DialInfo REC_DELE = 0x454c4544 }; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From b667338a8fe5ffb78bc28151948f31e03dc99407 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 20:41:39 +0300 Subject: [PATCH 0665/1812] Add NAME and DELE handling to Cell record --- components/esm/loadcell.cpp | 23 +++++++++++++++-------- components/esm/loadcell.hpp | 3 +++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 94f4b0b6e7..86b4e4edb8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -12,6 +12,7 @@ #include "esmwriter.hpp" #include "defs.hpp" #include "cellid.hpp" +#include "util.hpp" namespace { @@ -54,10 +55,17 @@ namespace ESM void Cell::load(ESMReader &esm, bool saveContext) { + loadName(esm); loadData(esm); loadCell(esm, saveContext); } +void Cell::loadName(ESMReader &esm) +{ + mName = esm.getHNString("NAME"); + mIsDeleted = readDeleSubRecord(esm); +} + void Cell::loadCell(ESMReader &esm, bool saveContext) { mRefNumCounter = 0; @@ -105,13 +113,6 @@ void Cell::loadCell(ESMReader &esm, bool saveContext) void Cell::loadData(ESMReader &esm) { - // Ignore this for now, it might mean we should delete the entire - // cell? - // TODO: treat the special case "another plugin moved this ref, but we want to delete it"! - if (esm.isNextSub("DELE")) { - esm.skipHSub(); - } - esm.getHNT(mData, "DATA", 12); } @@ -124,6 +125,12 @@ void Cell::postLoad(ESMReader &esm) void Cell::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mName); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNT("DATA", mData, 12); if (mData.mFlags & Interior) { @@ -147,7 +154,7 @@ void Cell::save(ESMWriter &esm) const esm.writeHNT("NAM5", mMapColor); } - if (mRefNumCounter != 0) + if (mRefNumCounter != 0 && !mIsDeleted) esm.writeHNT("NAM0", mRefNumCounter); } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 12fb8c0684..b313435d6a 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -112,11 +112,14 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; + bool mIsDeleted; + void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. void load(ESMReader &esm, bool saveContext = true); // Load everything (except references) + void loadName(ESMReader &esm); // Load NAME and checks for DELE void loadData(ESMReader &esm); // Load DATAstruct only void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except DATAstruct and references From 8c3654af11e21ec8ca068c1581e69de707000f67 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 20:56:26 +0300 Subject: [PATCH 0666/1812] Add NAME handling to Race record --- components/esm/loadrace.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index e88454d4c1..3feb06c927 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -22,6 +22,8 @@ void Race::load(ESMReader &esm) { mPowers.mList.clear(); + mId = esm.getHNString("NAME"); + bool hasData = false; while (esm.hasMoreSubs()) { @@ -51,6 +53,7 @@ void Race::load(ESMReader &esm) } void Race::save(ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNT("RADT", mData, 140); mPowers.save(esm); From 30b42bf4c0a3c953703987ec333bd89ecd667f7e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 21:24:35 +0300 Subject: [PATCH 0667/1812] Remove redundant code --- components/esm/loadinfo.cpp | 1 - components/esm/util.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 3394ddbad5..3b5e0ea3a2 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -23,7 +23,6 @@ void DialInfo::load(ESMReader &esm) // If the info is deleted, NAME and DELE sub-records are followed after NNAM if (esm.isNextSub("NAME")) { - esm.getSubName(); mResponse = esm.getHString(); mIsDeleted = readDeleSubRecord(esm); return; diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 892113cda1..ff24365441 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -8,7 +8,6 @@ namespace ESM { if (esm.isNextSub("DELE")) { - esm.getSubName(); esm.skipHSub(); return true; } From 09a33580170076f14b2d46d72ad93d60fe52fc07 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 00:04:14 +0300 Subject: [PATCH 0668/1812] Add NAME and DELE handling to Global record --- components/esm/loadglob.cpp | 16 ++++++++++++++++ components/esm/loadglob.hpp | 2 ++ 2 files changed, 18 insertions(+) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index a78ed1a1be..6cc37d675b 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -1,6 +1,9 @@ #include "loadglob.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" #include "defs.hpp" +#include "util.hpp" namespace ESM { @@ -8,11 +11,24 @@ namespace ESM void Global::load (ESMReader &esm) { + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + mValue.read (esm, ESM::Variant::Format_Global); } void Global::save (ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + mValue.write (esm, ESM::Variant::Format_Global); } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index cc5dbbdcfc..45b47a3bc9 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -24,6 +24,8 @@ struct Global std::string mId; Variant mValue; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From b2f3ccb080b459f212280cc2565110a0343645ec Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:17:59 +0300 Subject: [PATCH 0669/1812] Add NAME handling to GameSetting record --- components/esm/loadgmst.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 21d66339a9..9e2a80270d 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,5 +1,7 @@ #include "loadgmst.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" #include "defs.hpp" namespace ESM @@ -8,11 +10,13 @@ namespace ESM void GameSetting::load (ESMReader &esm) { + mId = esm.getHNString("NAME"); mValue.read (esm, ESM::Variant::Format_Gmst); } void GameSetting::save (ESMWriter &esm) const { + esm.writeHNCString("NAME", mId); mValue.write (esm, ESM::Variant::Format_Gmst); } From 89e44c8f1fcb02a0ea78b468402a2c8e96d5465c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:24:05 +0300 Subject: [PATCH 0670/1812] Remove explicit record ID in load/read methods of MWWorld::Store --- apps/openmw/mwworld/store.cpp | 10 ++-- apps/openmw/mwworld/store.hpp | 110 +++++++++++++++++++++++----------- components/esm/util.cpp | 18 ++++++ components/esm/util.hpp | 27 ++++++++- 4 files changed, 123 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cdcc00b4d3..767a33b135 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -35,7 +35,7 @@ void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) } } -void Store::load(ESM::ESMReader &esm, const std::string &id) +void Store::load(ESM::ESMReader &esm) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // and we merge all this data into one Cell object. However, we can't simply search for the cell id, @@ -43,9 +43,9 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // are not available until both cells have been loaded at least partially! // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); ESM::Cell cell; - cell.mName = id; + cell.loadName(esm); + std::string idLower = Misc::StringUtils::lowerCase(cell.mName); // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with @@ -119,9 +119,9 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) } } -void Store::load(ESM::ESMReader &esm, const std::string &id) +void Store::load(ESM::ESMReader &esm) { - load(esm, id, esm.getIndex()); + load(esm, esm.getIndex()); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2d73d5312e..a61cbd2ac1 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -10,6 +10,7 @@ #include #include +#include #include @@ -26,15 +27,19 @@ namespace MWWorld virtual size_t getSize() const = 0; virtual int getDynamicSize() const { return 0; } - virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; + virtual void load(ESM::ESMReader &esm) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} - virtual void read (ESM::ESMReader& reader, const std::string& id) {} + virtual void read (ESM::ESMReader& reader) {} ///< Read into dynamic storage + + virtual std::string getLastAddedRecordId() const { return ""; } + ///< Returns the last loaded/read ID or empty string if a loaded record has no ID + virtual bool isLastAddedRecordDeleted() const { return false; } }; template @@ -126,6 +131,7 @@ namespace MWWorld } }; + T mLastAddedRecord; friend class ESMStore; @@ -208,15 +214,16 @@ namespace MWWorld return ptr; } - void load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); + void load(ESM::ESMReader &esm) { + T record; + record.load(esm); - std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + std::string idLower = Misc::StringUtils::lowerCase(record.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, record)); if (inserted.second) mShared.push_back(&inserted.first->second); - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); + mLastAddedRecord = record; } void setUp() { @@ -325,58 +332,79 @@ namespace MWWorld ++iter) { writer.startRecord (T::sRecordId); - writer.writeHNString ("NAME", iter->second.mId); iter->second.save (writer); writer.endRecord (T::sRecordId); } } - void read (ESM::ESMReader& reader, const std::string& id) + void read (ESM::ESMReader& reader) { T record; - record.mId = id; record.load (reader); insert (record); + + mLastAddedRecord = record; + } + + std::string getLastAddedRecordId() const + { + return ESM::getRecordId(mLastAddedRecord); + } + + bool isLastAddedRecordDeleted() const + { + return ESM::isRecordDeleted(mLastAddedRecord); } }; template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); + inline void Store::load(ESM::ESMReader &esm) { + ESM::Dialogue dialogue; + dialogue.load(esm); - std::map::iterator it = mStatic.find(idLower); - if (it == mStatic.end()) { - it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed + std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); + std::map::iterator found = mStatic.find(idLower); + if (found == mStatic.end()) + { + mStatic.insert(std::make_pair(idLower, dialogue)); } - - it->second.load(esm); + else + { + found->second = dialogue; + } + + mLastAddedRecord = dialogue; } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::Script scpt; - scpt.load(esm); - Misc::StringUtils::toLower(scpt.mId); + inline void Store::load(ESM::ESMReader &esm) { + ESM::Script script; + script.load(esm); - std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + std::string idLower = Misc::StringUtils::toLower(script.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else - inserted.first->second = scpt; + inserted.first->second = script; + + mLastAddedRecord = script; } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) + inline void Store::load(ESM::ESMReader &esm) { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mId); - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + ESM::StartScript script; + script.load(esm); + + std::string idLower = Misc::StringUtils::toLower(script.mId); + std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else - inserted.first->second = s; + inserted.first->second = script; + + mLastAddedRecord = script; } template <> @@ -385,6 +413,7 @@ namespace MWWorld // For multiple ESM/ESP files we need one list per file. typedef std::vector LandTextureList; std::vector mStatic; + ESM::LandTexture mLastLoadedTexture; public: Store() { @@ -426,10 +455,9 @@ namespace MWWorld return mStatic[plugin].size(); } - void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { + void load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; lt.load(esm); - lt.mId = id; // Make sure we have room for the structure if (plugin >= mStatic.size()) { @@ -443,7 +471,7 @@ namespace MWWorld ltexl[lt.mIndex] = lt; } - void load(ESM::ESMReader &esm, const std::string &id); + void load(ESM::ESMReader &esm); iterator begin(size_t plugin) const { assert(plugin < mStatic.size()); @@ -454,6 +482,16 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } + + std::string getLastAddedRecordId() const + { + return ESM::getRecordId(mLastLoadedTexture); + } + + bool isLastAddedRecordDeleted() const + { + return ESM::isRecordDeleted(mLastLoadedTexture); + } }; template <> @@ -521,7 +559,7 @@ namespace MWWorld return ptr; } - void load(ESM::ESMReader &esm, const std::string &id) { + void load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); ptr->load(esm); @@ -688,7 +726,7 @@ namespace MWWorld // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. // There some nasty three-way cyclic header dependency involved, which I could only fix by moving // this method. - void load(ESM::ESMReader &esm, const std::string &id); + void load(ESM::ESMReader &esm); iterator intBegin() const { return iterator(mSharedInt.begin()); @@ -857,7 +895,7 @@ namespace MWWorld mCells = &cells; } - void load(ESM::ESMReader &esm, const std::string &id) { + void load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; pathgrid.load(esm); diff --git a/components/esm/util.cpp b/components/esm/util.cpp index ff24365441..4cfe644e8f 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -18,4 +18,22 @@ namespace ESM { esm.writeHNT("DELE", static_cast(0)); } + + template <> + bool isRecordDeleted(const StartScript &script) + { + return false; + } + + template <> + bool isRecordDeleted(const Race &race) + { + return false; + } + + template <> + bool isRecordDeleted(const GameSetting &gmst) + { + return false; + } } diff --git a/components/esm/util.hpp b/components/esm/util.hpp index c670fb23af..94a7956efb 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -8,7 +8,10 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "loadbsgn.hpp" +#include "loadsscr.hpp" +#include "loadglob.hpp" +#include "loadrace.hpp" +#include "loadgmst.hpp" namespace ESM { @@ -57,6 +60,28 @@ struct Vector3 bool readDeleSubRecord(ESMReader &esm); void writeDeleSubRecord(ESMWriter &esm); +template +std::string getRecordId(const RecordT &record) +{ + return record.mId; +} + +template +bool isRecordDeleted(const RecordT &record) +{ + return record.mIsDeleted; +} + +// The following records can't be deleted (for now) +template <> +bool isRecordDeleted(const StartScript &script); + +template <> +bool isRecordDeleted(const Race &race); + +template <> +bool isRecordDeleted(const GameSetting &gmst); + } #endif From 9301bc148e9fa10e58519debdc7103a9babae07b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:26:20 +0300 Subject: [PATCH 0671/1812] Remove NAME handling from MWWorld::ESMStore --- apps/openmw/mwworld/esmstore.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5d9beecb65..50a7e3376e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -95,23 +95,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) throw std::runtime_error(error.str()); } } else { - // Load it - std::string id = esm.getHNOString("NAME"); - // ... unless it got deleted! This means that the following record - // has been deleted, and trying to load it using standard assumptions - // on the structure will (probably) fail. - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - it->second->eraseStatic(id); - continue; - } - it->second->load(esm, id); - - // DELE can also occur after the usual subrecords - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - it->second->eraseStatic(id); - continue; + it->second->load(esm); + std::string id = it->second->getLastAddedRecordId(); + if (it->second->isLastAddedRecordDeleted()) + { + it->second->eraseStatic(id); + continue; } if (n.val==ESM::REC_DIAL) { @@ -194,13 +183,13 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - std::string id = reader.getHNString ("NAME"); - mStores[type]->read (reader, id); + StoreBase *store = mStores[type]; + store->read (reader); // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame // that really should be cleared instead of just overwritten - mIds[id] = type; + mIds[store->getLastAddedRecordId()] = type; } if (type==ESM::REC_NPC_) From 897a52cdda1cec48833af47c2798b6836c9f4d36 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 8 Jul 2015 21:40:01 +0300 Subject: [PATCH 0672/1812] Remove NAME handling from MWWorld::Globals --- apps/openmw/mwworld/globals.cpp | 26 ++++++++++++-------------- apps/openmw/mwworld/globals.hpp | 4 ++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index e7cb04590b..671793a170 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -14,7 +14,7 @@ namespace MWWorld { Globals::Collection::const_iterator Globals::find (const std::string& name) const { - Collection::const_iterator iter = mVariables.find (name); + Collection::const_iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); @@ -24,7 +24,7 @@ namespace MWWorld Globals::Collection::iterator Globals::find (const std::string& name) { - Collection::iterator iter = mVariables.find (name); + Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); @@ -41,28 +41,28 @@ namespace MWWorld for (MWWorld::Store::iterator iter = globals.begin(); iter!=globals.end(); ++iter) { - mVariables.insert (std::make_pair (iter->mId, iter->mValue)); + mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (iter->mId), *iter)); } } const ESM::Variant& Globals::operator[] (const std::string& name) const { - return find (name)->second; + return find (Misc::StringUtils::lowerCase (name))->second.mValue; } ESM::Variant& Globals::operator[] (const std::string& name) { - return find (name)->second; + return find (Misc::StringUtils::lowerCase (name))->second.mValue; } char Globals::getType (const std::string& name) const { - Collection::const_iterator iter = mVariables.find (name); + Collection::const_iterator iter = mVariables.find (Misc::StringUtils::lowerCase (name)); if (iter==mVariables.end()) return ' '; - switch (iter->second.getType()) + switch (iter->second.mValue.getType()) { case ESM::VT_Short: return 's'; case ESM::VT_Long: return 'l'; @@ -82,8 +82,7 @@ namespace MWWorld for (Collection::const_iterator iter (mVariables.begin()); iter!=mVariables.end(); ++iter) { writer.startRecord (ESM::REC_GLOB); - writer.writeHNString ("NAME", iter->first); - iter->second.write (writer, ESM::Variant::Format_Global); + iter->second.save (writer); writer.endRecord (ESM::REC_GLOB); } } @@ -92,14 +91,13 @@ namespace MWWorld { if (type==ESM::REC_GLOB) { - std::string id = reader.getHNString ("NAME"); + ESM::Global global; + global.load(reader); - Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (id)); + Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (global.mId)); if (iter!=mVariables.end()) - iter->second.read (reader, ESM::Variant::Format_Global); - else - reader.skipRecord(); + iter->second = global; return true; } diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index bb4ab13d92..3468c2e719 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -8,7 +8,7 @@ #include #include -#include +#include namespace ESM { @@ -29,7 +29,7 @@ namespace MWWorld { private: - typedef std::map Collection; + typedef std::map Collection; Collection mVariables; // type, value From 00bf87b5611d7dbc8fc8e7d5add1a4a236071733 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 15:17:38 +0300 Subject: [PATCH 0673/1812] Convert IDs of loaded records to lower case in MWWorld::Store --- apps/openmw/mwworld/store.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a61cbd2ac1..c482486d8e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -217,9 +217,9 @@ namespace MWWorld void load(ESM::ESMReader &esm) { T record; record.load(esm); + Misc::StringUtils::toLower(record.mId); - std::string idLower = Misc::StringUtils::lowerCase(record.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, record)); + std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); @@ -359,6 +359,7 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm) { + // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; dialogue.load(esm); @@ -380,9 +381,9 @@ namespace MWWorld inline void Store::load(ESM::ESMReader &esm) { ESM::Script script; script.load(esm); + Misc::StringUtils::toLower(script.mId); - std::string idLower = Misc::StringUtils::toLower(script.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); + std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else @@ -396,9 +397,9 @@ namespace MWWorld { ESM::StartScript script; script.load(esm); + Misc::StringUtils::toLower(script.mId); - std::string idLower = Misc::StringUtils::toLower(script.mId); - std::pair inserted = mStatic.insert(std::make_pair(idLower, script)); + std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); if (inserted.second) mShared.push_back(&inserted.first->second); else From 20723581a102f021ba04296096d5cd0c715f0d66 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 21:10:57 +0300 Subject: [PATCH 0674/1812] Letter case fix for MWWorld::Globals --- apps/openmw/mwworld/globals.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 671793a170..668a33f091 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -93,9 +93,9 @@ namespace MWWorld { ESM::Global global; global.load(reader); + Misc::StringUtils::toLower(global.mId); - Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (global.mId)); - + Collection::iterator iter = mVariables.find (global.mId); if (iter!=mVariables.end()) iter->second = global; From 7ecb54a776a298bee470397c40ce64945a2b0174 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 9 Jul 2015 21:45:24 +0300 Subject: [PATCH 0675/1812] Set Deleted flag to false when initializing ESM records --- components/esm/loadacti.cpp | 4 + components/esm/loadacti.hpp | 2 + components/esm/loadalch.cpp | 4 + components/esm/loadalch.hpp | 2 + components/esm/loadappa.cpp | 98 ++++++----- components/esm/loadappa.hpp | 2 + components/esm/loadarmo.cpp | 4 + components/esm/loadarmo.hpp | 2 + components/esm/loadbody.cpp | 82 ++++----- components/esm/loadbody.hpp | 2 + components/esm/loadbook.cpp | 4 + components/esm/loadbook.hpp | 2 + components/esm/loadbsgn.cpp | 76 ++++---- components/esm/loadbsgn.hpp | 2 + components/esm/loadcell.hpp | 3 +- components/esm/loadclas.cpp | 3 + components/esm/loadclas.hpp | 2 + components/esm/loadclot.cpp | 4 + components/esm/loadclot.hpp | 2 + components/esm/loadcont.cpp | 4 + components/esm/loadcont.hpp | 2 + components/esm/loadcrea.cpp | 4 + components/esm/loadcrea.hpp | 2 + components/esm/loaddial.cpp | 235 ++++++++++++------------- components/esm/loaddial.hpp | 2 + components/esm/loaddoor.cpp | 4 + components/esm/loaddoor.hpp | 2 + components/esm/loadench.cpp | 78 +++++---- components/esm/loadench.hpp | 2 + components/esm/loadfact.cpp | 141 +++++++-------- components/esm/loadfact.hpp | 2 + components/esm/loadglob.cpp | 4 + components/esm/loadglob.hpp | 2 + components/esm/loadinfo.cpp | 308 +++++++++++++++++---------------- components/esm/loadinfo.hpp | 2 + components/esm/loadingr.cpp | 4 + components/esm/loadingr.hpp | 2 + components/esm/loadlevlist.cpp | 3 + components/esm/loadlevlist.hpp | 2 + components/esm/loadligh.cpp | 4 + components/esm/loadligh.hpp | 2 + components/esm/loadlock.cpp | 4 + components/esm/loadlock.hpp | 2 + components/esm/loadltex.cpp | 47 ++--- components/esm/loadltex.hpp | 6 +- components/esm/loadmisc.cpp | 4 + components/esm/loadmisc.hpp | 2 + components/esm/loadnpc.cpp | 4 + components/esm/loadnpc.hpp | 2 + components/esm/loadprob.cpp | 4 + components/esm/loadprob.hpp | 2 + components/esm/loadregn.cpp | 105 +++++------ components/esm/loadregn.hpp | 2 + components/esm/loadrepa.cpp | 100 ++++++----- components/esm/loadrepa.hpp | 2 + components/esm/loadscpt.cpp | 5 +- components/esm/loadscpt.hpp | 2 + components/esm/loadsndg.cpp | 4 + components/esm/loadsndg.hpp | 2 + components/esm/loadsoun.cpp | 4 + components/esm/loadsoun.hpp | 2 + components/esm/loadspel.cpp | 4 + components/esm/loadspel.hpp | 2 + components/esm/loadstat.cpp | 4 + components/esm/loadstat.hpp | 2 + components/esm/loadweap.cpp | 4 + components/esm/loadweap.hpp | 2 + 67 files changed, 815 insertions(+), 619 deletions(-) diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 295d35f7e9..14a3abe54a 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; + Activator::Activator() + : mIsDeleted(false) + {} + void Activator::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 406512a225..93de07b250 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -19,6 +19,8 @@ struct Activator bool mIsDeleted; + Activator(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 12078a5f7e..5faeb99e16 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; + Potion::Potion() + : mIsDeleted(false) + {} + void Potion::load(ESMReader &esm) { mEffects.mList.clear(); diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index 3d1e6dee71..921585a9dc 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -35,6 +35,8 @@ struct Potion bool mIsDeleted; + Potion(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 9107e5a8eb..ea375aa7f6 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -9,60 +9,64 @@ namespace ESM { unsigned int Apparatus::sRecordId = REC_APPA; -void Apparatus::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + Apparatus::Apparatus() + : mIsDeleted(false) + {} - bool hasData = false; - while (esm.hasMoreSubs()) + void Apparatus::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'A','A','D','T'>::value: - esm.getHT(mData); - hasData = true; - break; - case ESM::FourCC<'S','C','R','I'>::value: - mScript = esm.getHString(); - break; - case ESM::FourCC<'I','T','E','X'>::value: - mIcon = esm.getHString(); - break; - default: - esm.fail("Unknown subrecord"); + return; } - } - if (!hasData) - esm.fail("Missing AADT"); -} -void Apparatus::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing AADT"); + } + + void Apparatus::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); - esm.writeHNT("AADT", mData, 16); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNCString("ITEX", mIcon); -} + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + esm.writeHNT("AADT", mData, 16); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNCString("ITEX", mIcon); + } void Apparatus::blank() { diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 62d8561a1d..2dac379952 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -40,6 +40,8 @@ struct Apparatus bool mIsDeleted; + Apparatus(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 626893d00f..d23a71cac9 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -39,6 +39,10 @@ namespace ESM unsigned int Armor::sRecordId = REC_ARMO; + Armor::Armor() + : mIsDeleted(false) + {} + void Armor::load(ESMReader &esm) { mParts.mParts.clear(); diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index eb911254fd..4ebe181a72 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -98,6 +98,8 @@ struct Armor bool mIsDeleted; + Armor(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 644eb3b502..e0ebfd5390 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,53 +9,57 @@ namespace ESM { unsigned int BodyPart::sRecordId = REC_BODY; + BodyPart::BodyPart() + : mIsDeleted(false) + {} -void BodyPart::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void BodyPart::load(ESMReader &esm) { - return; - } - - bool hasData = false; - while (esm.hasMoreSubs()) - { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mRace = esm.getHString(); - break; - case ESM::FourCC<'B','Y','D','T'>::value: - esm.getHT(mData, 4); - hasData = true; - break; - default: - esm.fail("Unknown subrecord"); + return; } + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } - if (!hasData) - esm.fail("Missing BYDT subrecord"); -} -void BodyPart::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + void BodyPart::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mRace); - esm.writeHNT("BYDT", mData, 4); -} + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mRace); + esm.writeHNT("BYDT", mData, 4); + } void BodyPart::blank() { diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 8e1e81f827..f32d2fb58d 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -62,6 +62,8 @@ struct BodyPart bool mIsDeleted; + BodyPart(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index aec361873d..2824b62000 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; + Book::Book() + : mIsDeleted(false) + {} + void Book::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 2f374c4b2e..931f813c0e 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -30,6 +30,8 @@ struct Book bool mIsDeleted; + Book(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 7892bfc68c..8cdeed3f6e 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -9,50 +9,54 @@ namespace ESM { unsigned int BirthSign::sRecordId = REC_BSGN; -void BirthSign::load(ESMReader &esm) -{ - mPowers.mList.clear(); + BirthSign::BirthSign() + : mIsDeleted(false) + {} - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - - while (esm.hasMoreSubs()) + void BirthSign::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mPowers.mList.clear(); + + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'T','N','A','M'>::value: - mTexture = esm.getHString(); - break; - case ESM::FourCC<'D','E','S','C'>::value: - mDescription = esm.getHString(); - break; - case ESM::FourCC<'N','P','C','S'>::value: - mPowers.add(esm); - break; - default: - esm.fail("Unknown subrecord"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } } } -} -void BirthSign::save(ESMWriter &esm) const -{ - if (mIsDeleted) + void BirthSign::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - } - esm.writeHNCString("NAME", mId); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("TNAM", mTexture); - esm.writeHNOCString("DESC", mDescription); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("TNAM", mTexture); + esm.writeHNOCString("DESC", mDescription); - mPowers.save(esm); -} + mPowers.save(esm); + } void BirthSign::blank() { diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 41c70fb248..685ade82ff 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -24,6 +24,8 @@ struct BirthSign bool mIsDeleted; + BirthSign(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index b313435d6a..bf65c5fa8b 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -85,7 +85,8 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(0) + mRefNumCounter(0), + mIsDeleted(false) {} // Interior cells are indexed by this (it's the 'id'), for exterior diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index df47a1a337..1384a6280d 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -23,6 +23,9 @@ namespace ESM "sSpecializationStealth" }; + Class::Class() + : mIsDeleted(false) + {} int& Class::CLDTstruct::getSkill (int index, bool major) { diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index b619137345..399e93c241 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -75,6 +75,8 @@ struct Class bool mIsDeleted; + Class(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 1c73c4f21f..88f2e57154 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Clothing::sRecordId = REC_CLOT; + Clothing::Clothing() + : mIsDeleted(false) + {} + void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 8b4a8b3bb2..202c1ec459 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -50,6 +50,8 @@ struct Clothing bool mIsDeleted; + Clothing(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f54fe66e25..3d3d7fced8 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -25,6 +25,10 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; + Container::Container() + : mIsDeleted(false) + {} + void Container::load(ESMReader &esm) { mInventory.mList.clear(); diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 51166b8d47..31c7e1815b 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -54,6 +54,8 @@ struct Container bool mIsDeleted; + Container(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 6da32eed78..57e911e701 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; + Creature::Creature() + : mIsDeleted(false) + {} + void Creature::load(ESMReader &esm) { mPersistent = (esm.getRecordFlags() & 0x0400) != 0; diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index fb43f6272d..22e834e45b 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -98,6 +98,8 @@ struct Creature bool mIsDeleted; + Creature(); + const std::vector& getTransport() const; void load(ESMReader &esm); diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 77a04ca013..667afc75c6 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -13,125 +13,128 @@ namespace ESM { unsigned int Dialogue::sRecordId = REC_DIAL; -void Dialogue::load(ESMReader &esm) -{ - mIsDeleted = false; + Dialogue::Dialogue() + : mIsDeleted(false) + {} - mId = esm.getHNString("NAME"); - esm.getSubNameIs("DATA"); - esm.getSubHeader(); - int si = esm.getSubSize(); - if (si == 1) - esm.getT(mType); - else if (si == 4) // The dialogue is deleted + void Dialogue::load(ESMReader &esm) { - int32_t empty; - esm.getT(empty); // Skip an empty DATA - mIsDeleted = readDeleSubRecord(esm); - } - else - esm.fail("Unknown sub record size"); -} + mIsDeleted = false; -void Dialogue::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) - { - esm.writeHNT("DATA", static_cast(0)); - writeDeleSubRecord(esm); - } - else - { - esm.writeHNT("DATA", mType); - } -} - -void Dialogue::blank() -{ - mInfo.clear(); -} - -void Dialogue::readInfo(ESMReader &esm, bool merge) -{ - const std::string& id = esm.getHNOString("INAM"); - - if (!merge || mInfo.empty()) - { - ESM::DialInfo info; - info.mId = id; - info.load(esm); - mLookup[id] = mInfo.insert(mInfo.end(), info); - return; - } - - ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); - - std::map::iterator lookup; - - lookup = mLookup.find(id); - - ESM::DialInfo info; - if (lookup != mLookup.end()) - { - it = lookup->second; - - // Merge with existing record. Only the subrecords that are present in - // the new record will be overwritten. - it->load(esm); - info = *it; - - // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record - mInfo.erase(it); - mLookup.erase(lookup); - } - else - { - info.mId = id; - info.load(esm); - } - - if (info.mNext.empty()) - { - mLookup[id] = mInfo.insert(mInfo.end(), info); - return; - } - if (info.mPrev.empty()) - { - mLookup[id] = mInfo.insert(mInfo.begin(), info); - return; - } - - lookup = mLookup.find(info.mPrev); - if (lookup != mLookup.end()) - { - it = lookup->second; - - mLookup[id] = mInfo.insert(++it, info); - return; - } - - lookup = mLookup.find(info.mNext); - if (lookup != mLookup.end()) - { - it = lookup->second; - - mLookup[id] = mInfo.insert(it, info); - return; - } - - std::cerr << "Failed to insert info " << id << std::endl; -} - -void Dialogue::clearDeletedInfos() -{ - for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) - { - if (it->mQuestStatus == DialInfo::QS_Deleted) - it = mInfo.erase(it); + mId = esm.getHNString("NAME"); + esm.getSubNameIs("DATA"); + esm.getSubHeader(); + int si = esm.getSubSize(); + if (si == 1) + esm.getT(mType); + else if (si == 4) // The dialogue is deleted + { + int32_t empty; + esm.getT(empty); // Skip an empty DATA + mIsDeleted = readDeleSubRecord(esm); + } else - ++it; + esm.fail("Unknown sub record size"); + } + + void Dialogue::save(ESMWriter &esm) const + { + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + esm.writeHNT("DATA", static_cast(0)); + writeDeleSubRecord(esm); + } + else + { + esm.writeHNT("DATA", mType); + } + } + + void Dialogue::blank() + { + mInfo.clear(); + } + + void Dialogue::readInfo(ESMReader &esm, bool merge) + { + const std::string& id = esm.getHNOString("INAM"); + + if (!merge || mInfo.empty()) + { + ESM::DialInfo info; + info.mId = id; + info.load(esm); + mLookup[id] = mInfo.insert(mInfo.end(), info); + return; + } + + ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); + + std::map::iterator lookup; + + lookup = mLookup.find(id); + + ESM::DialInfo info; + if (lookup != mLookup.end()) + { + it = lookup->second; + + // Merge with existing record. Only the subrecords that are present in + // the new record will be overwritten. + it->load(esm); + info = *it; + + // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record + mInfo.erase(it); + mLookup.erase(lookup); + } + else + { + info.mId = id; + info.load(esm); + } + + if (info.mNext.empty()) + { + mLookup[id] = mInfo.insert(mInfo.end(), info); + return; + } + if (info.mPrev.empty()) + { + mLookup[id] = mInfo.insert(mInfo.begin(), info); + return; + } + + lookup = mLookup.find(info.mPrev); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[id] = mInfo.insert(++it, info); + return; + } + + lookup = mLookup.find(info.mNext); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[id] = mInfo.insert(it, info); + return; + } + + std::cerr << "Failed to insert info " << id << std::endl; + } + + void Dialogue::clearDeletedInfos() + { + for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) + { + if (it->mQuestStatus == DialInfo::QS_Deleted) + it = mInfo.erase(it); + else + ++it; + } } } - -} diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index ab8cf4bff0..5e7d098716 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -47,6 +47,8 @@ struct Dialogue bool mIsDeleted; + Dialogue(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 6ee43fd1ac..87382fa7b1 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; + Door::Door() + : mIsDeleted(false) + {} + void Door::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index b0326a744a..546471ed3d 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -19,6 +19,8 @@ struct Door bool mIsDeleted; + Door(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 88d9e0f2e4..1518e0385a 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -9,51 +9,55 @@ namespace ESM { unsigned int Enchantment::sRecordId = REC_ENCH; -void Enchantment::load(ESMReader &esm) -{ - mEffects.mList.clear(); + Enchantment::Enchantment() + : mIsDeleted(false) + {} - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void Enchantment::load(ESMReader &esm) { - return; - } + mEffects.mList.clear(); - bool hasData = false; - while (esm.hasMoreSubs()) - { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'E','N','D','T'>::value: - esm.getHT(mData, 16); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - mEffects.add(esm); - break; - default: - esm.fail("Unknown subrecord"); - break; + return; } - } - if (!hasData) - esm.fail("Missing ENDT subrecord"); -} -void Enchantment::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); + } + + void Enchantment::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; - } + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } - esm.writeHNT("ENDT", mData, 16); - mEffects.save(esm); -} + esm.writeHNT("ENDT", mData, 16); + mEffects.save(esm); + } void Enchantment::blank() { diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index c9b19e31b3..6ebe8e9405 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -44,6 +44,8 @@ struct Enchantment bool mIsDeleted; + Enchantment(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 9149c2a30e..53f3aa5a6c 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -11,6 +11,10 @@ namespace ESM { unsigned int Faction::sRecordId = REC_FACT; + Faction::Faction() + : mIsDeleted(false) + {} + int& Faction::FADTstruct::getSkill (int index, bool ignored) { if (index<0 || index>=7) @@ -27,82 +31,83 @@ namespace ESM return mSkills[index]; } -void Faction::load(ESMReader &esm) -{ - mReactions.clear(); - for (int i=0;i<10;++i) - mRanks[i].clear(); - - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + void Faction::load(ESMReader &esm) { - return; + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); + + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) + { + return; + } + + int rankCounter=0; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing FADT subrecord"); } - int rankCounter=0; - bool hasData = false; - while (esm.hasMoreSubs()) + void Faction::save(ESMWriter &esm) const { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); + writeDeleSubRecord(esm); + return; + } + + esm.writeHNOCString("FNAM", mName); + + for (int i = 0; i < 10; i++) + { + if (mRanks[i].empty()) break; - case ESM::FourCC<'R','N','A','M'>::value: - if (rankCounter >= 10) - esm.fail("Rank out of range"); - mRanks[rankCounter++] = esm.getHString(); - break; - case ESM::FourCC<'F','A','D','T'>::value: - esm.getHT(mData, 240); - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - hasData = true; - break; - case ESM::FourCC<'A','N','A','M'>::value: - { - std::string faction = esm.getHString(); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; - break; - } - default: - esm.fail("Unknown subrecord"); + + esm.writeHNString("RNAM", mRanks[i], 32); + } + + esm.writeHNT("FADT", mData, 240); + + for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) + { + esm.writeHNString("ANAM", it->first); + esm.writeHNT("INTV", it->second); } } - if (!hasData) - esm.fail("Missing FADT subrecord"); -} -void Faction::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) - { - writeDeleSubRecord(esm); - return; - } - - esm.writeHNOCString("FNAM", mName); - - for (int i = 0; i < 10; i++) - { - if (mRanks[i].empty()) - break; - - esm.writeHNString("RNAM", mRanks[i], 32); - } - - esm.writeHNT("FADT", mData, 240); - - for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) - { - esm.writeHNString("ANAM", it->first); - esm.writeHNT("INTV", it->second); - } -} void Faction::blank() { diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index fec13b1ca0..96c02028ba 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -64,6 +64,8 @@ struct Faction bool mIsDeleted; + Faction(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 6cc37d675b..392df02b54 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Global::sRecordId = REC_GLOB; + Global::Global() + : mIsDeleted(false) + {} + void Global::load (ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 45b47a3bc9..c0219c0bac 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -26,6 +26,8 @@ struct Global bool mIsDeleted; + Global(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 3b5e0ea3a2..4c997213a0 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -9,170 +9,174 @@ namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; -void DialInfo::load(ESMReader &esm) -{ - mQuestStatus = QS_None; - mFactionLess = false; + DialInfo::DialInfo() + : mIsDeleted(false) + {} - mPrev = esm.getHNString("PNAM"); - mNext = esm.getHNString("NNAM"); - - // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings - mSelects.clear(); - - // If the info is deleted, NAME and DELE sub-records are followed after NNAM - if (esm.isNextSub("NAME")) + void DialInfo::load(ESMReader &esm) { - mResponse = esm.getHString(); - mIsDeleted = readDeleSubRecord(esm); - return; - } + mQuestStatus = QS_None; + mFactionLess = false; - esm.getSubNameIs("DATA"); - esm.getHT(mData, 12); + mPrev = esm.getHNString("PNAM"); + mNext = esm.getHNString("NNAM"); - if (!esm.hasMoreSubs()) - return; + // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings + mSelects.clear(); - // What follows is somewhat spaghetti-ish, but it's worth if for - // an extra speedup. INFO is by far the most common record type. - - // subName is a reference to the original, so it changes whenever - // a new sub name is read. esm.isEmptyOrGetName() will get the - // next name for us, or return true if there are no more records. - esm.getSubName(); - const NAME &subName = esm.retSubName(); - - if (subName.val == REC_ONAM) - { - mActor = esm.getHString(); - if (esm.isEmptyOrGetName()) + // If the info is deleted, NAME and DELE sub-records are followed after NNAM + if (esm.isNextSub("NAME")) + { + mResponse = esm.getHString(); + mIsDeleted = readDeleSubRecord(esm); return; - } - if (subName.val == REC_RNAM) - { - mRace = esm.getHString(); - if (esm.isEmptyOrGetName()) + } + + esm.getSubNameIs("DATA"); + esm.getHT(mData, 12); + + if (!esm.hasMoreSubs()) return; + + // What follows is somewhat spaghetti-ish, but it's worth if for + // an extra speedup. INFO is by far the most common record type. + + // subName is a reference to the original, so it changes whenever + // a new sub name is read. esm.isEmptyOrGetName() will get the + // next name for us, or return true if there are no more records. + esm.getSubName(); + const NAME &subName = esm.retSubName(); + + if (subName.val == REC_ONAM) + { + mActor = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_RNAM) + { + mRace = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_CNAM) + { + mClass = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_FNAM) + { + mFaction = esm.getHString(); + if (mFaction == "FFFF") + mFactionLess = true; + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_ANAM) + { + mCell = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_DNAM) + { + mPcFaction = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_SNAM) + { + mSound = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_NAME) + { + mResponse = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + while (subName.val == REC_SCVR) + { + SelectStruct ss; + + ss.mSelectRule = esm.getHString(); + + ss.mValue.read (esm, Variant::Format_Info); + + mSelects.push_back(ss); + + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_BNAM) + { + mResultScript = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_QSTN) + mQuestStatus = QS_Name; + else if (subName.val == REC_QSTF) + mQuestStatus = QS_Finished; + else if (subName.val == REC_QSTR) + mQuestStatus = QS_Restart; + else if (subName.val == REC_DELE) + mQuestStatus = QS_Deleted; + else + esm.fail( + "Don't know what to do with " + subName.toString() + + " in INFO " + mId); + + if (mQuestStatus != QS_None) + // Skip rest of record + esm.skipRecord(); } - if (subName.val == REC_CNAM) + + void DialInfo::save(ESMWriter &esm) const { - mClass = esm.getHString(); - if (esm.isEmptyOrGetName()) + esm.writeHNCString("PNAM", mPrev); + esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) + { + esm.writeHNCString("NAME", mResponse); + writeDeleSubRecord(esm); return; + } + + esm.writeHNT("DATA", mData, 12); + esm.writeHNOCString("ONAM", mActor); + esm.writeHNOCString("RNAM", mRace); + esm.writeHNOCString("CNAM", mClass); + esm.writeHNOCString("FNAM", mFaction); + esm.writeHNOCString("ANAM", mCell); + esm.writeHNOCString("DNAM", mPcFaction); + esm.writeHNOCString("SNAM", mSound); + esm.writeHNOString("NAME", mResponse); + + for (std::vector::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it) + { + esm.writeHNString("SCVR", it->mSelectRule); + it->mValue.write (esm, Variant::Format_Info); + } + + esm.writeHNOString("BNAM", mResultScript); + + switch(mQuestStatus) + { + case QS_Name: esm.writeHNT("QSTN",'\1'); break; + case QS_Finished: esm.writeHNT("QSTF", '\1'); break; + case QS_Restart: esm.writeHNT("QSTR", '\1'); break; + case QS_Deleted: esm.writeHNT("DELE", '\1'); break; + default: break; + } } - if (subName.val == REC_FNAM) - { - mFaction = esm.getHString(); - if (mFaction == "FFFF") - mFactionLess = true; - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_ANAM) - { - mCell = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_DNAM) - { - mPcFaction = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_SNAM) - { - mSound = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_NAME) - { - mResponse = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - while (subName.val == REC_SCVR) - { - SelectStruct ss; - - ss.mSelectRule = esm.getHString(); - - ss.mValue.read (esm, Variant::Format_Info); - - mSelects.push_back(ss); - - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_BNAM) - { - mResultScript = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_QSTN) - mQuestStatus = QS_Name; - else if (subName.val == REC_QSTF) - mQuestStatus = QS_Finished; - else if (subName.val == REC_QSTR) - mQuestStatus = QS_Restart; - else if (subName.val == REC_DELE) - mQuestStatus = QS_Deleted; - else - esm.fail( - "Don't know what to do with " + subName.toString() - + " in INFO " + mId); - - if (mQuestStatus != QS_None) - // Skip rest of record - esm.skipRecord(); -} - -void DialInfo::save(ESMWriter &esm) const -{ - esm.writeHNCString("PNAM", mPrev); - esm.writeHNCString("NNAM", mNext); - if (mIsDeleted) - { - esm.writeHNCString("NAME", mResponse); - writeDeleSubRecord(esm); - return; - } - - esm.writeHNT("DATA", mData, 12); - esm.writeHNOCString("ONAM", mActor); - esm.writeHNOCString("RNAM", mRace); - esm.writeHNOCString("CNAM", mClass); - esm.writeHNOCString("FNAM", mFaction); - esm.writeHNOCString("ANAM", mCell); - esm.writeHNOCString("DNAM", mPcFaction); - esm.writeHNOCString("SNAM", mSound); - esm.writeHNOString("NAME", mResponse); - - for (std::vector::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it) - { - esm.writeHNString("SCVR", it->mSelectRule); - it->mValue.write (esm, Variant::Format_Info); - } - - esm.writeHNOString("BNAM", mResultScript); - - switch(mQuestStatus) - { - case QS_Name: esm.writeHNT("QSTN",'\1'); break; - case QS_Finished: esm.writeHNT("QSTF", '\1'); break; - case QS_Restart: esm.writeHNT("QSTR", '\1'); break; - case QS_Deleted: esm.writeHNT("DELE", '\1'); break; - default: break; - } -} - void DialInfo::blank() { mData.mUnknown1 = 0; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 8b4fae761f..fbb7e36a5f 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -108,6 +108,8 @@ struct DialInfo bool mIsDeleted; + DialInfo(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 8bf0278f7a..a7018b36db 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; + Ingredient::Ingredient() + : mIsDeleted(false) + {} + void Ingredient::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 69a6501800..c92f28f183 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -33,6 +33,8 @@ struct Ingredient bool mIsDeleted; + Ingredient(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index c8cb110a6e..1e07086bcd 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,6 +7,9 @@ namespace ESM { + LevelledListBase::LevelledListBase() + : mIsDeleted(false) + {} void LevelledListBase::load(ESMReader &esm) { diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 4165275b21..14ebc99370 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -38,6 +38,8 @@ struct LevelledListBase bool mIsDeleted; + LevelledListBase(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index bd91e096ce..a153d500a0 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; + Light::Light() + : mIsDeleted(false) + {} + void Light::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 76274e6f4e..d4d3418d87 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -49,6 +49,8 @@ struct Light bool mIsDeleted; + Light(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index c1e866b585..3b169af33e 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; + Lockpick::Lockpick() + : mIsDeleted(false) + {} + void Lockpick::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index af18773ed8..ce7de2c06d 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -29,6 +29,8 @@ struct Lockpick bool mIsDeleted; + Lockpick(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 0ee30b11cd..13315e6848 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -9,29 +9,32 @@ namespace ESM { unsigned int LandTexture::sRecordId = REC_LTEX; -void LandTexture::load(ESMReader &esm) -{ - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - esm.getHNT(mIndex, "INTV"); - mTexture = esm.getHNString("DATA"); -} -void LandTexture::save(ESMWriter &esm) const -{ - if (mIsDeleted) + LandTexture::LandTexture() + : mIsDeleted(false) + {} + + void LandTexture::load(ESMReader &esm) { - writeDeleSubRecord(esm); + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + esm.getHNT(mIndex, "INTV"); + mTexture = esm.getHNString("DATA"); + } + void LandTexture::save(ESMWriter &esm) const + { + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNCString("NAME", mId); + esm.writeHNT("INTV", mIndex); + esm.writeHNCString("DATA", mTexture); } - esm.writeHNCString("NAME", mId); - esm.writeHNT("INTV", mIndex); - esm.writeHNCString("DATA", mTexture); -} - -void LandTexture::blank() -{ - mTexture.clear(); - mIndex = -1; - mIsDeleted = false; -} + void LandTexture::blank() + { + mTexture.clear(); + mIndex = -1; + mIsDeleted = false; + } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index e019e269e1..33af776120 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -36,11 +36,13 @@ struct LandTexture bool mIsDeleted; - void blank(); - ///< Set record to default state (does not touch the ID). + LandTexture(); void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); + ///< Set record to default state (does not touch the ID). }; } #endif diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 11d2f2a058..08cbcf7414 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; + Miscellaneous::Miscellaneous() + : mIsDeleted(false) + {} + void Miscellaneous::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 5d5e9f66f7..82018cd72d 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -34,6 +34,8 @@ struct Miscellaneous bool mIsDeleted; + Miscellaneous(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 280db07911..eadf23a21a 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; + NPC::NPC() + : mIsDeleted(false) + {} + void NPC::load(ESMReader &esm) { mPersistent = (esm.getRecordFlags() & 0x0400) != 0; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 7b75cb178a..2637527522 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -132,6 +132,8 @@ struct NPC bool mIsDeleted; + NPC(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 12f7ad00a6..f5287f9869 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; + Probe::Probe() + : mIsDeleted(false) + {} + void Probe::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index 9daab6b1ba..748d498fc6 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -29,6 +29,8 @@ struct Probe bool mIsDeleted; + Probe(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b0adc6f58e..2d99947b0c 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -9,69 +9,74 @@ namespace ESM { unsigned int Region::sRecordId = REC_REGN; -void Region::load(ESMReader &esm) -{ - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - mName = esm.getHNOString("FNAM"); + Region::Region() + : mIsDeleted(false) + {} - esm.getSubNameIs("WEAT"); - esm.getSubHeader(); - if (esm.getVer() == VER_12) + void Region::load(ESMReader &esm) { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData) - 2); - } - else if (esm.getVer() == VER_13) - { - // May include the additional two bytes (but not necessarily) - if (esm.getSubSize() == sizeof(mData)) - esm.getExact(&mData, sizeof(mData)); - else + mIsDeleted = readDeleSubRecord(esm); + mId = esm.getHNString("NAME"); + mName = esm.getHNOString("FNAM"); + + esm.getSubNameIs("WEAT"); + esm.getSubHeader(); + if (esm.getVer() == VER_12) { mData.mA = 0; mData.mB = 0; - esm.getExact(&mData, sizeof(mData)-2); + esm.getExact(&mData, sizeof(mData) - 2); + } + else if (esm.getVer() == VER_13) + { + // May include the additional two bytes (but not necessarily) + if (esm.getSubSize() == sizeof(mData)) + esm.getExact(&mData, sizeof(mData)); + else + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData)-2); + } + } + else + esm.fail("Don't know what to do in this version"); + + mSleepList = esm.getHNOString("BNAM"); + + esm.getHNT(mMapColor, "CNAM"); + + mSoundList.clear(); + while (esm.hasMoreSubs()) + { + SoundRef sr; + esm.getHNT(sr, "SNAM", 33); + mSoundList.push_back(sr); } } - else - esm.fail("Don't know what to do in this version"); - mSleepList = esm.getHNOString("BNAM"); - - esm.getHNT(mMapColor, "CNAM"); - - mSoundList.clear(); - while (esm.hasMoreSubs()) + void Region::save(ESMWriter &esm) const { - SoundRef sr; - esm.getHNT(sr, "SNAM", 33); - mSoundList.push_back(sr); - } -} -void Region::save(ESMWriter &esm) const -{ - if (mIsDeleted) - { - writeDeleSubRecord(esm); - } - esm.writeHNString("NAME", mId); - esm.writeHNOCString("FNAM", mName); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } + esm.writeHNString("NAME", mId); + esm.writeHNOCString("FNAM", mName); - if (esm.getVersion() == VER_12) - esm.writeHNT("WEAT", mData, sizeof(mData) - 2); - else - esm.writeHNT("WEAT", mData); + if (esm.getVersion() == VER_12) + esm.writeHNT("WEAT", mData, sizeof(mData) - 2); + else + esm.writeHNT("WEAT", mData); - esm.writeHNOCString("BNAM", mSleepList); + esm.writeHNOCString("BNAM", mSleepList); - esm.writeHNT("CNAM", mMapColor); - for (std::vector::const_iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) - { - esm.writeHNT("SNAM", *it); + esm.writeHNT("CNAM", mMapColor); + for (std::vector::const_iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) + { + esm.writeHNT("SNAM", *it); + } } -} void Region::blank() { diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 921ab887b6..9082437fed 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -53,6 +53,8 @@ struct Region bool mIsDeleted; + Region(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 608536f02b..fb213efd83 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -9,62 +9,66 @@ namespace ESM { unsigned int Repair::sRecordId = REC_REPA; -void Repair::load(ESMReader &esm) -{ - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + Repair::Repair() + : mIsDeleted(false) + {} - bool hasData = true; - while (esm.hasMoreSubs()) + void Repair::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mId = esm.getHNString("NAME"); + if (mIsDeleted = readDeleSubRecord(esm)) { - case ESM::FourCC<'M','O','D','L'>::value: - mModel = esm.getHString(); - break; - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'R','I','D','T'>::value: - esm.getHT(mData, 16); - hasData = true; - break; - case ESM::FourCC<'S','C','R','I'>::value: - mScript = esm.getHString(); - break; - case ESM::FourCC<'I','T','E','X'>::value: - mIcon = esm.getHString(); - break; - default: - esm.fail("Unknown subrecord"); + return; } - } - if (!hasData) - esm.fail("Missing RIDT subrecord"); -} -void Repair::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - if (mIsDeleted) + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); + } + + void Repair::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - return; + esm.writeHNCString("NAME", mId); + if (mIsDeleted) + { + writeDeleSubRecord(esm); + return; + } + + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + + esm.writeHNT("RIDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); } - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - - esm.writeHNT("RIDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} - void Repair::blank() { mData.mWeight = 0; diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index a660574be0..1448f9c772 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -29,6 +29,8 @@ struct Repair bool mIsDeleted; + Repair(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 67c1b8f6ff..529f0a66d4 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -9,9 +9,12 @@ namespace ESM { - unsigned int Script::sRecordId = REC_SCPT; + Script::Script() + : mIsDeleted(false) + {} + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 401dfe1050..58b5842e83 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -52,6 +52,8 @@ public: bool mIsDeleted; + Script(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index f92c4eee83..261087be05 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; + SoundGenerator::SoundGenerator() + : mIsDeleted(false) + {} + void SoundGenerator::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index e486976f51..13eb180723 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -38,6 +38,8 @@ struct SoundGenerator bool mIsDeleted; + SoundGenerator(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 19e8a5d804..9a1a52b1e5 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; + Sound::Sound() + : mIsDeleted(false) + {} + void Sound::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 95c89b29d3..0b40ae7514 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -25,6 +25,8 @@ struct Sound bool mIsDeleted; + Sound(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index cac06b2001..d2d8c7d6df 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; + Spell::Spell() + : mIsDeleted(false) + {} + void Spell::load(ESMReader &esm) { mEffects.mList.clear(); diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 2aba131add..327e94d8f8 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -47,6 +47,8 @@ struct Spell bool mIsDeleted; + Spell(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index a49caba897..2fde46bd2b 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; + Static::Static() + : mIsDeleted(false) + {} + void Static::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index c4306ad8fd..f88ad671bd 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -30,6 +30,8 @@ struct Static bool mIsDeleted; + Static(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 66d65d0f51..38fb94adbf 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -9,6 +9,10 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; + Weapon::Weapon() + : mIsDeleted(false) + {} + void Weapon::load(ESMReader &esm) { mId = esm.getHNString("NAME"); diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 30dfbc92af..ce61eeb727 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -71,6 +71,8 @@ struct Weapon bool mIsDeleted; + Weapon(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; From f12619b86a149f17aaa136456d6fd97061fec0f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 02:34:00 +0200 Subject: [PATCH 0676/1812] Implement fStromWindSpeed (Fixes #2764) --- apps/openmw/mwworld/weather.cpp | 9 ++++++--- apps/openmw/mwworld/weather.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36e..2d2b3e20d1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -66,6 +66,10 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; + bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); if (usesPrecip) weather.mRainEffect = "meshes\\raindrop.nif"; @@ -79,7 +83,6 @@ Rain Height Max=700 ? Rain Threshold=0.6 ? Max Raindrops=650 ? */ - weather.mIsStorm = (name == "ashstorm" || name == "blight"); mWeatherSettings[name] = weather; } @@ -112,8 +115,8 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang return 1.f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d7dfee99b9..efe69f17cb 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -156,7 +156,8 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); + // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time + WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); ~WeatherManager(); /** @@ -210,6 +211,7 @@ namespace MWWorld std::string mPlayingSoundID; MWWorld::Fallback* mFallback; + MWWorld::ESMStore* mStore; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602a..a2c7c3a791 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,8 +163,6 @@ namespace MWWorld mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); @@ -193,6 +191,8 @@ namespace MWWorld mGlobalVariables.fill (mStore); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWorldScene = new Scene(*mRendering, mPhysics); } @@ -265,7 +265,7 @@ namespace MWWorld // we don't want old weather to persist on a new game delete mWeatherManager; mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); From 72686c32ae18a1e5afb89478849b15bd4cfcc881 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 03:03:17 +0200 Subject: [PATCH 0677/1812] Fix runtime exceptions on MyGUI debug builds --- components/myguiplatform/myguirendermanager.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 4979d6451b..89d55f5c15 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -523,12 +523,8 @@ void RenderManager::destroyAllResources() bool RenderManager::checkTexture(MyGUI::ITexture* _texture) { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - if (item->second == _texture) - return true; - } - return false; + // We support external textures that aren't registered via this manager, so can't implement this method sensibly. + return true; } } From 12f413ba9b8c6fbbf81af8dd1a6fd4eca193eaaf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 10 Jul 2015 20:21:55 +0200 Subject: [PATCH 0678/1812] Don't instantiate specialized templates This fixes the VS2012 build issue --- apps/openmw/mwworld/store.cpp | 12 ++++++------ apps/openmw/mwworld/store.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 96c7118964..d873ab4686 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1064,11 +1064,11 @@ namespace MWWorld template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; @@ -1082,21 +1082,21 @@ template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 02fb983cda..3cbd8d3ac9 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -319,7 +319,7 @@ namespace MWWorld public: - Store(); + Store(); void setCells(Store& cells); void load(ESM::ESMReader &esm, const std::string &id); From 4b002863c899d22c2a060773e39034a69a7b3e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 00:45:11 +0200 Subject: [PATCH 0679/1812] Re-enabled a few build targets --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cbfc5d4890..a0a6f0746d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 3d3b37324d95e3e774e00db58d1e5e68e22035cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 01:38:20 +0200 Subject: [PATCH 0680/1812] Change build targets again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0a6f0746d..80277f8ba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From ebdd5dc9939b40aa3503b37dc9785b8206f810b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:06:53 +0200 Subject: [PATCH 0681/1812] Fix code that I forgot to uncomment (thanks coverity) --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6252d392bf..fc1a19391c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -459,7 +459,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = 0;//(mAmmunition.get() != NULL); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) From 667c80fb2acc4809493fc912e82a72e66797b461 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:09:50 +0200 Subject: [PATCH 0682/1812] Add brackets around a correct expression to fix coverity warning --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fc1a19391c..6417bc812c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -622,7 +622,7 @@ void NpcAnimation::updateParts() continue; } - if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) { // Allow opposite gender's parts as fallback if parts for our gender are missing BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); From 24ae1d5acea04696ee3eec79c15ec0de90a49345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:33:31 +0200 Subject: [PATCH 0683/1812] Fix some issues found by coverity --- apps/essimporter/importer.cpp | 15 +++++++++++++++ apps/essimporter/importercontext.hpp | 4 ++++ apps/openmw/mwdialogue/filter.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ apps/openmw/mwrender/ripplesimulation.hpp | 1 - components/myguiplatform/myguirendermanager.cpp | 2 +- components/nifosg/controller.cpp | 3 ++- 7 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 32ad1816cf..27b70a06ec 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -166,7 +166,9 @@ namespace ESSImport if (i >= file2.mRecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -174,7 +176,9 @@ namespace ESSImport if (rec.mName != rec2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl; + std::cout.flags(f); return; // TODO: try to recover } @@ -185,7 +189,9 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -193,8 +199,10 @@ namespace ESSImport if (sub.mName != sub2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; + std::cout.flags(f); break; // TODO: try to recover } @@ -203,6 +211,8 @@ namespace ESSImport if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end()) continue; + std::ios::fmtflags f(std::cout.flags()); + std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; @@ -235,6 +245,7 @@ namespace ESSImport std::cout << "\033[0m"; } std::cout << std::endl; + std::cout.flags(f); } } } @@ -319,7 +330,11 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) + { + std::ios::fmtflags f(std::cout.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; + std::cout.flags(f); + } esm.skipRecord(); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 3b010cb8ff..c93dff269d 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -49,6 +49,10 @@ namespace ESSImport std::map mNpcs; Context() + : mDay(0) + , mMonth(0) + , mYear(0) + , mHour(0.f) { mPlayer.mAutoMove = 0; ESM::CellId playerCellId; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index adb7d38923..29fac1c673 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -203,6 +203,8 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c return false; // script does not have a variable of this name. int index = localDefs.getIndex (name); + if (index < 0) + return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9cf9575227..582519b190 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -896,6 +896,9 @@ namespace MWGui void WindowManager::updateMap() { + if (!mLocalMapRender) + return; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5dbb..1717cca573 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 89d55f5c15..160d659bd6 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -119,7 +119,7 @@ class Drawable : public osg::Drawable { // VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909 osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) + if (0)//bufferobject) { state->bindVertexBufferObject(bufferobject); diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5e7e55004e..83ecc0fa97 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -407,7 +407,8 @@ FlipController::FlipController(int texSlot, float delta, std::vector Date: Sat, 11 Jul 2015 04:27:35 +0200 Subject: [PATCH 0684/1812] Fix cout/cerr mixup --- apps/essimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 27b70a06ec..624241039d 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -331,9 +331,9 @@ namespace ESSImport { if (unknownRecords.insert(n.val).second) { - std::ios::fmtflags f(std::cout.flags()); + std::ios::fmtflags f(std::cerr.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; - std::cout.flags(f); + std::cerr.flags(f); } esm.skipRecord(); From b97a4cee44676ec44934dac69b1e16d2370492c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 11 Jul 2015 16:09:13 +0200 Subject: [PATCH 0685/1812] added button bar to script subview --- apps/opencs/view/world/scriptsubview.cpp | 61 ++++++++++++++++++------ apps/opencs/view/world/scriptsubview.hpp | 7 +++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 411eb3660d..dc079c3a9f 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -15,26 +15,20 @@ #include "../../model/settings/usersettings.hpp" #include "scriptedit.hpp" +#include "recordbuttonbar.hpp" CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0) +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), + mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { + std::vector selection (1, id.getId()); + mCommandDispatcher.setSelection (selection); + QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); - layout->addWidget (mBottom, 0); - layout->insertWidget (0, mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); - - QWidget *widget = new QWidget; + QWidget *widget = new QWidget (this);; widget->setLayout (layout); setWidget (widget); @@ -54,6 +48,25 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // buttons + mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); + + layout->addWidget (mButtons); + + // status bar + QStatusBar *statusBar = new QStatusBar(mBottom); + mStatus = new QLabel(mBottom); + statusBar->addWidget (mStatus); + + mBottom = new QWidget(this); + QStackedLayout *bottmLayout = new QStackedLayout(mBottom); + bottmLayout->setContentsMargins (0, 0, 0, 0); + bottmLayout->addWidget (statusBar); + mBottom->setLayout (bottmLayout); + + layout->addWidget (mBottom, 0); + + // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), @@ -62,6 +75,11 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); + updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -78,6 +96,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { mEditor->setMonoFont(value.at(0).toStdString() == "true"); } + + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -93,6 +113,8 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } void CSVWorld::ScriptSubView::useHint (const std::string& hint) @@ -159,3 +181,14 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i emit closeRequest(); } +void CSVWorld::ScriptSubView::switchToRow (int row) +{ + int idColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + std::string id = mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData(); + setUniversalId (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, id)); + + mEditor->setPlainText (mModel->data (mModel->index (row, mColumn)).toString()); + + std::vector selection (1, id); + mCommandDispatcher.setSelection (selection); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 1c6474e542..0479e6ad8c 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include "../../model/world/commanddispatcher.hpp" + #include "../doc/subview.hpp" class QModelIndex; @@ -19,6 +21,7 @@ namespace CSMWorld namespace CSVWorld { class ScriptEdit; + class RecordButtonBar; class ScriptSubView : public CSVDoc::SubView { @@ -30,6 +33,8 @@ namespace CSVWorld int mColumn; QWidget *mBottom; QLabel *mStatus; + RecordButtonBar *mButtons; + CSMWorld::CommandDispatcher mCommandDispatcher; public: @@ -52,6 +57,8 @@ namespace CSVWorld private slots: void updateStatusBar(); + + void switchToRow (int row); }; } From e0983c815c32c9b79d340100ab2b4b6750820554 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 11 Jul 2015 22:17:53 +0300 Subject: [PATCH 0686/1812] Some fixes for ESM Dialogues and Infos --- apps/openmw/mwworld/store.hpp | 3 ++- components/esm/loaddial.cpp | 2 ++ components/esm/loaddial.hpp | 3 ++- components/esm/loadinfo.cpp | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index c482486d8e..ff0ca01592 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -371,7 +371,8 @@ namespace MWWorld } else { - found->second = dialogue; + found->second.mIsDeleted = dialogue.mIsDeleted; + found->second.mType = dialogue.mType; } mLastAddedRecord = dialogue; diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 667afc75c6..aeec468727 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -32,6 +32,7 @@ namespace ESM int32_t empty; esm.getT(empty); // Skip an empty DATA mIsDeleted = readDeleSubRecord(esm); + mType = Unknown; } else esm.fail("Unknown sub record size"); @@ -54,6 +55,7 @@ namespace ESM void Dialogue::blank() { mInfo.clear(); + mIsDeleted = false; } void Dialogue::readInfo(ESMReader &esm, bool merge) diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 5e7d098716..8fc7e14e95 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,7 +30,8 @@ struct Dialogue Voice = 1, Greeting = 2, Persuasion = 3, - Journal = 4 + Journal = 4, + Unknown = -1 // Used for deleted dialogues }; std::string mId; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 4c997213a0..c1b12e24c9 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -17,6 +17,7 @@ namespace ESM { mQuestStatus = QS_None; mFactionLess = false; + mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -142,6 +143,7 @@ namespace ESM { esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); + if (mIsDeleted) { esm.writeHNCString("NAME", mResponse); @@ -200,5 +202,6 @@ namespace ESM mResultScript.clear(); mFactionLess = false; mQuestStatus = QS_None; + mIsDeleted = false; } } From adec0cb61df161e4bb25d0387d7a1ecde21363cb Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 00:19:04 +0300 Subject: [PATCH 0687/1812] Add removing of deleted Infos to Dialogue::clearDeletedInfos() --- components/esm/loaddial.cpp | 2 +- components/esm/loaddial.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index aeec468727..dfac0ce637 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -133,7 +133,7 @@ namespace ESM { for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) { - if (it->mQuestStatus == DialInfo::QS_Deleted) + if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted) it = mInfo.erase(it); else ++it; diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 8fc7e14e95..e80a7b0b25 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -53,7 +53,7 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm) const; - /// Remove all INFOs marked as QS_Deleted from mInfos. + /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. void clearDeletedInfos(); /// Read the next info record From b508846a644f58264f84fb1a041f56d133260f65 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:32:48 +1200 Subject: [PATCH 0688/1812] Renamed mStoredAvailableNodes to mPopulateAvailableNodes. Don't call getAllowedNodes() needlessly. --- apps/openmw/mwmechanics/aiwander.cpp | 13 +++++++------ apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 4aef8f8ba4..3da02306b8 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -117,7 +117,7 @@ namespace MWMechanics mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } @@ -191,7 +191,7 @@ namespace MWMechanics if(!currentCell || cellChange) { currentCell = actor.getCell(); - mStoredAvailableNodes = false; // prob. not needed since mDistance = 0 + mPopulateAvailableNodes = true; } cStats.setDrawState(DrawState_Nothing); @@ -390,7 +390,7 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if(!mStoredAvailableNodes) + if (mPopulateAvailableNodes) { getAllowedNodes(actor, currentCell->getCell()); } @@ -640,7 +640,7 @@ namespace MWMechanics if (mDistance == 0) return; - if (!mStoredAvailableNodes) + if (mPopulateAvailableNodes) getAllowedNodes(actor, actor.getCell()->getCell()); if (mAllowedNodes.empty()) @@ -660,7 +660,7 @@ namespace MWMechanics actor.getClass().adjustPosition(actor, false); // may have changed cell - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } int AiWander::OffsetToPreventOvercrowding() @@ -722,8 +722,9 @@ namespace MWMechanics { SetCurrentNodeToClosestAllowedNode(npcPos); } - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } + + mPopulateAvailableNodes = false; } // When only one path grid point in wander distance, diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 926017b46a..fb1ed0b7e9 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -88,8 +88,8 @@ namespace MWMechanics - // if false triggers calculating allowed nodes based on mDistance - bool mStoredAvailableNodes; + // do we need to calculate allowed nodes based on mDistance + bool mPopulateAvailableNodes; From df421fce9265cee142eee278610f927a466b40fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:35:15 +1200 Subject: [PATCH 0689/1812] extracted function setPathToAnAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 61 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3da02306b8..17d125209f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -504,41 +504,48 @@ namespace MWMechanics // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) { - assert(mAllowedNodes.size()); - unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - ToWorldCoordinates(dest, currentCell->getCell()); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) + if (mAllowedNodes.size()) { - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): - ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); - // check if mCurrentNode was taken out of mAllowedNodes - if(mTrimCurrentNode && mAllowedNodes.size() > 1) - mTrimCurrentNode = false; - else - mAllowedNodes.push_back(mCurrentNode); - mCurrentNode = temp; - - moveNow = false; - walking = true; + setPathToAnAllowedNode(actor, storage, pos); } - // Choose a different node and delete this one from possible nodes because it is uncreachable: - else - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } } return false; // AiWander package not yet completed } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) + { + unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); + ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); + ToWorldCoordinates(dest, storage.mCell->getCell()); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + // check if mCurrentNode was taken out of mAllowedNodes + if (mTrimCurrentNode && mAllowedNodes.size() > 1) + mTrimCurrentNode = false; + else + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + storage.mMoveNow = false; + storage.mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { if (cell->isExterior()) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index fb1ed0b7e9..9f68ee1719 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -71,6 +71,7 @@ namespace MWMechanics void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); + void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ef78b1e568f21638a9c87d11e8813332841a556 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:37:31 +1200 Subject: [PATCH 0690/1812] extracted playGreetingIfPlayerGetsTooClose() --- apps/openmw/mwmechanics/aiwander.cpp | 136 ++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 17d125209f..753e6ef685 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -432,71 +432,7 @@ namespace MWMechanics // Allow interrupting a walking actor to trigger a greeting if(idleNow || walking) { - // Play a random voice greeting if the player gets too close - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = static_cast(hello); - static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() - .get().find("iGreetDistanceMultiplier")->getInt(); - - helloDistance *= iGreetDistanceMultiplier; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); - osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - float playerDistSqr = (playerPos - actorPos).length2(); - - int& greetingTimer = storage.mGreetingTimer; - if (greetingState == Greet_None) - { - if ((playerDistSqr <= helloDistance*helloDistance) && - !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) - && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) - greetingTimer++; - - if (greetingTimer >= GREETING_SHOULD_START) - { - greetingState = Greet_InProgress; - MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); - greetingTimer = 0; - } - } - - if(greetingState == Greet_InProgress) - { - greetingTimer++; - - if(walking) - { - stopWalking(actor, storage); - moveNow = false; - walking = false; - mObstacleCheck.clear(); - idleNow = true; - getRandomIdle(playedIdle); - } - - if(!rotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - targetAngleRadians = faceAngleRadians; - rotate = true; - } - - if (greetingTimer >= GREETING_SHOULD_END) - { - greetingState = Greet_Done; - greetingTimer = 0; - } - } - - if (greetingState == MWMechanics::AiWander::Greet_Done) - { - float resetDist = 2*helloDistance; - if (playerDistSqr >= resetDist*resetDist) - greetingState = Greet_None; - } + playGreetingIfPlayerGetsTooClose(actor, storage); } if(moveNow && mDistance) @@ -514,6 +450,76 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + // Play a random voice greeting if the player gets too close + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + float helloDistance = static_cast(hello); + static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore() + .get().find("iGreetDistanceMultiplier")->getInt(); + + helloDistance *= iGreetDistanceMultiplier; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + float playerDistSqr = (playerPos - actorPos).length2(); + + int& greetingTimer = storage.mGreetingTimer; + GreetingState& greetingState = storage.mSaidGreeting; + if (greetingState == Greet_None) + { + if ((playerDistSqr <= helloDistance*helloDistance) && + !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) + && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) + greetingTimer++; + + if (greetingTimer >= GREETING_SHOULD_START) + { + greetingState = Greet_InProgress; + MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); + greetingTimer = 0; + } + } + + if (greetingState == Greet_InProgress) + { + greetingTimer++; + + if (storage.mWalking) + { + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + mObstacleCheck.clear(); + storage.mIdleNow = true; + getRandomIdle(storage.mPlayedIdle); + } + + if (!storage.mRotate) + { + osg::Vec3f dir = playerPos - actorPos; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mRotate = true; + } + + if (greetingTimer >= GREETING_SHOULD_END) + { + greetingState = Greet_Done; + greetingTimer = 0; + } + } + + if (greetingState == MWMechanics::AiWander::Greet_Done) + { + float resetDist = 2 * helloDistance; + if (playerDistSqr >= resetDist*resetDist) + greetingState = Greet_None; + } + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9f68ee1719..0451ec7001 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -72,6 +72,7 @@ namespace MWMechanics bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); + void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 0b089a55640f1c1184c68cbea15a63f9303f6e69 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:38:36 +1200 Subject: [PATCH 0691/1812] extracted function evadeObstacles() --- apps/openmw/mwmechanics/aiwander.cpp | 83 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 753e6ef685..a2388320c6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -239,45 +239,7 @@ namespace MWMechanics zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - // Returns true if evasive action needs to be taken - if(mObstacleCheck.check(actor, duration)) - { - // first check if we're walking into a door - if(proximityToDoor(actor)) // NOTE: checks interior cells only - { - // remove allowed points then select another random destination - mTrimCurrentNode = true; - trimAllowedNodes(mAllowedNodes, storage.mPathFinder); - mObstacleCheck.clear(); - storage.mPathFinder.clearPath(); - walking = false; - moveNow = true; - } - else // probably walking into another NPC - { - // TODO: diagonal should have same animation as walk forward - // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); - } - mStuckCount++; // TODO: maybe no longer needed - } -//#if 0 - // TODO: maybe no longer needed - if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset - { - //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; - mObstacleCheck.clear(); - - stopWalking(actor, storage); - moveNow = false; - walking = false; - chooseAction = true; - mStuckCount = 0; - } -//#endif + evadeObstacles(actor, storage, duration); } @@ -450,6 +412,49 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + { + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + if (proximityToDoor(actor)) // NOTE: checks interior cells only + { + // remove allowed points then select another random destination + mTrimCurrentNode = true; + trimAllowedNodes(mAllowedNodes, storage.mPathFinder); + mObstacleCheck.clear(); + storage.mPathFinder.clearPath(); + storage.mWalking = false; + storage.mMoveNow = true; + } + else // probably walking into another NPC + { + // TODO: diagonal should have same animation as walk forward + // but doesn't seem to do that? + actor.getClass().getMovementSettings(actor).mPosition[0] = 1; + actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + // change the angle a bit, too + const ESM::Position& pos = actor.getRefData().getPosition(); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + } + mStuckCount++; // TODO: maybe no longer needed + } +//#if 0 + // TODO: maybe no longer needed + if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset + { + //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; + mObstacleCheck.clear(); + + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + storage.mChooseAction = true; + mStuckCount = 0; + } +//#endif + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 0451ec7001..5196bca002 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -73,6 +73,7 @@ namespace MWMechanics void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 22059d68f6e70df4cb3764a0742e172888ab4b53 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:14:48 +1200 Subject: [PATCH 0692/1812] Remove duplicated code. --- apps/openmw/mwmechanics/aiwander.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a2388320c6..a17f7a1f66 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -225,8 +225,6 @@ namespace MWMechanics storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - moveNow = false; - walking = false; chooseAction = true; mHasReturnPosition = false; } @@ -329,17 +327,8 @@ namespace MWMechanics { // End package if duration is complete or mid-night hits: MWWorld::TimeStamp currentTime = world->getTimeStamp(); - if(currentTime.getHour() >= mStartTime.getHour() + mDuration) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } - else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { if(!mRepeat) { @@ -447,8 +436,6 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; storage.mChooseAction = true; mStuckCount = 0; } @@ -494,8 +481,6 @@ namespace MWMechanics if (storage.mWalking) { stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; mObstacleCheck.clear(); storage.mIdleNow = true; getRandomIdle(storage.mPlayedIdle); @@ -601,6 +586,8 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + storage.mMoveNow = false; + storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) From e294cd95cd2cb155c5fede771592fc3c4a7eab11 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:14 +1200 Subject: [PATCH 0693/1812] extracted function playIdleDialogueRandomly() --- apps/openmw/mwmechanics/aiwander.cpp | 57 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a17f7a1f66..1375b5807a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -285,32 +285,7 @@ namespace MWMechanics } } - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && MWBase::Environment::get().getSoundManager()->sayDone(actor)) - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - float roll = Misc::Rng::rollProbability() * 10000.0f; - - // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds - // due to the roll being an integer. - // Our implementation does not have these issues, so needs to be recalibrated. We chose to - // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() - < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } + playIdleDialogueRandomly(actor); float& lastReaction = storage.mReaction; lastReaction += duration; @@ -442,6 +417,36 @@ namespace MWMechanics //#endif } + void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) + { + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) + && MWBase::Environment::get().getSoundManager()->sayDone(actor)) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + float roll = Misc::Rng::rollProbability() * 10000.0f; + + // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds + // due to the roll being an integer. + // Our implementation does not have these issues, so needs to be recalibrated. We chose to + // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + const ESM::Position& pos = actor.getRefData().getPosition(); + if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() + < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5196bca002..82baeedf36 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -74,6 +74,7 @@ namespace MWMechanics void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void playIdleDialogueRandomly(const MWWorld::Ptr& actor); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ddeabcdfbe006c2f23eb682bf8c611505a3e84f8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:41 +1200 Subject: [PATCH 0694/1812] Removed unused field that was giving compiler warning. --- apps/openmw/mwrender/ripplesimulation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5dbb..1717cca573 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; From c266315a355480ad6e4bc665e5d4150c6c8de8f3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 15:20:22 +0300 Subject: [PATCH 0695/1812] Load/read methods in MWWorld::Store return a pair (record ID, deleted flag) --- apps/openmw/mwworld/esmstore.cpp | 18 ++++----- apps/openmw/mwworld/store.cpp | 67 +++++++++++++------------------- apps/openmw/mwworld/store.hpp | 39 ++++++++----------- components/esm/util.hpp | 6 --- 4 files changed, 53 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 99d32d06b7..50324f3e8e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -96,22 +96,21 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) throw std::runtime_error(error.str()); } } else { - it->second->load(esm); - std::string id = it->second->getLastAddedRecordId(); - if (it->second->isLastAddedRecordDeleted()) + RecordId id = it->second->load(esm); + if (id.mIsDeleted) { - it->second->eraseStatic(id); + it->second->eraseStatic(id.mId); continue; } if (n.val==ESM::REC_DIAL) { - dialogue = const_cast(mDialogs.find(id)); + dialogue = const_cast(mDialogs.find(id.mId)); } else { dialogue = 0; } // Insert the reference into the global lookup - if (!id.empty() && isCacheableRecord(n.val)) { - mIds[Misc::StringUtils::lowerCase (id)] = n.val; + if (!id.mId.empty() && isCacheableRecord(n.val)) { + mIds[Misc::StringUtils::lowerCase (id.mId)] = n.val; } } listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); @@ -184,13 +183,12 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - StoreBase *store = mStores[type]; - store->read (reader); + RecordId id = mStores[type]->read (reader); // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame // that really should be cleared instead of just overwritten - mIds[store->getLastAddedRecordId()] = type; + mIds[id.mId] = type; } if (type==ESM::REC_NPC_) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index aeb96dcab4..c8c42d17db 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -44,6 +44,10 @@ namespace namespace MWWorld { + RecordId::RecordId(const std::string &id, bool isDeleted) + : mId(id), mIsDeleted(isDeleted) + {} + template IndexedStore::IndexedStore() { @@ -180,7 +184,7 @@ namespace MWWorld return ptr; } template - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { T record; record.load(esm); @@ -190,7 +194,7 @@ namespace MWWorld if (inserted.second) mShared.push_back(&inserted.first->second); - mLastAddedRecord = record; + return RecordId(record.mId, ESM::isRecordDeleted(record)); } template void Store::setUp() @@ -317,25 +321,13 @@ namespace MWWorld } } template - void Store::read(ESM::ESMReader& reader) + RecordId Store::read(ESM::ESMReader& reader) { T record; record.load (reader); insert (record); - mLastAddedRecord = record; - } - - - template - std::string Store::getLastAddedRecordId() const - { - return ESM::getRecordId(mLastAddedRecord); - } - template - bool Store::isLastAddedRecordDeleted() const - { - return ESM::isRecordDeleted(mLastAddedRecord); + return RecordId(record.mId, ESM::isRecordDeleted(record)); } // LandTexture @@ -375,7 +367,7 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].size(); } - void Store::load(ESM::ESMReader &esm, size_t plugin) + RecordId Store::load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; lt.load(esm); @@ -389,11 +381,13 @@ namespace MWWorld ltexl.resize(lt.mIndex+1); // Store it - ltexl[lt.mIndex] = mLastAddedRecord = lt; + ltexl[lt.mIndex] = lt; + + return RecordId(lt.mId, lt.mIsDeleted); } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { - load(esm, esm.getIndex()); + return load(esm, esm.getIndex()); } Store::iterator Store::begin(size_t plugin) const { @@ -405,16 +399,6 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } - - std::string Store::getLastAddedRecordId() const - { - return ESM::getRecordId(mLastAddedRecord); - } - - bool Store::isLastAddedRecordDeleted() const - { - return ESM::isRecordDeleted(mLastAddedRecord); - } // Land //========================================================================= @@ -462,7 +446,7 @@ namespace MWWorld } return ptr; } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); ptr->load(esm); @@ -480,6 +464,8 @@ namespace MWWorld } mStatic.push_back(ptr); + + return RecordId(); // No ID and can't be deleted (for now) } void Store::setUp() { @@ -622,7 +608,7 @@ namespace MWWorld mSharedExt.push_back(&(it->second)); } } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // and we merge all this data into one Cell object. However, we can't simply search for the cell id, @@ -704,6 +690,7 @@ namespace MWWorld mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; } } + return RecordId("", cell.mIsDeleted); } Store::iterator Store::intBegin() const { @@ -859,7 +846,7 @@ namespace MWWorld { mCells = &cells; } - void Store::load(ESM::ESMReader &esm) + RecordId Store::load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; pathgrid.load(esm); @@ -884,6 +871,8 @@ namespace MWWorld if (!ret.second) ret.first->second = pathgrid; } + + return RecordId(); // No ID and can't be deleted (for now) } size_t Store::getSize() const { @@ -1035,7 +1024,7 @@ namespace MWWorld } template <> - inline void Store::load(ESM::ESMReader &esm) { + inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; dialogue.load(esm); @@ -1053,7 +1042,7 @@ namespace MWWorld found->second.mType = dialogue.mType; } - mLastAddedRecord = dialogue; + return RecordId(dialogue.mId, dialogue.mIsDeleted); } @@ -1061,7 +1050,7 @@ namespace MWWorld //========================================================================= template <> - inline void Store::load(ESM::ESMReader &esm) { + inline RecordId Store::load(ESM::ESMReader &esm) { ESM::Script script; script.load(esm); Misc::StringUtils::toLower(script.mId); @@ -1072,7 +1061,7 @@ namespace MWWorld else inserted.first->second = script; - mLastAddedRecord = script; + return RecordId(script.mId, script.mIsDeleted); } @@ -1080,7 +1069,7 @@ namespace MWWorld //========================================================================= template <> - inline void Store::load(ESM::ESMReader &esm) + inline RecordId Store::load(ESM::ESMReader &esm) { ESM::StartScript script; script.load(esm); @@ -1092,7 +1081,7 @@ namespace MWWorld else inserted.first->second = script; - mLastAddedRecord = script; + return RecordId(script.mId); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 0fdfffd41d..bbbd30cd05 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,6 +19,14 @@ namespace Loading namespace MWWorld { + struct RecordId + { + std::string mId; + bool mIsDeleted; + + RecordId(const std::string &id = "", bool isDeleted = false); + }; + struct StoreBase { virtual ~StoreBase() {} @@ -28,19 +36,15 @@ namespace MWWorld virtual size_t getSize() const = 0; virtual int getDynamicSize() const { return 0; } - virtual void load(ESM::ESMReader &esm) = 0; + virtual RecordId load(ESM::ESMReader &esm) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} - virtual void read (ESM::ESMReader& reader) {} + virtual RecordId read (ESM::ESMReader& reader) { return RecordId(); } ///< Read into dynamic storage - - virtual std::string getLastAddedRecordId() const { return ""; } - ///< Returns the last loaded/read ID or empty string if a loaded record has no ID - virtual bool isLastAddedRecordDeleted() const { return false; } }; template @@ -137,8 +141,6 @@ namespace MWWorld // for heads/hairs in the character creation) std::map mDynamic; - T mLastAddedRecord; - typedef std::map Dynamic; typedef std::map Static; @@ -185,12 +187,9 @@ namespace MWWorld bool erase(const std::string &id); bool erase(const T &item); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; - void read(ESM::ESMReader& reader); - - std::string getLastAddedRecordId() const; - bool isLastAddedRecordDeleted() const; + RecordId read(ESM::ESMReader& reader); }; template <> @@ -199,7 +198,6 @@ namespace MWWorld // For multiple ESM/ESP files we need one list per file. typedef std::vector LandTextureList; std::vector mStatic; - ESM::LandTexture mLastAddedRecord; public: Store(); @@ -214,14 +212,11 @@ namespace MWWorld size_t getSize() const; size_t getSize(size_t plugin) const; - void load(ESM::ESMReader &esm, size_t plugin); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm, size_t plugin); + RecordId load(ESM::ESMReader &esm); iterator begin(size_t plugin) const; iterator end(size_t plugin) const; - - std::string getLastAddedRecordId() const; - bool isLastAddedRecordDeleted() const; }; template <> @@ -243,7 +238,7 @@ namespace MWWorld ESM::Land *search(int x, int y) const; ESM::Land *find(int x, int y) const; - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); void setUp(); }; @@ -293,7 +288,7 @@ namespace MWWorld void setUp(); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); iterator intBegin() const; iterator intEnd() const; @@ -335,7 +330,7 @@ namespace MWWorld Store(); void setCells(Store& cells); - void load(ESM::ESMReader &esm); + RecordId load(ESM::ESMReader &esm); size_t getSize() const; void setUp(); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 94a7956efb..ca6917fd1c 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -60,12 +60,6 @@ struct Vector3 bool readDeleSubRecord(ESMReader &esm); void writeDeleSubRecord(ESMWriter &esm); -template -std::string getRecordId(const RecordT &record) -{ - return record.mId; -} - template bool isRecordDeleted(const RecordT &record) { From 42f9136141657cbe3fd0801c579e37dd1ff47a30 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 15:22:51 +0300 Subject: [PATCH 0696/1812] Remove DELE and NAME handling from RefIdCollection and RefIdData --- apps/opencs/model/world/refidcollection.cpp | 56 +----------- apps/opencs/model/world/refiddata.cpp | 12 +-- apps/opencs/model/world/refiddata.hpp | 96 +++++++++++++++++---- 3 files changed, 87 insertions(+), 77 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b46..0ca050e181 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -767,61 +767,7 @@ const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (int index) con void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type) { - std::string id = reader.getHNOString ("NAME"); - - int index = searchId (id); - - if (reader.isNextSub ("DELE")) - { - reader.skipRecord(); - - if (index==-1) - { - // deleting a record that does not exist - - // ignore it for now - - /// \todo report the problem to the user - } - else if (base) - { - mData.erase (index, 1); - } - else - { - mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted; - } - } - else - { - if (index==-1) - { - // new record - int index = mData.getAppendIndex (type); - mData.appendRecord (type, id, base); - - RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - - mData.load (localIndex, reader, base); - - mData.getRecord (localIndex).mState = - base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - } - else - { - // old record - RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - - if (!base) - if (mData.getRecord (localIndex).mState==RecordBase::State_Erased) - throw std::logic_error ("attempt to access a deleted record"); - - mData.load (localIndex, reader, base); - - if (!base) - mData.getRecord (localIndex).mState = RecordBase::State_Modified; - } - } + mData.load(reader, base, type); } int CSMWorld::RefIdCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f368..68f3fc4ad6 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -161,15 +161,15 @@ int CSMWorld::RefIdData::getAppendIndex (UniversalId::Type type) const return index; } -void CSMWorld::RefIdData::load (const LocalIndex& index, ESM::ESMReader& reader, bool base) +void CSMWorld::RefIdData::load (ESM::ESMReader& reader, bool base, CSMWorld::UniversalId::Type type) { - std::map::iterator iter = - mRecordContainers.find (index.second); + std::map::iterator found = + mRecordContainers.find (type); - if (iter==mRecordContainers.end()) - throw std::logic_error ("invalid local index type"); + if (found == mRecordContainers.end()) + throw std::logic_error ("Invalid type for an Object (Reference ID)"); - iter->second->load (index.first, reader, base); + found->second->load(reader, base); } void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 85d16a6eb2..17d9139115 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -49,7 +49,7 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record) = 0; - virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; + virtual void load (ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; @@ -73,7 +73,7 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record); - virtual void load (int index, ESM::ESMReader& reader, bool base); + virtual void load (ESM::ESMReader& reader, bool base); virtual void erase (int index, int count); @@ -122,9 +122,67 @@ namespace CSMWorld } template - void RefIdDataContainer::load (int index, ESM::ESMReader& reader, bool base) + void RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { - (base ? mContainer.at (index).mBase : mContainer.at (index).mModified).load (reader); + RecordT record; + record.load(reader); + + typename std::vector >::iterator found = mContainer.begin(); + for (; found != mContainer.end(); ++found) + { + if (found->get().mId == record.mId) + { + break; + } + } + + if (record.mIsDeleted) + { + if (found == mContainer.end()) + { + // deleting a record that does not exist + // ignore it for now + /// \todo report the problem to the user + return; + } + + if (base) + { + mContainer.erase(found); + } + else + { + found->mState = RecordBase::State_Deleted; + } + } + else + { + if (found == mContainer.end()) + { + appendRecord(record.mId, base); + if (base) + { + mContainer.back().mBase = record; + } + else + { + mContainer.back().mModified = record; + } + } + else + { + if (!base) + { + if (found->mState == RecordBase::State_Erased) + { + throw std::logic_error("Attempt to access a deleted record"); + } + + found->mState = RecordBase::State_Modified; + found->mModified = record; + } + } + } } template @@ -145,20 +203,26 @@ namespace CSMWorld template void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { - CSMWorld::RecordBase::State state = mContainer.at (index).mState; + Record record = mContainer.at(index); + RecordT esmRecord; - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + switch (record.mState) { - writer.startRecord (mContainer.at (index).mModified.sRecordId); - writer.writeHNCString ("NAME", getId (index)); - mContainer.at (index).mModified.save (writer); - writer.endRecord (mContainer.at (index).mModified.sRecordId); - } - else if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + case RecordBase::State_Modified: + case RecordBase::State_ModifiedOnly: + esmRecord = record.mModified; + break; + case RecordBase::State_Deleted: + esmRecord = record.mBase; + esmRecord.mIsDeleted = true; + break; + default: + break; } + + writer.startRecord(esmRecord.sRecordId); + esmRecord.save(writer); + writer.endRecord(esmRecord.sRecordId); } @@ -220,7 +284,7 @@ namespace CSMWorld int getAppendIndex (UniversalId::Type type) const; - void load (const LocalIndex& index, ESM::ESMReader& reader, bool base); + void load (ESM::ESMReader& reader, bool base, UniversalId::Type type); int getSize() const; From 74a055f3ccbe25e50d2947d6fe639a84e3138ec7 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 10:40:11 +0300 Subject: [PATCH 0697/1812] Remove NAME and DELE handling from IdCollection --- apps/opencs/model/world/cell.cpp | 5 +- apps/opencs/model/world/data.cpp | 32 +++++------ apps/opencs/model/world/idcollection.hpp | 67 ++++++++---------------- apps/opencs/model/world/land.hpp | 10 ++++ apps/opencs/model/world/pathgrid.hpp | 10 ++++ components/esm/util.cpp | 36 +++++++++++++ components/esm/util.hpp | 24 +++++++++ 7 files changed, 118 insertions(+), 66 deletions(-) diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 40520a9ba7..8816cd35ee 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -5,16 +5,13 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm) { - mName = mId; - ESM::Cell::load (esm, false); + mId = mName; if (!(mData.mFlags & Interior)) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a92a7ad793..348656a7ca 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -988,41 +988,41 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_DIAL: { - std::string id = mReader->getHNOString ("NAME"); - ESM::Dialogue record; - record.mId = id; record.load (*mReader); - if (record.mType==ESM::Dialogue::Journal) + if (record.mIsDeleted) { - mJournals.load (record, mBase); - mDialogue = &mJournals.getRecord (id).get(); - } - else if (record.mType==ESM::Dialogue::Deleted) - { - mDialogue = 0; // record vector can be shuffled around which would make pointer - // to record invalid + // record vector can be shuffled around which would make pointer to record invalid + mDialogue = 0; - if (mJournals.tryDelete (id)) + if (mJournals.tryDelete (record.mId)) { /// \todo handle info records } - else if (mTopics.tryDelete (id)) + else if (mTopics.tryDelete (record.mId)) { /// \todo handle info records } else { messages.add (UniversalId::Type_None, - "Trying to delete dialogue record " + id + " which does not exist", + "Trying to delete dialogue record " + record.mId + " which does not exist", "", CSMDoc::Message::Severity_Warning); } } else { - mTopics.load (record, mBase); - mDialogue = &mTopics.getRecord (id).get(); + if (record.mType == ESM::Dialogue::Journal) + { + mJournals.load (record, mBase); + mDialogue = &mJournals.getRecord (record.mId).get(); + } + else + { + mTopics.load (record, mBase); + mDialogue = &mTopics.getRecord (record.mId).get(); + } } break; diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4eafc59bd5..41ce59702d 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_IDCOLLECTION_H #include +#include #include "collection.hpp" @@ -41,69 +42,43 @@ namespace CSMWorld template int IdCollection::load (ESM::ESMReader& reader, bool base) { - std::string id = reader.getHNOString ("NAME"); + ESXRecordT record; + loadRecord (record, reader); - if (reader.isNextSub ("DELE")) + std::string id = IdAccessorT().getId (record); + int index = searchId (id); + + if (ESM::isRecordDeleted (record)) { - int index = Collection::searchId (id); - - reader.skipRecord(); - if (index==-1) { // deleting a record that does not exist - // ignore it for now - /// \todo report the problem to the user + return -1; } - else if (base) + + if (base) { - Collection::removeRows (index, 1); + removeRows (index, 1); } else { - Record record = Collection::getRecord (index); - record.mState = RecordBase::State_Deleted; - this->setRecord (index, record); + Record baseRecord = getRecord (index); + baseRecord.mState = RecordBase::State_Deleted; + this->setRecord (index, baseRecord); } return -1; } - else - { - ESXRecordT record; + // + //if (index != -1) + //{ + // ESXRecordT existedRecord = getRecord(index).get(); + // IdAccessorT().getId(record) = IdAccessorT().getId(existedRecord); + //} - // Sometimes id (i.e. NAME of the cell) may be different to the id we stored - // earlier. e.g. NAME == "Vivec, Arena" but id == "#-4 11". Sometime NAME is - // missing altogether for scripts or cells. - // - // In such cases the returned index will be -1. We then try updating the - // IdAccessor's id manually (e.g. set mId of the record to "Vivec, Arena") - // and try getting the index once more after loading the record. The mId of the - // record would have changed to "#-4 11" after the load, and searchId() should find - // it (if this is a modify) - int index = this->searchId (id); - - if (index==-1) - IdAccessorT().getId (record) = id; - else - { - record = this->getRecord (index).get(); - } - - loadRecord (record, reader); - - if (index==-1) - { - std::string newId = IdAccessorT().getId(record); - int newIndex = this->searchId(newId); - if (newIndex != -1 && id != newId) - index = newIndex; - } - - return load (record, base, index); - } + return load (record, base, index); } template diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd8..adf5c03317 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace CSMWorld { @@ -26,4 +27,13 @@ namespace CSMWorld }; } +namespace ESM +{ + template <> + bool isRecordDeleted(const CSMWorld::Land &land) + { + return false; + } +} + #endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7e7b7c3bb6..cd5e472c8b 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace CSMWorld { @@ -26,4 +27,13 @@ namespace CSMWorld }; } +namespace ESM +{ + template <> + bool isRecordDeleted(const CSMWorld::Pathgrid &pgrd) + { + return false; + } +} + #endif diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 4cfe644e8f..a5ec377a31 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -36,4 +36,40 @@ namespace ESM { return false; } + + template <> + bool isRecordDeleted(const Skill &skill) + { + return false; + } + + template <> + bool isRecordDeleted(const MagicEffect &mgef) + { + return false; + } + + template <> + bool isRecordDeleted(const Pathgrid &pgrd) + { + return false; + } + + template <> + bool isRecordDeleted(const Land &land) + { + return false; + } + + template <> + bool isRecordDeleted(const DebugProfile &profile) + { + return false; + } + + template <> + bool isRecordDeleted(const Filter &filter) + { + return false; + } } diff --git a/components/esm/util.hpp b/components/esm/util.hpp index ca6917fd1c..531e7eb762 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -12,6 +12,12 @@ #include "loadglob.hpp" #include "loadrace.hpp" #include "loadgmst.hpp" +#include "loadskil.hpp" +#include "loadmgef.hpp" +#include "loadland.hpp" +#include "loadpgrd.hpp" +#include "debugprofile.hpp" +#include "filter.hpp" namespace ESM { @@ -76,6 +82,24 @@ bool isRecordDeleted(const Race &race); template <> bool isRecordDeleted(const GameSetting &gmst); +template <> +bool isRecordDeleted(const Skill &skill); + +template <> +bool isRecordDeleted(const MagicEffect &mgef); + +template <> +bool isRecordDeleted(const Pathgrid &pgrd); + +template <> +bool isRecordDeleted(const Land &land); + +template <> +bool isRecordDeleted(const DebugProfile &profile); + +template <> +bool isRecordDeleted(const Filter &filter); + } #endif From 749eff5259269a3fced49098ca39517c06f6a582 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 13 Jul 2015 09:42:16 +0200 Subject: [PATCH 0698/1812] renaming a few user settings categories --- apps/opencs/model/settings/usersettings.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85ba..11fc8bfebf 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -162,7 +162,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } - declareSection ("table-input", "Table Input"); + declareSection ("table-input", "ID Tables"); { QString inPlaceEdit ("Edit in Place"); QString editRecord ("Edit Record"); @@ -217,7 +217,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } - declareSection ("report-input", "Report Input"); + declareSection ("report-input", "Reports"); { QString none ("None"); QString edit ("Edit"); @@ -257,7 +257,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setDefaultValue (none); shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

" + toolTip); } - + declareSection ("search", "Search & Replace"); { Setting *before = createSetting (Type_SpinBox, "char-before", @@ -299,7 +299,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() QStringList modes; modes << "Ignore" << modeNormal << "Strict"; - + Setting *warnings = createSetting (Type_ComboBox, "warnings", "Warning Mode"); warnings->setDeclaredValues (modes); @@ -309,7 +309,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "

  • Normal: Report warning as a warning
  • " "
  • Strict: Promote warning to an error
  • " ""); - + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); @@ -346,7 +346,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() cycle->setToolTip ("When using next/previous functions at the last/first item of a " "list go to the first/last item"); } - + { /****************************************************************** * There are three types of values: From c8c79dc1efa5682c52ead7221628812638a55fed Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 10:53:31 +0300 Subject: [PATCH 0699/1812] Move ID loading into a separate method for Dialogue and DialInfo records --- apps/openmw/mwworld/store.cpp | 8 +++---- components/esm/loaddial.cpp | 39 ++++++++++++++++++++--------------- components/esm/loaddial.hpp | 6 ++++++ components/esm/loadinfo.cpp | 14 ++++++++++++- components/esm/loadinfo.hpp | 6 ++++++ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index c8c42d17db..8f55bb466e 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1027,19 +1027,19 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; - dialogue.load(esm); + dialogue.loadId(esm); std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); std::map::iterator found = mStatic.find(idLower); if (found == mStatic.end()) { + dialogue.loadData(esm); mStatic.insert(std::make_pair(idLower, dialogue)); } else { - // Update only read fields (don't touching the Info list) - found->second.mIsDeleted = dialogue.mIsDeleted; - found->second.mType = dialogue.mType; + found->second.loadData(esm); + dialogue = found->second; } return RecordId(dialogue.mId, dialogue.mIsDeleted); diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index dfac0ce637..fcdb57c8db 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -19,9 +19,18 @@ namespace ESM void Dialogue::load(ESMReader &esm) { - mIsDeleted = false; + loadId(esm); + loadData(esm); + } + void Dialogue::loadId(ESMReader &esm) + { + mIsDeleted = false; mId = esm.getHNString("NAME"); + } + + void Dialogue::loadData(ESMReader &esm) + { esm.getSubNameIs("DATA"); esm.getSubHeader(); int si = esm.getSubSize(); @@ -60,31 +69,28 @@ namespace ESM void Dialogue::readInfo(ESMReader &esm, bool merge) { - const std::string& id = esm.getHNOString("INAM"); + ESM::DialInfo info; + info.loadId(esm); if (!merge || mInfo.empty()) { - ESM::DialInfo info; - info.mId = id; - info.load(esm); - mLookup[id] = mInfo.insert(mInfo.end(), info); + info.loadInfo(esm); + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); return; } ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); std::map::iterator lookup; + lookup = mLookup.find(info.mId); - lookup = mLookup.find(id); - - ESM::DialInfo info; if (lookup != mLookup.end()) { it = lookup->second; // Merge with existing record. Only the subrecords that are present in // the new record will be overwritten. - it->load(esm); + it->loadInfo(esm); info = *it; // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record @@ -93,18 +99,17 @@ namespace ESM } else { - info.mId = id; - info.load(esm); + info.loadInfo(esm); } if (info.mNext.empty()) { - mLookup[id] = mInfo.insert(mInfo.end(), info); + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); return; } if (info.mPrev.empty()) { - mLookup[id] = mInfo.insert(mInfo.begin(), info); + mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); return; } @@ -113,7 +118,7 @@ namespace ESM { it = lookup->second; - mLookup[id] = mInfo.insert(++it, info); + mLookup[info.mId] = mInfo.insert(++it, info); return; } @@ -122,11 +127,11 @@ namespace ESM { it = lookup->second; - mLookup[id] = mInfo.insert(it, info); + mLookup[info.mId] = mInfo.insert(it, info); return; } - std::cerr << "Failed to insert info " << id << std::endl; + std::cerr << "Failed to insert info " << info.mId << std::endl; } void Dialogue::clearDeletedInfos() diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index e80a7b0b25..73bf169741 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -51,6 +51,12 @@ struct Dialogue Dialogue(); void load(ESMReader &esm); + ///< Loads all sub-records of Dialogue record + void loadId(ESMReader &esm); + ///< Loads NAME sub-record of Dialogue record + void loadData(ESMReader &esm); + ///< Loads all sub-records of Dialogue record, except NAME sub-record + void save(ESMWriter &esm) const; /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index c1b12e24c9..8f5f0f28b0 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -14,10 +14,21 @@ namespace ESM {} void DialInfo::load(ESMReader &esm) + { + loadId(esm); + loadInfo(esm); + } + + void DialInfo::loadId(ESMReader &esm) + { + mIsDeleted = false; + mId = esm.getHNString("INAM"); + } + + void DialInfo::loadInfo(ESMReader &esm) { mQuestStatus = QS_None; mFactionLess = false; - mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -141,6 +152,7 @@ namespace ESM void DialInfo::save(ESMWriter &esm) const { + esm.writeHNCString("INAM", mId); esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index fbb7e36a5f..c243cd50e0 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -111,6 +111,12 @@ struct DialInfo DialInfo(); void load(ESMReader &esm); + ///< Loads all sub-records of Info record + void loadId(ESMReader &esm); + ///< Loads only Id of Info record (INAM sub-record) + void loadInfo(ESMReader &esm); + ///< Loads all sub-records of Info record, except INAM sub-record + void save(ESMWriter &esm) const; void blank(); From 71e5fc7f0458f77e94879399a39e36393ed19409 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 11:19:14 +0300 Subject: [PATCH 0700/1812] Remove INAM handling from InfoCollection --- apps/opencs/model/world/infocollection.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 560be8131e..1b95c1505e 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -107,21 +107,18 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector Date: Mon, 13 Jul 2015 12:52:18 +0200 Subject: [PATCH 0701/1812] added user settings option to toggle toolbars in single-record subviews --- apps/opencs/model/settings/usersettings.cpp | 9 +++ apps/opencs/view/world/dialoguesubview.cpp | 86 ++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 16 ++-- apps/opencs/view/world/scriptsubview.cpp | 63 ++++++++++----- apps/opencs/view/world/scriptsubview.hpp | 8 ++ 5 files changed, 131 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 11fc8bfebf..673db4057a 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,6 +217,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } + declareSection ("dialogues", "ID Dialogues"); + { + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + } + declareSection ("report-input", "Reports"); { QString none ("None"); @@ -310,6 +316,9 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "
  • Strict: Promote warning to an error
  • " ""); + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ed50b81cd7..edd9cc1e28 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -31,6 +31,7 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" +#include "../../model/settings/usersettings.hpp" #include "../widget/coloreditor.hpp" #include "../widget/droplineedit.hpp" @@ -66,7 +67,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo CSMWorld::Columns::ColumnId columnId = static_cast ( mTable->getColumnId (index.column())); - + if (QVariant::String == v.type()) { label->setText(v.toString()); @@ -75,7 +76,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (columnId)); - + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } else @@ -324,11 +325,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di Q_ASSERT(mWidget != NULL); Q_ASSERT(CSMWorld::ColumnBase::isId(display)); Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); - + mWidget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(mWidget, - SIGNAL(customContextMenuRequested(const QPoint &)), - this, + connect(mWidget, + SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(showContextMenu(const QPoint &))); mEditIdAction = new QAction(this); @@ -352,7 +353,7 @@ void CSVWorld::IdContextMenu::excludeId(const std::string &id) QString CSVWorld::IdContextMenu::getWidgetValue() const { - QLineEdit *lineEdit = qobject_cast(mWidget); + QLineEdit *lineEdit = qobject_cast(mWidget); QLabel *label = qobject_cast(mWidget); QString value = ""; @@ -411,7 +412,7 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { removeEditIdActionFromMenu(); } - + if (!mContextMenu->actions().isEmpty()) { mContextMenu->exec(mWidget->mapToGlobal(pos)); @@ -588,9 +589,9 @@ void CSVWorld::EditWidget::remake(int row) tablesLayout->addWidget(label); tablesLayout->addWidget(table); - connect(table, - SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), - this, + connect(table, + SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), + this, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) @@ -830,9 +831,28 @@ void CSVWorld::SimpleDialogueSubView::updateCurrentId() } +void CSVWorld::DialogueSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), getTable(), mBottom, + &getCommandDispatcher(), this); + + getMainLayout().insertWidget (1, mButtons); + + // connections + connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) -: SimpleDialogueSubView (id, document) +: SimpleDialogueSubView (id, document), mButtons (0) { // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); @@ -843,32 +863,44 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - mButtons = new RecordButtonBar (id, getTable(), mBottom, - &getCommandDispatcher(), this); + if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true") + addButtonBar(); // layout - getMainLayout().addWidget (mButtons); getMainLayout().addWidget (mBottom); - - // connections - connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); - connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } void CSVWorld::DialogueSubView::setEditLock (bool locked) { SimpleDialogueSubView::setEditLock (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); } void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) { SimpleDialogueSubView::updateUserSetting (name, value); - mButtons->updateUserSetting (name, value); + + if (name=="dialogues/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + getMainLayout().removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } + } + + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::DialogueSubView::showPreview () @@ -908,7 +940,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row) setUniversalId (CSMWorld::UniversalId (type, id)); updateCurrentId(); - + getEditWidget().remake (row); int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification); @@ -923,5 +955,5 @@ void CSVWorld::DialogueSubView::requestFocus (const std::string& id) QModelIndex index = getTable().getModelIndex (id, 0); if (index.isValid()) - switchToRow (index.row()); + switchToRow (index.row()); } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index d82936e459..2ae0f97203 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,8 +195,8 @@ namespace CSVWorld CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor - void createEditorContextMenu(QWidget *editor, - CSMWorld::ColumnBase::Display display, + void createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, int currentRow) const; public: @@ -236,7 +236,7 @@ namespace CSVWorld void updateCurrentId(); bool isLocked() const; - + public: SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -256,10 +256,14 @@ namespace CSVWorld class DialogueSubView : public SimpleDialogueSubView { Q_OBJECT - + TableBottomBox* mBottom; RecordButtonBar *mButtons; + private: + + void addButtonBar(); + public: DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, @@ -268,14 +272,14 @@ namespace CSVWorld virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString& name, const QStringList& value); - + private slots: void showPreview(); void viewRecord(); - void switchToRow (int row); + void switchToRow (int row); void requestFocus (const std::string& id); }; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dc079c3a9f..0f5d5014a8 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -17,19 +17,32 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +void CSVWorld::ScriptSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + + mLayout.insertWidget (1, mButtons); + + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - QVBoxLayout *layout = new QVBoxLayout; - - layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); QWidget *widget = new QWidget (this);; - widget->setLayout (layout); + widget->setLayout (&mLayout); setWidget (widget); mModel = &dynamic_cast ( @@ -49,9 +62,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); // buttons - mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); - - layout->addWidget (mButtons); + if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") + addButtonBar(); // status bar QStatusBar *statusBar = new QStatusBar(mBottom); @@ -64,7 +76,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: bottmLayout->addWidget (statusBar); mBottom->setLayout (bottmLayout); - layout->addWidget (mBottom, 0); + mLayout.addWidget (mBottom, 0); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -75,11 +87,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); - updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -88,16 +95,33 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { if (name == "script-editor/show-linenum") { - std::string showLinenum = value.at(0).toStdString(); + std::string showLinenum = value.at(0).toUtf8().constData(); mEditor->showLineNum(showLinenum == "true"); mBottom->setVisible(showLinenum == "true"); } else if (name == "script-editor/mono-font") { - mEditor->setMonoFont(value.at(0).toStdString() == "true"); + mEditor->setMonoFont (value.at(0)==QString ("true")); + } + else if (name=="script-editor/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + mLayout.removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } } - mButtons->updateUserSetting (name, value); + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -113,7 +137,10 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0479e6ad8c..370754ebe7 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,12 +1,15 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include + #include "../../model/world/commanddispatcher.hpp" #include "../doc/subview.hpp" class QModelIndex; class QLabel; +class QVBoxLayout; namespace CSMDoc { @@ -35,6 +38,11 @@ namespace CSVWorld QLabel *mStatus; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; + QVBoxLayout mLayout; + + private: + + void addButtonBar(); public: From 5a0af772dda52209ffe92b26bbfbb6aa4e1ea68a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 17:40:03 +0200 Subject: [PATCH 0702/1812] Update README.md - Remove "an attempt at". I think we are far enough into the project to say that the "attempt" has been successful, at least to a degree. ;) - Added Current Status section. - Added line about OpenMW-CS. --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f62800e1fd..5b986e0075 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ OpenMW [![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) -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. +OpenMW is a recreation of 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. + +OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. * Version: 0.36.0 * License: GPL (see docs/license/GPL3.txt for more information) @@ -14,6 +15,13 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) +Current Status +-------------- + +The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. + +Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page. + Getting Started --------------- From f1b52c964a2da506aefdc7b404bd00fee766b273 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:00:41 +0200 Subject: [PATCH 0703/1812] Select the current resolution in resolution list on game start (Fixes #2768) --- apps/openmw/mwgui/settingswindow.cpp | 21 +++++++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 1 + 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index df5aa1a407..3ab2a6ce3f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -233,6 +233,7 @@ namespace MWGui if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); } + highlightCurrentResolution(); std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); @@ -299,8 +300,28 @@ namespace MWGui } void SettingsWindow::onResolutionCancel() + { + highlightCurrentResolution(); + } + + void SettingsWindow::highlightCurrentResolution() { mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); + + int currentX = Settings::Manager::getInt("resolution x", "Video"); + int currentY = Settings::Manager::getInt("resolution y", "Video"); + + for (size_t i=0; igetItemCount(); ++i) + { + int resX, resY; + parseResolution (resX, resY, mResolutionList->getItemNameAt(i)); + + if (resX == currentX && resY == currentY) + { + mResolutionList->setIndexSelected(i); + break; + } + } } void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 45d489284b..79487c54b8 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -59,6 +59,7 @@ namespace MWGui void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); void onResolutionAccept(); void onResolutionCancel(); + void highlightCurrentResolution(); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); From dca4704b4b665f0853917150f7902e0c29607e58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:40:05 +0200 Subject: [PATCH 0704/1812] Print exceptions in CharacterCreation::spawnDialog --- apps/openmw/mwgui/charactercreation.cpp | 241 ++++++++++++------------ 1 file changed, 124 insertions(+), 117 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 73b950a6aa..d0a0505262 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -132,134 +132,141 @@ namespace MWGui void CharacterCreation::spawnDialog(const char id) { - switch (id) + try { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; + switch (id) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(mViewer, mResourceSystem); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_ClassPick: - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_Birth: - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; - case GM_ClassCreate: - if (!mCreateClassDialog) - { - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - } - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); - - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - - mReviewDialog->setHealth ( stats.getHealth() ); - mReviewDialog->setMagicka( stats.getMagicka() ); - mReviewDialog->setFatigue( stats.getFatigue() ); - } - - { - std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map::iterator it = attributes.begin(); - it != attributes.end(); ++it) + case GM_ClassCreate: + if (!mCreateClassDialog) { - mReviewDialog->setAttribute(static_cast (it->first), it->second); + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); } - } + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); - { - std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map::iterator it = skills.begin(); - it != skills.end(); ++it) { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; + mReviewDialog->setHealth ( stats.getHealth() ); + mReviewDialog->setMagicka( stats.getMagicka() ); + mReviewDialog->setFatigue( stats.getFatigue() ); + } + + { + std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } + } + + { + std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + } + + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + catch (std::exception& e) + { + std::cerr << "Failed to create chargen window: " << e.what() << std::endl; } } From c4866bdfc63e28ceff2573dabb643fafc4283360 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 19:13:26 +0200 Subject: [PATCH 0705/1812] Disable mipmaps for GUI textures For some reason, the mipmap generator seems to be broken on Linux Intel graphics (works on Nvidia). This was breaking the scrollbar arrows, which are minified enough to show using a mipmap. --- components/myguiplatform/myguitexture.cpp | 2 ++ components/resource/texturemanager.cpp | 25 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 0a846b227d..50ac5c1f34 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -87,6 +87,8 @@ namespace osgMyGUI throw std::runtime_error("No texturemanager set"); mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); + // disable mip-maps + mTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb39..ae8d161027 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -64,7 +64,30 @@ namespace Resource for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) { osg::ref_ptr tex = it->second; - tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + + // Keep mip-mapping disabled if the texture creator explicitely requested it. + osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); + if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) + { + osg::Texture::FilterMode newMin = osg::Texture::LINEAR; + switch (mMinFilter) + { + case osg::Texture::LINEAR: + case osg::Texture::LINEAR_MIPMAP_LINEAR: + case osg::Texture::LINEAR_MIPMAP_NEAREST: + newMin = osg::Texture::LINEAR; + break; + case osg::Texture::NEAREST: + case osg::Texture::NEAREST_MIPMAP_LINEAR: + case osg::Texture::NEAREST_MIPMAP_NEAREST: + newMin = osg::Texture::NEAREST; + break; + } + tex->setFilter(osg::Texture::MIN_FILTER, newMin); + } + else + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); } From b55a4999caf2150afa6bc26d3ccc303a684131a0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 22:37:14 +0300 Subject: [PATCH 0706/1812] Add NAME handling to DebugProfile and Filter records --- components/esm/debugprofile.cpp | 2 ++ components/esm/filter.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 6c05fac2a2..9c8164d299 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -9,6 +9,7 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; void ESM::DebugProfile::load (ESMReader& esm) { + mId = esm.getHNString ("NAME"); mDescription = esm.getHNString ("DESC"); mScriptText = esm.getHNString ("SCRP"); esm.getHNT (mFlags, "FLAG"); @@ -16,6 +17,7 @@ void ESM::DebugProfile::load (ESMReader& esm) void ESM::DebugProfile::save (ESMWriter& esm) const { + esm.writeHNCString ("NAME", mId); esm.writeHNCString ("DESC", mDescription); esm.writeHNCString ("SCRP", mScriptText); esm.writeHNT ("FLAG", mFlags); diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index a80427bbed..ee2c678692 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -9,12 +9,14 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; void ESM::Filter::load (ESMReader& esm) { + mId = esm.getHNString ("NAME"); mFilter = esm.getHNString ("FILT"); mDescription = esm.getHNString ("DESC"); } void ESM::Filter::save (ESMWriter& esm) const { + esm.writeHNCString ("NAME", mId); esm.writeHNCString ("FILT", mFilter); esm.writeHNCString ("DESC", mDescription); } From de6dc21552d0a5c190f2930df6090fdaeb66dbe6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 23:36:25 +0200 Subject: [PATCH 0707/1812] Create hardware cursors in advance (Fixes #2660) --- apps/openmw/mwgui/windowmanagerimp.cpp | 56 +++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + components/sdlutil/sdlcursormanager.cpp | 13 ++---- components/sdlutil/sdlcursormanager.hpp | 6 +-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b190..a2a8261617 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -235,8 +235,9 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + // Create all cursors in advance + createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->setEnabled(true); // hide mygui's pointer @@ -1181,31 +1182,7 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { - if(!mCursorManager->cursorChanged(name)) - return; //the cursor manager doesn't want any more info about this cursor - //See if we can get the information we need out of the cursor resource - ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); - if(imgSetPtr != NULL) - { - MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); - - std::string tex_name = imgSet->getIndexInfo(0,0).texture; - - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); - tex->setUnRefImageDataAfterApply(false); // FIXME? - - //everything looks good, send it to the cursor manager - if(tex.valid()) - { - Uint8 size_x = imgSetPtr->getSize().width; - Uint8 size_y = imgSetPtr->getSize().height; - Uint8 hotspot_x = imgSetPtr->getHotSpot().left; - Uint8 hotspot_y = imgSetPtr->getHotSpot().top; - int rotation = imgSetPtr->getRotation(); - - mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); - } - } + mCursorManager->cursorChanged(name); } void WindowManager::popGuiMode() @@ -1963,6 +1940,33 @@ namespace MWGui return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); } + void WindowManager::createCursors() + { + MyGUI::ResourceManager::EnumeratorPtr enumerator = MyGUI::ResourceManager::getInstance().getEnumerator(); + while (enumerator.next()) + { + MyGUI::IResource* resource = enumerator.current().second; + ResourceImageSetPointerFix* imgSetPointer = dynamic_cast(resource); + if (!imgSetPointer) + continue; + std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture; + + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + + if(tex.valid()) + { + //everything looks good, send it to the cursor manager + Uint8 size_x = imgSetPointer->getSize().width; + Uint8 size_y = imgSetPointer->getSize().height; + Uint8 hotspot_x = imgSetPointer->getHotSpot().left; + Uint8 hotspot_y = imgSetPointer->getHotSpot().top; + int rotation = imgSetPointer->getRotation(); + + mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); + } + } + } + void WindowManager::createTextures() { { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c275a9f626..e6c8d0a817 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -511,6 +511,7 @@ namespace MWGui void onClipboardRequested(const std::string& _type, std::string& _data); void createTextures(); + void createCursors(); void setMenuTransparency(float value); }; } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index a8a48f4f8b..d8d4b0b506 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -175,23 +175,16 @@ namespace SDLUtil } } - bool SDLCursorManager::cursorChanged(const std::string& name) + void SDLCursorManager::cursorChanged(const std::string& name) { mCurrentCursor = name; CursorMap::const_iterator curs_iter = mCursorMap.find(name); - //we have this cursor if(curs_iter != mCursorMap.end()) { + //we have this cursor _setGUICursor(name); - - return false; - } - else - { - //they should get back to us with more info - return true; } } @@ -200,7 +193,7 @@ namespace SDLUtil SDL_SetCursor(mCursorMap.find(name)->second); } - void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + void SDLCursorManager::createCursor(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); } diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp index 646f548e3c..0db578039c 100644 --- a/components/sdlutil/sdlcursormanager.hpp +++ b/components/sdlutil/sdlcursormanager.hpp @@ -27,11 +27,9 @@ namespace SDLUtil /// \brief Tell the manager that the cursor has changed, giving the /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the manager is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name); + virtual void cursorChanged(const std::string &name); - /// \brief Follow up a cursorChanged() call with enough info to create an cursor. - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void createCursor(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); private: void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); From 2202973c2462b9299480c9106904383a113fb89d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 10:05:45 +0200 Subject: [PATCH 0708/1812] replaced the script subview status bar with a bottom box (including a status bar) --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- apps/opencs/view/world/scriptsubview.cpp | 33 +++++++++----------- apps/opencs/view/world/scriptsubview.hpp | 6 ++-- apps/opencs/view/world/tablebottombox.cpp | 36 ++++++++++++++++++---- apps/opencs/view/world/tablebottombox.hpp | 13 ++++++-- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index edd9cc1e28..5a44708c19 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -857,8 +857,6 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); - mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (requestFocus (const std::string&))); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0f5d5014a8..f65f772856 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -16,6 +15,8 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +#include "tablebottombox.hpp" +#include "genericcreator.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -33,7 +34,7 @@ void CSVWorld::ScriptSubView::addButtonBar() } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); @@ -65,18 +66,13 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // status bar - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); + // bottom box + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + connect (mBottom, SIGNAL (requestFocus (const std::string&)), + this, SLOT (requestFocus (const std::string&))); - mLayout.addWidget (mBottom, 0); + mLayout.addWidget (mBottom); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -124,14 +120,15 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); } +void CSVWorld::ScriptSubView::setStatusBar (bool show) +{ + mBottom->setStatusBar (show); +} + void CSVWorld::ScriptSubView::updateStatusBar () { - std::ostringstream stream; - - stream << "(" << mEditor->textCursor().blockNumber() + 1 << ", " - << mEditor->textCursor().columnNumber() + 1 << ")"; - - mStatus->setText (QString::fromUtf8 (stream.str().c_str())); + mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1, + mEditor->textCursor().columnNumber() + 1); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 370754ebe7..09f7907ee9 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -25,6 +25,7 @@ namespace CSVWorld { class ScriptEdit; class RecordButtonBar; + class TableBottomBox; class ScriptSubView : public CSVDoc::SubView { @@ -34,8 +35,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; - QWidget *mBottom; - QLabel *mStatus; + TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; @@ -54,6 +54,8 @@ namespace CSVWorld virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void setStatusBar (bool show); + public slots: void textChanged(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc764..12226450b0 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -35,15 +35,23 @@ void CSVWorld::TableBottomBox::updateStatus() } } + if (mHasPosition) + { + if (!first) + stream << " -- "; + + stream << "(" << mRow << ", " << mColumn << ")"; + } + mStatus->setText (QString::fromUtf8 (stream.str().c_str())); } } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mCreating (false), mHasPosition (false) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -74,6 +82,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -152,6 +162,20 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi updateStatus(); } +void CSVWorld::TableBottomBox::positionChanged (int row, int column) +{ + mRow = row; + mColumn = column; + mHasPosition = true; + updateStatus(); +} + +void CSVWorld::TableBottomBox::noMorePosition() +{ + mHasPosition = false; + updateStatus(); +} + void CSVWorld::TableBottomBox::createRequest() { mCreator->reset(); @@ -162,8 +186,8 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->focus(); } -void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, - const CSMWorld::UniversalId::Type type) +void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, + const CSMWorld::UniversalId::Type type) { mCreator->reset(); mCreator->cloneMode(id, type); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42d..6e68553bc8 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -30,6 +30,9 @@ namespace CSVWorld Creator *mCreator; bool mCreating; QStackedLayout *mLayout; + bool mHasPosition; + int mRow; + int mColumn; private: @@ -41,9 +44,9 @@ namespace CSVWorld public: - TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, + TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent = 0); virtual ~TableBottomBox(); @@ -77,6 +80,10 @@ namespace CSVWorld /// \param deleted Number of deleted records /// \param modified Number of added and modified records + void positionChanged (int row, int column); + + void noMorePosition(); + void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); From 0860c27b039465e4505f5211a9bcbb9ddedf773e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 11:49:41 +0200 Subject: [PATCH 0709/1812] improving consistency of subview layouts --- apps/opencs/view/tools/searchsubview.cpp | 20 +++++++++----------- apps/opencs/view/world/previewsubview.cpp | 2 -- apps/opencs/view/world/scenesubview.cpp | 2 -- apps/opencs/view/world/tablesubview.cpp | 3 --- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index dc670af40a..8b35db6aed 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -16,7 +16,7 @@ void CSVTools::SearchSubView::replace (bool selection) { if (mLocked) return; - + std::vector indices = mTable->getReplaceIndices (selection); std::string replace = mSearchBox.getReplaceText(); @@ -29,7 +29,7 @@ void CSVTools::SearchSubView::replace (bool selection) CSMTools::Search search (mSearch); CSMWorld::IdTableBase *currentTable = 0; - + // We are running through the indices in reverse order to avoid messing up multiple results // in a single string. for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) @@ -46,7 +46,7 @@ void CSVTools::SearchSubView::replace (bool selection) search.configure (table); currentTable = table; } - + std::string hint = model.getHint (*iter); if (search.verify (mDocument, table, id, hint)) @@ -63,7 +63,7 @@ void CSVTools::SearchSubView::replace (bool selection) void CSVTools::SearchSubView::showEvent (QShowEvent *event) { CSVDoc::SubView::showEvent (event); - mSearchBox.focus(); + mSearchBox.focus(); } CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -71,25 +71,23 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (&mSearchBox); - + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; - + widget->setLayout (layout); setWidget (widget); stateChanged (document.getState(), &document); - + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); - + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -124,7 +122,7 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) mSearch = search; mSearch.setPadding (paddingBefore, paddingAfter); - + mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1c2d6b95c7..756e79fe6f 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -13,8 +13,6 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo { QHBoxLayout *layout = new QHBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - if (document.getData().getReferenceables().searchId (id.getId())==-1) { std::string referenceableId = diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 397d249296..b7a795e230 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -31,8 +31,6 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0); mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c4..e2c9e2fb14 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -23,8 +23,6 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this), 0); @@ -166,4 +164,3 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) } return false; } - From cf1fb76bb4cdb3e08f8b4a71e682681a811fe64b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:34:13 +0200 Subject: [PATCH 0710/1812] fixed deleted button sensitivity state --- apps/opencs/view/world/recordbuttonbar.cpp | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 63c0dd0a18..9cae0d0c9d 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -17,18 +17,17 @@ void CSVWorld::RecordButtonBar::updateModificationButtons() mCloneButton->setDisabled (createAndDeleteDisabled); mAddButton->setDisabled (createAndDeleteDisabled); - mDeleteButton->setDisabled (createAndDeleteDisabled); bool commandDisabled = !mCommandDispatcher || mLocked; - + mRevertButton->setDisabled (commandDisabled); - mDeleteButton->setDisabled (commandDisabled); + mDeleteButton->setDisabled (commandDisabled || createAndDeleteDisabled); } void CSVWorld::RecordButtonBar::updatePrevNextButtons() { int rows = mTable.rowCount(); - + if (rows<=1) { mPrevButton->setDisabled (true); @@ -62,12 +61,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mPrevButton->setIcon(QIcon(":/go-previous.png")); mPrevButton->setToolTip ("Switch to previous record"); buttonsLayout->addWidget (mPrevButton, 0); - + mNextButton = new QToolButton (this); mNextButton->setIcon(QIcon(":/go-next.png")); mNextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget (mNextButton, 1); - + buttonsLayout->addStretch(2); // optional buttons of the right section @@ -94,22 +93,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mCloneButton->setIcon(QIcon(":/edit-clone.png")); mCloneButton->setToolTip ("Clone record"); buttonsLayout->addWidget(mCloneButton); - + mAddButton = new QToolButton (this); mAddButton->setIcon(QIcon(":/add.png")); mAddButton->setToolTip ("Add new record"); buttonsLayout->addWidget(mAddButton); - + mDeleteButton = new QToolButton (this); mDeleteButton->setIcon(QIcon(":/edit-delete.png")); mDeleteButton->setToolTip ("Delete record"); buttonsLayout->addWidget(mDeleteButton); - + mRevertButton = new QToolButton (this); mRevertButton->setIcon(QIcon(":/edit-undo.png")); mRevertButton->setToolTip ("Revert record"); buttonsLayout->addWidget(mRevertButton); - + setLayout (buttonsLayout); // connections @@ -132,7 +131,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); - + updateModificationButtons(); updatePrevNextButtons(); } @@ -170,7 +169,7 @@ void CSVWorld::RecordButtonBar::cloneRequest() } void CSVWorld::RecordButtonBar::nextId() -{ +{ int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; if (newRow >= mTable.rowCount()) @@ -180,8 +179,8 @@ void CSVWorld::RecordButtonBar::nextId() newRow = 0; else return; - } - + } + emit switchToRow (newRow); } @@ -197,7 +196,7 @@ void CSVWorld::RecordButtonBar::prevId() else return; } - + emit switchToRow (newRow); } From df027b3498f1730cfda5daed06052c04a64456d9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:52:48 +0200 Subject: [PATCH 0711/1812] hooked up script subview buttons to bottom box (enables add and clone) --- apps/opencs/view/world/scriptsubview.cpp | 15 +++++++++------ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index f65f772856..181400c888 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -23,7 +23,7 @@ void CSVWorld::ScriptSubView::addButtonBar() if (mButtons) return; - mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + mButtons = new RecordButtonBar (getUniversalId(), *mModel, mBottom, &mCommandDispatcher, this); mLayout.insertWidget (1, mButtons); @@ -61,16 +61,14 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: throw std::logic_error ("Can't find script column"); mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // bottom box and buttons + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - // buttons if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // bottom box - mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), - this, SLOT (requestFocus (const std::string&))); + this, SLOT (switchToId (const std::string&))); mLayout.addWidget (mBottom); @@ -216,3 +214,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); } + +void CSVWorld::ScriptSubView::switchToId (const std::string& id) +{ + switchToRow (mModel->getModelIndex (id, 0).row()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 09f7907ee9..6e5276c682 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -69,6 +69,8 @@ namespace CSVWorld void updateStatusBar(); void switchToRow (int row); + + void switchToId (const std::string& id); }; } From 73731d27e9e32f26e154b16fd1eb4543f84ea917 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 14 Jul 2015 23:54:47 +0900 Subject: [PATCH 0712/1812] Add ${MYGUI_LIBRARIES} to components/CMakeLists.txt --- components/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3224d09896..d91bb5c30d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -180,6 +180,7 @@ target_link_libraries(components ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} ) if (WIN32) From 5e623a2a1d06d5679f214cad95123a1d3bd88b34 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 16:18:33 +0300 Subject: [PATCH 0713/1812] Rework RefIdData code. Update the index map when a new record is loaded --- apps/opencs/model/world/refiddata.cpp | 30 +++++++++-- apps/opencs/model/world/refiddata.hpp | 73 +++++++++++---------------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 68f3fc4ad6..e7b36015e3 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -3,10 +3,20 @@ #include -#include - CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {} + +std::string CSMWorld::RefIdData::getRecordId(const CSMWorld::RefIdData::LocalIndex &index) const +{ + std::map::const_iterator found = + mRecordContainers.find (index.second); + + if (found == mRecordContainers.end()) + throw std::logic_error ("invalid local index type"); + + return found->second->getId(index.first); +} + CSMWorld::RefIdData::RefIdData() { mRecordContainers.insert (std::make_pair (UniversalId::Type_Activator, &mActivators)); @@ -167,9 +177,21 @@ void CSMWorld::RefIdData::load (ESM::ESMReader& reader, bool base, CSMWorld::Uni mRecordContainers.find (type); if (found == mRecordContainers.end()) - throw std::logic_error ("Invalid type for an Object (Reference ID)"); + throw std::logic_error ("Invalid Referenceable ID type"); - found->second->load(reader, base); + int index = found->second->load(reader, base); + if (index != -1) + { + LocalIndex localIndex = LocalIndex(index, type); + if (base && getRecord(localIndex).mState == RecordBase::State_Deleted) + { + erase(localIndex, 1); + } + else + { + mIndex[Misc::StringUtils::lowerCase(getRecordId(localIndex))] = localIndex; + } + } } void CSMWorld::RefIdData::erase (const LocalIndex& index, int count) diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 17d9139115..195244ba89 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -25,6 +25,8 @@ #include #include +#include + #include "record.hpp" #include "universalid.hpp" @@ -49,7 +51,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record) = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual int load (ESM::ESMReader& reader, bool base) = 0; + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count) = 0; @@ -73,7 +76,8 @@ namespace CSMWorld virtual void insertRecord (RecordBase& record); - virtual void load (ESM::ESMReader& reader, bool base); + virtual int load (ESM::ESMReader& reader, bool base); + ///< \return index of a loaded record or -1 if no record was loaded virtual void erase (int index, int count); @@ -122,15 +126,16 @@ namespace CSMWorld } template - void RefIdDataContainer::load (ESM::ESMReader& reader, bool base) + int RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { RecordT record; record.load(reader); - typename std::vector >::iterator found = mContainer.begin(); - for (; found != mContainer.end(); ++found) + int index = 0; + int numRecords = static_cast(mContainer.size()); + for (; index < numRecords; ++index) { - if (found->get().mId == record.mId) + if (Misc::StringUtils::ciEqual(mContainer[index].get().mId, record.mId)) { break; } @@ -138,26 +143,21 @@ namespace CSMWorld if (record.mIsDeleted) { - if (found == mContainer.end()) + if (index == numRecords) { // deleting a record that does not exist // ignore it for now /// \todo report the problem to the user - return; + return -1; } - if (base) - { - mContainer.erase(found); - } - else - { - found->mState = RecordBase::State_Deleted; - } + // Flag the record as Deleted even for a base content file. + // RefIdData is responsible for its erasure. + mContainer[index].mState = RecordBase::State_Deleted; } else { - if (found == mContainer.end()) + if (index == numRecords) { appendRecord(record.mId, base); if (base) @@ -169,20 +169,13 @@ namespace CSMWorld mContainer.back().mModified = record; } } - else + else if (!base) { - if (!base) - { - if (found->mState == RecordBase::State_Erased) - { - throw std::logic_error("Attempt to access a deleted record"); - } - - found->mState = RecordBase::State_Modified; - found->mModified = record; - } + mContainer[index].setModified(record); } } + + return index; } template @@ -204,25 +197,15 @@ namespace CSMWorld void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { Record record = mContainer.at(index); - RecordT esmRecord; + RecordT esmRecord = record.get(); - switch (record.mState) + if (record.isModified() || record.mState == RecordBase::State_Deleted) { - case RecordBase::State_Modified: - case RecordBase::State_ModifiedOnly: - esmRecord = record.mModified; - break; - case RecordBase::State_Deleted: - esmRecord = record.mBase; - esmRecord.mIsDeleted = true; - break; - default: - break; + esmRecord.mIsDeleted = (record.mState == RecordBase::State_Deleted); + writer.startRecord(esmRecord.sRecordId); + esmRecord.save(writer); + writer.endRecord(esmRecord.sRecordId); } - - writer.startRecord(esmRecord.sRecordId); - esmRecord.save(writer); - writer.endRecord(esmRecord.sRecordId); } @@ -262,6 +245,8 @@ namespace CSMWorld void erase (const LocalIndex& index, int count); ///< Must not spill over into another type. + std::string getRecordId(const LocalIndex &index) const; + public: RefIdData(); From a1389b87bacd08f54c4c146c7a0b6d1ed51edc54 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 23:31:16 +0300 Subject: [PATCH 0714/1812] Return a correct index for a loaded record that was deleted --- apps/opencs/model/world/idcollection.hpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 41ce59702d..d08abce5b3 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -61,22 +61,14 @@ namespace CSMWorld if (base) { removeRows (index, 1); - } - else - { - Record baseRecord = getRecord (index); - baseRecord.mState = RecordBase::State_Deleted; - this->setRecord (index, baseRecord); + return -1; } - return -1; + Record baseRecord = getRecord (index); + baseRecord.mState = RecordBase::State_Deleted; + setRecord (index, baseRecord); + return index; } - // - //if (index != -1) - //{ - // ESXRecordT existedRecord = getRecord(index).get(); - // IdAccessorT().getId(record) = IdAccessorT().getId(existedRecord); - //} return load (record, base, index); } From 335ef97cf561e4655363e16041aaf119cde375db Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Jul 2015 18:47:11 +0200 Subject: [PATCH 0715/1812] Rename Animation::Group to Animation::BlendMask The old naming is problematic, because the term group was being used for another feature (text key groups) already. --- apps/openmw/mwmechanics/character.cpp | 70 +++++++++++------------ apps/openmw/mwrender/animation.cpp | 42 +++++++------- apps/openmw/mwrender/animation.hpp | 30 +++++----- apps/openmw/mwrender/characterpreview.cpp | 6 +- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4b2ce9f4cb..bd15b6a738 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -251,26 +251,26 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, ~0ul); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } else if(knockdown) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (recovery) { mHitState = CharState_Hit; mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (block) { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "block start", "block stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -303,7 +303,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockDown; mAnimation->disable(mCurrentHit); - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "loop stop", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } } @@ -314,7 +314,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(force && mJumpState != JumpState_None) { std::string jump; - MWRender::Animation::Group jumpgroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { jump = "jump"; @@ -323,7 +323,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat jump += weap->shortgroup; if(!mAnimation->hasAnimation(jump)) { - jumpgroup = MWRender::Animation::Group_LowerBody; + jumpmask = MWRender::Animation::BlendMask_LowerBody; jump = "jump"; } } @@ -336,7 +336,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump = jump; if (mAnimation->hasAnimation("jump")) - mAnimation->play(mCurrentJump, Priority_Jump, jumpgroup, false, + mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } else @@ -344,7 +344,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpgroup, true, + mAnimation->play(jump, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -354,7 +354,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mMovementState = movement; std::string movement; - MWRender::Animation::Group movegroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { @@ -364,7 +364,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat movement += weap->shortgroup; if(!mAnimation->hasAnimation(movement)) { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement = movestate->groupname; } } @@ -386,7 +386,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement.erase(swimpos, 4); if(!mAnimation->hasAnimation(movement)) movement.clear(); @@ -447,7 +447,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -486,7 +486,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, + mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } @@ -602,7 +602,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mCurrentJump = ""; mMovementAnimationControlled = true; - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startpoint, 0); } @@ -868,10 +868,10 @@ void CharacterController::updateIdleStormState() mAnimation->getInfo("idlestorm", &complete); if (complete == 0) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "start", "loop start", 0.0f, 0); else if (complete == 1) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "loop start", "loop stop", 0.0f, ~0ul); } else @@ -882,7 +882,7 @@ void CharacterController::updateIdleStormState() { if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) { - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -989,7 +989,7 @@ bool CharacterController::updateCreatureState() if (!mCurrentWeapon.empty()) { mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_All, true, + MWRender::Animation::BlendMask_All, true, 1, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1064,7 +1064,7 @@ bool CharacterController::updateWeaponState() { getWeaponGroup(mWeaponType, weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1075,7 +1075,7 @@ bool CharacterController::updateWeaponState() mAnimation->setWeaponGroup(weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1192,7 +1192,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1224,7 +1224,7 @@ bool CharacterController::updateWeaponState() Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1251,7 +1251,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1302,7 +1302,7 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1374,7 +1374,7 @@ bool CharacterController::updateWeaponState() //don't allow to continue playing hit animation on UpperBody after actor had attacked during it if(mHitState == CharState_Hit) { - mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); + mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); //commenting out following 2 lines will give a bit different combat dynamics(slower) mHitState = CharState_None; mCurrentHit.clear(); @@ -1398,7 +1398,7 @@ bool CharacterController::updateWeaponState() //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1441,11 +1441,11 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, start, stop, 0.0f, 0); else mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, start, stop, 0.0f, 0); } } @@ -1459,11 +1459,11 @@ bool CharacterController::updateWeaponState() MWBase::Environment::get().getWorld()->isSwimming(mPtr) || cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); } else { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); } } @@ -1475,7 +1475,7 @@ bool CharacterController::updateWeaponState() && updateCarriedLeftVisible(mWeaponType)) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); } else if (mAnimation->isPlaying("torch")) @@ -1505,7 +1505,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1786,7 +1786,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1894,7 +1894,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mIdleState = CharState_SpecialIdle; mAnimation->play(groupname, Priority_Default, - MWRender::Animation::Group_All, false, 1.0f, + MWRender::Animation::BlendMask_All, false, 1.0f, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 91f459ff2f..097a4febfa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ namespace MWRender typedef std::map > ControllerMap; - ControllerMap mControllerMap[Animation::sNumGroups]; + ControllerMap mControllerMap[Animation::sNumBlendMasks]; const std::multimap& getTextKeys(); }; @@ -261,7 +261,7 @@ namespace MWRender , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) { - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); } @@ -299,9 +299,9 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } - size_t Animation::detectAnimGroup(osg::Node* node) + size_t Animation::detectBlendMask(osg::Node* node) { - static const char sGroupRoots[sNumGroups][32] = { + static const char sBlendMaskRoots[sNumBlendMasks][32] = { "", /* Lower body / character root */ "Bip01 Spine1", /* Torso */ "Bip01 L Clavicle", /* Left arm */ @@ -311,9 +311,9 @@ namespace MWRender while(node != mObjectRoot) { const std::string &name = node->getName(); - for(size_t i = 1;i < sNumGroups;i++) + for(size_t i = 1;i < sNumBlendMasks;i++) { - if(name == sGroupRoots[i]) + if(name == sBlendMaskRoots[i]) return i; } @@ -361,13 +361,13 @@ namespace MWRender osg::Node* node = found->second; - size_t group = detectAnimGroup(node); + size_t blendMask = detectBlendMask(node); // clone the controller, because each Animation needs its own ControllerSource osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL); - cloned->setSource(mAnimationTimePtr[group]); + cloned->setSource(mAnimationTimePtr[blendMask]); - animsrc->mControllerMap[group].insert(std::make_pair(bonename, cloned)); + animsrc->mControllerMap[blendMask].insert(std::make_pair(bonename, cloned)); } mAnimSources.push_back(animsrc); @@ -390,7 +390,7 @@ namespace MWRender { mStates.clear(); - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i]->setTimePtr(boost::shared_ptr()); mAccumCtrl = NULL; @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -505,7 +505,7 @@ namespace MWRender state.mLoopCount = loops; state.mPlaying = (state.getTime() < state.mStopTime); state.mPriority = priority; - state.mGroups = groups; + state.mBlendMask = blendMask; state.mAutoDisable = autodisable; mStates[groupname] = state; @@ -643,35 +643,35 @@ namespace MWRender mAccumCtrl = NULL; - for(size_t grp = 0;grp < sNumGroups;grp++) + for(size_t blendMask = 0;blendMask < sNumBlendMasks;blendMask++) { AnimStateMap::const_iterator active = mStates.end(); AnimStateMap::const_iterator state = mStates.begin(); for(;state != mStates.end();++state) { - if(!(state->second.mGroups&(1<second.mBlendMask&(1<second.mPriority < state->second.mPriority) active = state; } - mAnimationTimePtr[grp]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); + mAnimationTimePtr[blendMask]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); - // add external controllers for the AnimSource active in this group + // add external controllers for the AnimSource active in this blend mask if (active != mStates.end()) { boost::shared_ptr animsrc = active->second.mSource; - for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[grp].begin(); it != animsrc->mControllerMap[grp].end(); ++it) + for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[blendMask].begin(); it != animsrc->mControllerMap[blendMask].end(); ++it) { osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); mActiveControllers.insert(std::make_pair(node, it->second)); - if (grp == 0 && node == mAccumRoot) + if (blendMask == 0 && node == mAccumRoot) { mAccumCtrl = it->second; @@ -690,14 +690,14 @@ namespace MWRender addControllers(); } - void Animation::changeGroups(const std::string &groupname, int groups) + void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); if(stateiter != mStates.end()) { - if(stateiter->second.mGroups != groups) + if(stateiter->second.mBlendMask != mask) { - stateiter->second.mGroups = groups; + stateiter->second.mBlendMask = mask; resetActiveGroups(); } return; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d23a629549..0a90489cf0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,16 +67,16 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: - enum Group { - Group_LowerBody = 1<<0, + enum BlendMask { + BlendMask_LowerBody = 1<<0, - Group_Torso = 1<<1, - Group_LeftArm = 1<<2, - Group_RightArm = 1<<3, + BlendMask_Torso = 1<<1, + BlendMask_LeftArm = 1<<2, + BlendMask_RightArm = 1<<3, - Group_UpperBody = Group_Torso | Group_LeftArm | Group_RightArm, + BlendMask_UpperBody = BlendMask_Torso | BlendMask_LeftArm | BlendMask_RightArm, - Group_All = Group_LowerBody | Group_UpperBody + BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; class TextKeyListener @@ -90,7 +90,7 @@ public: protected: /* This is the number of *discrete* groups. */ - static const size_t sNumGroups = 4; + static const size_t sNumBlendMasks = 4; class AnimationTime : public SceneUtil::ControllerSource { @@ -133,12 +133,12 @@ protected: size_t mLoopCount; int mPriority; - int mGroups; + int mBlendMask; bool mAutoDisable; AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), - mPriority(0), mGroups(0), mAutoDisable(true) + mPriority(0), mBlendMask(0), mAutoDisable(true) { } ~AnimState(); @@ -176,7 +176,7 @@ protected: typedef std::multimap, osg::ref_ptr > ControllerMap; ControllerMap mActiveControllers; - boost::shared_ptr mAnimationTimePtr[sNumGroups]; + boost::shared_ptr mAnimationTimePtr[sNumBlendMasks]; // Stored in all lowercase for a case-insensitive lookup typedef std::map > NodeMap; @@ -213,7 +213,7 @@ protected: */ void resetActiveGroups(); - size_t detectAnimGroup(osg::Node* node); + size_t detectBlendMask(osg::Node* node); /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ @@ -304,7 +304,7 @@ public: * \param priority Priority of the animation. The animation will play on * bone groups that don't have another animation set of a * higher priority. - * \param groups Bone groups to play the animation on. + * \param blendMask Bone groups to play the animation on. * \param autodisable Automatically disable the animation when it stops * playing. * \param speedmult Speed multiplier for the animation. @@ -319,7 +319,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int groups, bool autodisable, + void play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); @@ -358,7 +358,7 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeGroups(const std::string &groupname, int group); + void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 32e51c4d6d..b4e1189f73 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -241,13 +241,13 @@ namespace MWRender mAnimation->showCarriedLeft(showCarriedLeft); mCurrentAnimGroup = groupname; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentAnimGroup, 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && showCarriedLeft) { if(!mAnimation->getInfo("torch")) - mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false, + mAnimation->play("torch", 2, Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } else if(mAnimation->getInfo("torch")) @@ -357,7 +357,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play("idle", 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->runAnimation(0.f); // attach camera to follow the head node From e93a578f237b67f9e6d5da361220589895f08dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:18:31 +0200 Subject: [PATCH 0716/1812] Extend the animation priority system to one priority value per bone group / distinct blend mask --- apps/openmw/mwrender/animation.cpp | 14 ++++++------- apps/openmw/mwrender/animation.hpp | 33 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 097a4febfa..2be2165ea6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -473,8 +473,6 @@ namespace MWRender return; } - priority = std::max(0, priority); - AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -653,7 +651,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority < state->second.mPriority) + if(active == mStates.end() || active->second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) active = state; } @@ -690,6 +688,7 @@ namespace MWRender addControllers(); } + // TODO: remove void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); @@ -1208,9 +1207,10 @@ namespace MWRender { for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) { - if((stateiter->second.mPriority > MWMechanics::Priority_Movement - && stateiter->second.mPriority < MWMechanics::Priority_Torch) - || stateiter->second.mPriority == MWMechanics::Priority_Death) + if (stateiter->second.mPriority.contains(int(MWMechanics::Priority_Hit)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Weapon)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Knockdown)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Death))) return false; } return true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0a90489cf0..90d2a68a32 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -118,6 +118,35 @@ protected: struct AnimSource; + /// Holds an animation priority value for each distinct bone blendmask. + struct AnimPriority + { + /// Convenience constructor, initialises all priorities to the same value. + AnimPriority(int priority) + { + for (unsigned int i=0; i mSource; float mStartTime; @@ -132,7 +161,7 @@ protected: bool mPlaying; size_t mLoopCount; - int mPriority; + AnimPriority mPriority; int mBlendMask; bool mAutoDisable; @@ -319,7 +348,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int blendMask, bool autodisable, + void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 50db6ed3968df6b3e16cf9315b6f3a47d8ac8227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:40:36 +0200 Subject: [PATCH 0717/1812] Use the extended animation priority for weapon animations --- apps/openmw/mwmechanics/character.cpp | 56 +++++++----------- apps/openmw/mwrender/animation.hpp | 85 ++++++++++++++------------- 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bd15b6a738..8f813ceb1b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1051,6 +1051,9 @@ bool CharacterController::updateWeaponState() } } + MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) @@ -1063,8 +1066,8 @@ bool CharacterController::updateWeaponState() if(weaptype == WeapType_None) { getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1074,8 +1077,8 @@ bool CharacterController::updateWeaponState() mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1191,8 +1194,8 @@ bool CharacterController::updateWeaponState() case 2: mAttackType = "target"; break; } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1223,8 +1226,8 @@ bool CharacterController::updateWeaponState() else if(item.getTypeName() == typeid(ESM::Probe).name()) Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1250,8 +1253,8 @@ bool CharacterController::updateWeaponState() determineAttackType(); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1301,8 +1304,8 @@ bool CharacterController::updateWeaponState() mAttackStrength = attackStrength; mAnimation->disable(mCurrentWeapon); - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1397,8 +1400,8 @@ bool CharacterController::updateWeaponState() case UpperCharState_MinAttackToMaxAttack: //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1440,33 +1443,16 @@ bool CharacterController::updateWeaponState() { mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, start, stop, 0.0f, 0); else - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, start, stop, 0.0f, 0); } } - //if playing combat animation and lowerbody is not busy switch to whole body animation - if((weaptype != WeapType_None || mUpperBodyState == UpperCharState_UnEquipingWeap) && animPlaying) - { - if( mMovementState != CharState_None || - mJumpState != JumpState_None || - mHitState != CharState_None || - MWBase::Environment::get().getWorld()->isSwimming(mPtr) || - cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); - } - else - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); - } - } - if (mPtr.getClass().hasInventoryStore(mPtr)) { MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 90d2a68a32..35c0b5346c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,9 +67,15 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: + enum BoneGroup { + BoneGroup_LowerBody = 0, + BoneGroup_Torso, + BoneGroup_LeftArm, + BoneGroup_RightArm + }; + enum BlendMask { BlendMask_LowerBody = 1<<0, - BlendMask_Torso = 1<<1, BlendMask_LeftArm = 1<<2, BlendMask_RightArm = 1<<3, @@ -78,47 +84,10 @@ public: BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; - - class TextKeyListener - { - public: - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) = 0; - }; - - void setTextKeyListener(TextKeyListener* listener); - -protected: - /* This is the number of *discrete* groups. */ + /* This is the number of *discrete* blend masks. */ static const size_t sNumBlendMasks = 4; - class AnimationTime : public SceneUtil::ControllerSource - { - private: - boost::shared_ptr mTimePtr; - - public: - - void setTimePtr(boost::shared_ptr time) - { mTimePtr = time; } - boost::shared_ptr getTimePtr() const - { return mTimePtr; } - - virtual float getValue(osg::NodeVisitor* nv); - }; - - class NullAnimationTime : public SceneUtil::ControllerSource - { - public: - virtual float getValue(osg::NodeVisitor *nv) - { - return 0.f; - } - }; - - struct AnimSource; - - /// Holds an animation priority value for each distinct bone blendmask. + /// Holds an animation priority value for each BoneGroup. struct AnimPriority { /// Convenience constructor, initialises all priorities to the same value. @@ -147,6 +116,42 @@ protected: int mPriority[sNumBlendMasks]; }; + class TextKeyListener + { + public: + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) = 0; + }; + + void setTextKeyListener(TextKeyListener* listener); + +protected: + class AnimationTime : public SceneUtil::ControllerSource + { + private: + boost::shared_ptr mTimePtr; + + public: + + void setTimePtr(boost::shared_ptr time) + { mTimePtr = time; } + boost::shared_ptr getTimePtr() const + { return mTimePtr; } + + virtual float getValue(osg::NodeVisitor* nv); + }; + + class NullAnimationTime : public SceneUtil::ControllerSource + { + public: + virtual float getValue(osg::NodeVisitor *nv) + { + return 0.f; + } + }; + + struct AnimSource; + struct AnimState { boost::shared_ptr mSource; float mStartTime; From cf14d1748c50dad6a64c8a7019c7fe454b09652a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:47:29 +0200 Subject: [PATCH 0718/1812] Use the extended animation priority for Hit animations --- apps/openmw/mwmechanics/character.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f813ceb1b..ea0d4f3227 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1374,15 +1374,6 @@ bool CharacterController::updateWeaponState() mAnimation->attachArrow(); mUpperBodyState = UpperCharState_WeapEquiped; - //don't allow to continue playing hit animation on UpperBody after actor had attacked during it - if(mHitState == CharState_Hit) - { - mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); - //commenting out following 2 lines will give a bit different combat dynamics(slower) - mHitState = CharState_None; - mCurrentHit.clear(); - mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false); - } } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) mUpperBodyState = UpperCharState_Nothing; From 83cceeee7283183db18e40b1890a20c55dae4ad3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:54:37 +0200 Subject: [PATCH 0719/1812] Use the extended animation priority for Block animations, allow starting attacks during a block animation (Fixes #2761) --- apps/openmw/mwmechanics/character.cpp | 11 +++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea0d4f3227..a71f8d1601 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -270,7 +270,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); + MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); + priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -1148,7 +1150,7 @@ bool CharacterController::updateWeaponState() bool animPlaying; if(mAttackingOrSpell) { - if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) + if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackType.clear(); @@ -2029,12 +2031,13 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell) bool CharacterController::readyToPrepareAttack() const { - return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; + return (mHitState == CharState_None || mHitState == CharState_Block) + && mUpperBodyState <= UpperCharState_WeapEquiped; } bool CharacterController::readyToStartAttack() const { - if (mHitState != CharState_None) + if (mHitState != CharState_None && mHitState != CharState_Block) return false; if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b239b4a925..6b530ae2a8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,6 +32,7 @@ enum Priority { Priority_Movement, Priority_Hit, Priority_Weapon, + Priority_Block, Priority_Knockdown, Priority_Torch, Priority_Storm, From 3656851750b089a897d5b0077f0177808d7412f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:55:33 +0200 Subject: [PATCH 0720/1812] Remove the now unused changeBlendMask --- apps/openmw/mwrender/animation.cpp | 15 --------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2be2165ea6..84f46c4ab8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -688,21 +688,6 @@ namespace MWRender addControllers(); } - // TODO: remove - void Animation::changeBlendMask(const std::string &groupname, int mask) - { - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - if(stateiter->second.mBlendMask != mask) - { - stateiter->second.mBlendMask = mask; - resetActiveGroups(); - } - return; - } - } - void Animation::stopLooping(const std::string& groupname) { AnimStateMap::iterator stateiter = mStates.find(groupname); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 35c0b5346c..1cf2ce9bab 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -392,7 +392,6 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; From 17ada63fcb87d45b5da89d1efa33d24e229236e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 15:46:31 +0200 Subject: [PATCH 0721/1812] Don't play turning animations on the upperbody when in first person mode (Fixes #2287) --- apps/openmw/mwmechanics/character.cpp | 50 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a71f8d1601..95546dca93 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -355,55 +355,55 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mMovementState = movement; - std::string movement; + std::string movementAnimName; MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { - movement = movestate->groupname; - if(weap != sWeaponTypeListEnd && movement.find("swim") == std::string::npos) + movementAnimName = movestate->groupname; + if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) { - movement += weap->shortgroup; - if(!mAnimation->hasAnimation(movement)) + movementAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(movementAnimName)) { movemask = MWRender::Animation::BlendMask_LowerBody; - movement = movestate->groupname; + movementAnimName = movestate->groupname; } } - if(!mAnimation->hasAnimation(movement)) + if(!mAnimation->hasAnimation(movementAnimName)) { - std::string::size_type swimpos = movement.find("swim"); + std::string::size_type swimpos = movementAnimName.find("swim"); if(swimpos == std::string::npos) { - std::string::size_type runpos = movement.find("run"); + std::string::size_type runpos = movementAnimName.find("run"); if (runpos != std::string::npos) { - movement.replace(runpos, runpos+3, "walk"); - if (!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.replace(runpos, runpos+3, "walk"); + if (!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } else - movement.clear(); + movementAnimName.clear(); } else { movemask = MWRender::Animation::BlendMask_LowerBody; - movement.erase(swimpos, 4); - if(!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.erase(swimpos, 4); + if(!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } } } /* If we're playing the same animation, restart from the loop start instead of the * beginning. */ - int mode = ((movement == mCurrentMovement) ? 2 : 1); + int mode = ((movementAnimName == mCurrentMovement) ? 2 : 1); mMovementAnimationControlled = true; mAnimation->disable(mCurrentMovement); - mCurrentMovement = movement; + mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { float vel, speedmult = 1.0f; @@ -449,7 +449,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, + MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); + if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) + && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() + && MWBase::Environment::get().getWorld()->isFirstPerson()) + { + priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; + } + + mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -458,7 +468,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing - || mMovementState != CharState_None + || (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight) || mHitState != CharState_None) && !mPtr.getClass().isBipedal(mPtr)) idle = CharState_None; From e8a9567be30fb35e78e252bf52e95bcebe76a109 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 19:39:01 +0300 Subject: [PATCH 0722/1812] Move DELE handling to CellRef record --- apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 58 ++++++++++++++--------------- apps/openmw/mwworld/cellstore.hpp | 2 +- components/esm/cellref.cpp | 21 +++++++++++ components/esm/cellref.hpp | 4 ++ components/esm/loadcell.cpp | 12 ++---- components/esm/loadcell.hpp | 3 +- 7 files changed, 59 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 49197d1671..0ce6032243 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// and the build will fail with an ugly three-way cyclic header dependence /// so we need to pass the instantiation of the method to the linker, when /// all methods are known. - void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); + void load (ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index b33a6f8db8..a516725811 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -147,7 +147,7 @@ namespace MWWorld { template - void CellRefList::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore) + void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { const MWWorld::Store &store = esmStore.get(); @@ -158,7 +158,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); - if (deleted) + if (ref.mIsDeleted) liveCellRef.mData.setDeleted(true); if (iter != mList.end()) @@ -374,10 +374,9 @@ namespace MWWorld ESM::CellRef ref; // Get each reference in turn - bool deleted = false; - while (mCell->getNextRef (esm[index], ref, deleted)) + while (mCell->getNextRef (esm[index], ref)) { - if (deleted) + if (ref.mIsDeleted) continue; // Don't list reference if it was moved to a different cell. @@ -420,8 +419,7 @@ namespace MWWorld ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn - bool deleted = false; - while(mCell->getNextRef(esm[index], ref, deleted)) + while(mCell->getNextRef(esm[index], ref)) { // Don't load reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = @@ -430,7 +428,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted, store); + loadRef (ref, store); } } @@ -439,7 +437,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, false, store); + loadRef (ref, store); } } @@ -468,32 +466,32 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, const ESMStore& store) { Misc::StringUtils::toLower (ref.mRefID); switch (store.find (ref.mRefID)) { - case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; - case ESM::REC_ALCH: mPotions.load(ref, deleted, store); break; - case ESM::REC_APPA: mAppas.load(ref, deleted, store); break; - case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break; - case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break; - case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break; - case ESM::REC_CONT: mContainers.load(ref, deleted, store); break; - case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break; - case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break; - case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break; - case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break; - case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break; - case ESM::REC_LIGH: mLights.load(ref, deleted, store); break; - case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break; - case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break; - case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break; - case ESM::REC_PROB: mProbes.load(ref, deleted, store); break; - case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break; - case ESM::REC_STAT: mStatics.load(ref, deleted, store); break; - case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; + case ESM::REC_ACTI: mActivators.load(ref, store); break; + case ESM::REC_ALCH: mPotions.load(ref,store); break; + case ESM::REC_APPA: mAppas.load(ref, store); break; + case ESM::REC_ARMO: mArmors.load(ref, store); break; + case ESM::REC_BOOK: mBooks.load(ref, store); break; + case ESM::REC_CLOT: mClothes.load(ref, store); break; + case ESM::REC_CONT: mContainers.load(ref, store); break; + case ESM::REC_CREA: mCreatures.load(ref, store); break; + case ESM::REC_DOOR: mDoors.load(ref, store); break; + case ESM::REC_INGR: mIngreds.load(ref, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, store); break; + case ESM::REC_LIGH: mLights.load(ref, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, store); break; + case ESM::REC_PROB: mProbes.load(ref, store); break; + case ESM::REC_REPA: mRepairs.load(ref, store); break; + case ESM::REC_STAT: mStatics.load(ref, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, store); break; case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f879343d9d..5caa4eeea2 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); - void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); + void loadRef (ESM::CellRef& ref, const ESMStore& store); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c3b889df59..e43a37b668 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,6 +3,17 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include "util.hpp" + +ESM::CellRef::CellRef() + : mScale(1.0f), + mFactionRank(-2), + mEnchantmentCharge(-1), + mGoldValue(1), + mChargeInt(-1), + mLockLevel(0), + mIsDeleted(false) +{} void ESM::RefNum::load (ESMReader& esm, bool wide) { @@ -27,6 +38,7 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { + mIsDeleted = false; loadId(esm, wideRefNum); loadData(esm); } @@ -97,6 +109,8 @@ void ESM::CellRef::loadData(ESMReader &esm) if (esm.isNextSub("NAM0")) esm.skipHSub(); + + mIsDeleted = readDeleSubRecord (esm); } void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const @@ -149,6 +163,11 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (!inInventory) esm.writeHNT("DATA", mPos, 24); + + if (mIsDeleted) + { + writeDeleSubRecord(esm); + } } void ESM::CellRef::blank() @@ -178,6 +197,8 @@ void ESM::CellRef::blank() mPos.pos[i] = 0; mPos.rot[i] = 0; } + + mIsDeleted = false; } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index e9959611b3..553dbaae32 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -99,6 +99,10 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; + bool mIsDeleted; + + CellRef(); + /// Calls loadId and loadData void load (ESMReader& esm, bool wideRefNum = false); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 86b4e4edb8..67701a5b74 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -177,7 +177,7 @@ std::string Cell::getDescription() const } } -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves, MovedCellRef *mref) +bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) @@ -206,14 +206,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMo // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); - if (esm.isNextSub("DELE")) - { - esm.skipHSub(); - deleted = true; - } - else - deleted = false; - return true; } @@ -244,6 +236,8 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) mAmbi.mSunlight = 0; mAmbi.mFog = 0; mAmbi.mFogDensity = 0; + + mIsDeleted = false; } CellId Cell::getCellId() const diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index bf65c5fa8b..a1a758e3bd 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -163,8 +163,7 @@ struct Cell reuse one memory location without blanking it between calls. */ /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, - CellRef &ref, bool& deleted, bool ignoreMoves = false, MovedCellRef *mref = 0); + static bool getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves = false, MovedCellRef *mref = 0); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. From 992b7703155300f6a0c83b47f78f6513561f0a66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 18:52:23 +0200 Subject: [PATCH 0723/1812] Don't set OnPcEquip for items that failed to equip (Fixes #2776) --- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 392a4a84ae..39f4764035 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -436,6 +436,20 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case + if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) + { + std::pair canEquip = ptr.getClass().canBeEquipped(ptr, player); + if (canEquip.first == 0) + { + MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + updateItemView(); + return; + } + } + // If the item has a script, set its OnPcEquip to 1 if (!script.empty() // Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards, @@ -455,7 +469,7 @@ namespace MWGui { boost::shared_ptr action = ptr.getClass().use(ptr); - action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + action->execute (player); mSkippedToEquip = MWWorld::Ptr(); } From f8d360190d7443337e5a1d48d8b0505491c5fd73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 19:10:09 +0200 Subject: [PATCH 0724/1812] Remove an unneeded virtual --- apps/openmw/mwgui/windowbase.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 195b6c384d..43fb8901e7 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -21,16 +21,16 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - ///Unhides the window + /// Notify that window has been made visible virtual void open() {} - ///Hides the window + /// Notify that window has been hidden virtual void close () {} - ///Gracefully exits the window + /// Gracefully exits the window virtual void exit() {} - ///Sets the visibility of the window + /// Sets the visibility of the window virtual void setVisible(bool visible); - ///Returns the visibility state of the window - virtual bool isVisible(); + /// Returns the visibility state of the window + bool isVisible(); void center(); }; From 3ba73f5fd9feb9727b56f32767c848e520d9a94c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 20:53:08 +0300 Subject: [PATCH 0725/1812] Handle deleted records in RefCollection --- apps/opencs/model/world/refcollection.cpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index ff30dafae6..d32f21d0a1 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -20,12 +20,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Cell& cell2 = base ? cell.mBase : cell.mModified; CellRef ref; - - bool deleted = false; ESM::MovedCellRef mref; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, deleted, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -50,17 +48,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool // https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30 ref.mOriginalCell = cell2.mId; - if (deleted) - { - // FIXME: how to mark the record deleted? - CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, - mCells.getId (cellIndex)); - - messages.add (id, "Moved reference "+ref.mRefID+" is in DELE state"); - - continue; - } - // It is not always possibe to ignore moved references sub-record and // calculate from coordinates. Some mods may place the ref in positions // outside normal bounds, resulting in non sensical cell id's. This often @@ -92,7 +79,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool break; } - if (deleted) + if (ref.mIsDeleted) { if (iter==cache.end()) { @@ -100,7 +87,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool mCells.getId (cellIndex)); messages.add (id, "Attempt to delete a non-existing reference"); - continue; } @@ -108,7 +94,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool Record record = getRecord (index); - if (record.mState==RecordBase::State_BaseOnly) + if (base) { removeRows (index, 1); cache.erase (iter); From 2016ff773fbf0376c28dfaa9df0ff65d47052f84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 12:36:20 +0200 Subject: [PATCH 0726/1812] display script errors in script subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/scripterrortable.cpp | 87 +++++++++++++++++++++ apps/opencs/view/world/scripterrortable.hpp | 45 +++++++++++ apps/opencs/view/world/scriptsubview.cpp | 33 +++++++- apps/opencs/view/world/scriptsubview.hpp | 4 + 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/world/scripterrortable.cpp create mode 100644 apps/opencs/view/world/scripterrortable.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4c7801d461..96e5a5b32d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar tableeditidaction + dialoguespinbox recordbuttonbar tableeditidaction scripterrortable ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp new file mode 100644 index 0000000000..0c97339dc9 --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -0,0 +1,87 @@ + +#include "scripterrortable.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + + +void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); +} + +void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error); +} + +void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, + CSMDoc::Message::Severity severity, int line) +{ + int row = rowCount(); + + setRowCount (row+1); + + setItem (row, 0, new QTableWidgetItem ("")); + + if (line!=-1) + { + QTableWidgetItem *item = new QTableWidgetItem; + item->setData (Qt::DisplayRole, line+1); + setItem (row, 1, item); + } + + setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); +} + +CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) +: QTableWidget (parent), mContext (document.getData()) +{ + setColumnCount (3); + + QStringList headers; + headers << "Severity" << "Line" << "Description"; + setHorizontalHeaderLabels (headers); + horizontalHeader()->setStretchLastSection (true); + + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); +} + +void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) +{ + +} + +void CSVWorld::ScriptErrorTable::update (const std::string& source) +{ + setRowCount (0); + + try + { + std::istringstream input (source); + + Compiler::Scanner scanner (*this, input, mContext.getExtensions()); + + Compiler::FileParser parser (*this, mContext); + + scanner.scan (parser); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); + } +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp new file mode 100644 index 0000000000..791125c127 --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -0,0 +1,45 @@ +#ifndef CSV_WORLD_SCRIPTERRORTABLE_H +#define CSV_WORLD_SCRIPTERRORTABLE_H + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" +#include "../../model/doc/messages.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler + { + Q_OBJECT + + Compiler::Extensions mExtensions; + CSMWorld::ScriptContext mContext; + + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + + void addMessage (const std::string& message, CSMDoc::Message::Severity severity, + int line = -1); + + public: + + ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); + + void updateUserSetting (const QString& name, const QStringList& value); + + void update (const std::string& source); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 181400c888..d48e647d9b 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -17,6 +18,7 @@ #include "recordbuttonbar.hpp" #include "tablebottombox.hpp" #include "genericcreator.hpp" +#include "scripterrortable.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -40,7 +42,16 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mMain = new QSplitter (this); + mMain->setOrientation (Qt::Vertical); + mLayout.addWidget (mMain, 2); + + mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this); + mMain->addWidget (mEditor); + mMain->setCollapsible (0, false); + + mErrors = new ScriptErrorTable (document, this); + mMain->addWidget (mErrors); QWidget *widget = new QWidget (this);; widget->setLayout (&mLayout); @@ -60,7 +71,9 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (mColumn==-1) throw std::logic_error ("Can't find script column"); - mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); + + mEditor->setPlainText (source); // bottom box and buttons mBottom = new TableBottomBox (CreatorFactory(), document, id, this); @@ -83,6 +96,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -116,6 +131,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr if (mButtons) mButtons->updateUserSetting (name, value); + + mErrors->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -173,8 +190,12 @@ void CSVWorld::ScriptSubView::textChanged() ScriptEdit::ChangeLock lock (*mEditor); + QString source = mEditor->toPlainText(); + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, - mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); + mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -189,9 +210,13 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && index.column()>=topLeft.column() && index.column()<=bottomRight.column()) { + QString source = mModel->data (index).toString(); + QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setPlainText (source); mEditor->setTextCursor (cursor); + + mErrors->update (source.toUtf8().constData()); } } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6e5276c682..0b6f4d9239 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -10,6 +10,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; +class QSplitter; namespace CSMDoc { @@ -26,6 +27,7 @@ namespace CSVWorld class ScriptEdit; class RecordButtonBar; class TableBottomBox; + class ScriptErrorTable; class ScriptSubView : public CSVDoc::SubView { @@ -39,6 +41,8 @@ namespace CSVWorld RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; + QSplitter *mMain; + ScriptErrorTable *mErrors; private: From 2d8a78726dbab573041cd97d922a4814bc3471ff Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:09:14 +0200 Subject: [PATCH 0727/1812] improved error reporting --- apps/opencs/view/world/scripterrortable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 0c97339dc9..cb793237ae 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -14,7 +14,10 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { - addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + std::ostringstream stream; + stream << message << " (" << loc.mLiteral << ")"; + + addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); } From 9b12b4f1e25dff384137a8915ddc460acdbd749e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:46:02 +0200 Subject: [PATCH 0728/1812] refactored mapping from message severity enum to string --- apps/opencs/model/doc/messages.cpp | 16 +++++++++++++++- apps/opencs/model/doc/messages.hpp | 8 +++++--- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++------------- apps/opencs/view/world/scripterrortable.cpp | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index bd6e808c82..c8d26d39bb 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -8,6 +8,20 @@ CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& me : mId (id), mMessage (message), mHint (hint), mSeverity (severity) {} +std::string CSMDoc::Message::toString (Severity severity) +{ + switch (severity) + { + case CSMDoc::Message::Severity_Info: return "Information"; + case CSMDoc::Message::Severity_Warning: return "Warning"; + case CSMDoc::Message::Severity_Error: return "Error"; + case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; + case CSMDoc::Message::Severity_Default: break; + } + + return ""; +} + CSMDoc::Messages::Messages (Message::Severity default_) : mDefault (default_) @@ -18,7 +32,7 @@ void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& { if (severity==Message::Severity_Default) severity = mDefault; - + mMessages.push_back (Message (id, message, hint, severity)); } diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 86f5feb152..429feae4ec 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -21,18 +21,20 @@ namespace CSMDoc // reporting it correctly Severity_Default = 4 }; - + CSMWorld::UniversalId mId; std::string mMessage; std::string mHint; Severity mSeverity; Message(); - + Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity); + + static std::string toString (Severity severity); }; - + class Messages { public: diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 480691710d..4bf7d1581d 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -13,7 +13,7 @@ CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn) if (severityColumn) mColumnSeverity = index++; - + if (fieldColumn) mColumnField = index++; @@ -46,7 +46,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const case Column_Type: return static_cast (mRows.at (index.row()).mId.getType()); - + case Column_Id: { CSMWorld::UniversalId id = mRows.at (index.row()).mId; @@ -56,7 +56,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - + case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); @@ -85,16 +85,10 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (index.column()==mColumnSeverity) { - switch (mRows.at (index.row()).mSeverity) - { - case CSMDoc::Message::Severity_Info: return "Information"; - case CSMDoc::Message::Severity_Warning: return "Warning"; - case CSMDoc::Message::Severity_Error: return "Error"; - case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; - case CSMDoc::Message::Severity_Default: break; - } + return QString::fromUtf8 ( + CSMDoc::Message::toString (mRows.at (index.row()).mSeverity).c_str()); } - + return QVariant(); } @@ -144,7 +138,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p void CSMTools::ReportModel::add (const CSMDoc::Message& message) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - + mRows.push_back (message); endInsertRows(); diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index cb793237ae..dfa0368244 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,7 +34,7 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem ("")); + setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); if (line!=-1) { From f6f82d433c77cb68b16d88785ed210179287addd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:55:05 +0200 Subject: [PATCH 0729/1812] Fix bug with loop key assignment Animations with time of "loop start" == time of "loop stop" were not getting their loop times assigned correctly. This fixes incorrect playing of the jump animation, one aspect of Bug #2286. --- apps/openmw/mwrender/animation.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 84f46c4ab8..dab289f6c7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -598,23 +598,20 @@ namespace MWRender state.setTime(state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint)); // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation - // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.getTime() > state.mStartTime) + // (see handleTextKey). But if startpoint is already past these keys, or start time is == stop time, we need to assign them now. + const std::string loopstarttag = groupname+": loop start"; + const std::string loopstoptag = groupname+": loop stop"; + + NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + for (; key != startkey && key != keys.rend(); ++key) { - const std::string loopstarttag = groupname+": loop start"; - const std::string loopstoptag = groupname+": loop stop"; + if (key->first > state.getTime()) + continue; - NifOsg::TextKeyMap::const_reverse_iterator key(groupend); - for (; key != startkey && key != keys.rend(); ++key) - { - if (key->first > state.getTime()) - continue; - - if (key->second == loopstarttag) - state.mLoopStartTime = key->first; - else if (key->second == loopstoptag) - state.mLoopStopTime = key->first; - } + if (key->second == loopstarttag) + state.mLoopStartTime = key->first; + else if (key->second == loopstoptag) + state.mLoopStopTime = key->first; } return true; From b5c79738f10822f0814e3244100ed5ade56bb99b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:56:09 +0200 Subject: [PATCH 0730/1812] Fix enchantments casting more than once per button press, broken by a1432b0255dd659 --- apps/openmw/mwmechanics/character.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 95546dca93..9ccee84f62 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,6 +43,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" namespace { @@ -1169,6 +1170,10 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); + } const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); From cc59493cb2e227561eea680c5e34c8dc794cbf2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:03:16 +0200 Subject: [PATCH 0731/1812] Don't restart the jump animation when equipping a different weapon (Fixes #2286) --- apps/openmw/mwmechanics/character.cpp | 39 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9ccee84f62..8fa02c3cd4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -237,7 +237,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) +void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force) { // hit recoils/knockdown animations handling if(mPtr.getClass().isActor()) @@ -314,40 +314,41 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; - if(force && mJumpState != JumpState_None) + if(force || jump != mJumpState) { - std::string jump; + bool startAtLoop = (jump == mJumpState); + mJumpState = jump; + + std::string jumpAnimName; MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { - jump = "jump"; + jumpAnimName = "jump"; if(weap != sWeaponTypeListEnd) { - jump += weap->shortgroup; - if(!mAnimation->hasAnimation(jump)) + jumpAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(jumpAnimName)) { jumpmask = MWRender::Animation::BlendMask_LowerBody; - jump = "jump"; + jumpAnimName = "jump"; } } } if(mJumpState == JumpState_InAir) { - int mode = ((jump == mCurrentJump) ? 2 : 1); - mAnimation->disable(mCurrentJump); - mCurrentJump = jump; + mCurrentJump = jumpAnimName; if (mAnimation->hasAnimation("jump")) mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, - 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); } else { mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpmask, true, + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -717,7 +718,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mDeathState == CharState_None) - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); } @@ -1556,6 +1557,8 @@ void CharacterController::update(float duration) CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; + JumpingState jumpstate = JumpState_None; + bool forcestateupdate = false; mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; @@ -1638,7 +1641,7 @@ void CharacterController::update(float duration) } forcestateupdate = (mJumpState != JumpState_InAir); - mJumpState = JumpState_InAir; + jumpstate = JumpState_InAir; static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); @@ -1683,7 +1686,7 @@ void CharacterController::update(float duration) else if(mJumpState == JumpState_InAir) { forcestateupdate = true; - mJumpState = JumpState_Landing; + jumpstate = JumpState_Landing; vec.z() = 0.0f; float height = cls.getCreatureStats(mPtr).land(); @@ -1714,7 +1717,7 @@ void CharacterController::update(float duration) } else { - mJumpState = JumpState_None; + jumpstate = JumpState_None; vec.z() = 0.0f; inJump = false; @@ -1792,7 +1795,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; if (!mSkipAnim) - refreshCurrentAnims(idlestate, movestate, forcestateupdate); + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); if (inJump) mMovementAnimationControlled = false; @@ -1928,7 +1931,7 @@ void CharacterController::forceStateUpdate() return; clearAnimQueue(); - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); if(mDeathState != CharState_None) { playRandomDeath(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6b530ae2a8..f37afd996a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -186,7 +186,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void determineAttackType(); - void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); + void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void clearAnimQueue(); From 9a115fedbc724ce29e3cae8da6a19d24c28a0fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:11:33 +0200 Subject: [PATCH 0732/1812] Add ability to copy&paste the version label in the main menu --- files/mygui/openmw_mainmenu.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_mainmenu.layout b/files/mygui/openmw_mainmenu.layout index f4c7142ce7..c4d88ff855 100644 --- a/files/mygui/openmw_mainmenu.layout +++ b/files/mygui/openmw_mainmenu.layout @@ -3,10 +3,12 @@ - + + + From 660e7f5d893ffde813df4f178b891797caa35102 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:28:17 +0200 Subject: [PATCH 0733/1812] Don't update animation states in skipAnim mode (Fixes #2782) --- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8fa02c3cd4..50faaa91ba 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1788,14 +1788,17 @@ void CharacterController::update(float duration) } } - // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. - if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) - forcestateupdate = updateWeaponState() || forcestateupdate; - else - forcestateupdate = updateCreatureState() || forcestateupdate; - if (!mSkipAnim) + { + // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. + if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) + forcestateupdate = updateWeaponState() || forcestateupdate; + else + forcestateupdate = updateCreatureState() || forcestateupdate; + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + } + if (inJump) mMovementAnimationControlled = false; From 91d71d0fcd690559a47dec6a889ca189ee09a199 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:39:09 +0200 Subject: [PATCH 0734/1812] Disable MyGUI's scrollbar autorepeat (Fixes #2779) We are currently using a custom implementation so as to support MyGUI version 3.2.1. When compiled with 3.2.2 or later, we need to disable MyGUI's autorepeat so that it doesn't interfere with ours. --- apps/openmw/mwgui/widgets.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 158d5fd5e4..481ffaadec 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -539,6 +539,9 @@ namespace MWGui , mRepeatStepTime(0.1f) , mIsIncreasing(true) { +#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,2) + ScrollBar::setRepeatEnabled(false); +#endif } MWScrollBar::~MWScrollBar() From 83ef1f7eea99d02be09408398437682f72e0cacf Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 00:56:15 -0500 Subject: [PATCH 0735/1812] Add support for linking OpenSceneGraph statically Added some basic support for linking to OpenSceneGraph and its plugins statically. Also added a library necessary to statically link MyGUI (previously Ogre pulled it in). --- CMakeLists.txt | 62 +++++++++++++++++++++++++- cmake/FindMyGUI.cmake | 1 + components/resource/texturemanager.cpp | 13 ++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a4..a151c85034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,8 @@ configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_ option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" FALSE) +option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) @@ -199,9 +201,67 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) +if(OSG_STATIC) + macro(use_static_osg_plugin_library PLUGIN_NAME) + set(PLUGIN_NAME_DBG ${PLUGIN_NAME}d ${PLUGIN_NAME}D ${PLUGIN_NAME}_d ${PLUGIN_NAME}_D ${PLUGIN_NAME}_debug ${PLUGIN_NAME}) + + # For now, users wishing to do a static build will need to pass the path to where the plugins reside + # More clever logic would need to deduce the path, probably installed under /lib/osgPlugins- + find_library(${PLUGIN_NAME}_LIBRARY_REL NAMES ${PLUGIN_NAME} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + find_library(${PLUGIN_NAME}_LIBRARY_DBG NAMES ${PLUGIN_NAME_DBG} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + make_library_set(${PLUGIN_NAME}_LIBRARY) + + if("${${PLUGIN_NAME}_LIBRARY}" STREQUAL "") + message(FATAL_ERROR "Unable to find static OpenSceneGraph plugin: ${PLUGIN_NAME}") + endif() + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${PLUGIN_NAME}_LIBRARY}) + endmacro() + + macro(use_static_osg_plugin_dep DEPENDENCY) + find_package(${DEPENDENCY} REQUIRED) + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${DEPENDENCY}_LIBRARIES}) + endmacro() + + add_definitions(-DOSG_LIBRARY_STATIC) + + set(PLUGIN_LIST + osgdb_png # depends on libpng, zlib + osgdb_tga + osgdb_dds + osgdb_jpeg # depends on libjpeg + ) + + foreach(PLUGIN ${PLUGIN_LIST}) + use_static_osg_plugin_library(${PLUGIN}) + endforeach() + + # OSG static plugins need to linked against their respective dependencies + set(PLUGIN_DEPS_LIST + PNG # needed by osgdb_png + ZLIB # needed by osgdb_png + JPEG # needed by osgdb_jpeg + ) + + foreach(DEPENDENCY ${PLUGIN_DEPS_LIST}) + use_static_osg_plugin_dep(${DEPENDENCY}) + endforeach() +endif() + +if(QT_STATIC) + if(WIN32) + if(DESIRED_QT_VERSION MATCHES 4) + # QtCore needs WSAAsyncSelect from Ws2_32.lib + set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib) + message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}") + endif() + endif() +endif() + find_package(MyGUI REQUIRED) if (${MYGUI_VERSION} VERSION_LESS "3.2.1") message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info") diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 320765b537..f85b6ba523 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -54,6 +54,7 @@ IF (WIN32) #Windows if ( MYGUI_STATIC ) set(LIB_SUFFIX "Static") + find_package(freetype) endif ( MYGUI_STATIC ) find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb39..eca711b3c1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,11 +1,24 @@ #include "texturemanager.hpp" #include +#include #include #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From eab1ec9160674db02c5b701479e86d5acb8c3f43 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 11:52:59 +0200 Subject: [PATCH 0736/1812] consider script warning settings for script subview --- apps/opencs/view/world/scripterrortable.cpp | 19 +++++++++++++++++-- apps/opencs/view/world/scripterrortable.hpp | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dfa0368244..29f1d6820a 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -10,7 +10,7 @@ #include #include "../../model/doc/document.hpp" - +#include "../../model/settings/usersettings.hpp" void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -44,6 +44,18 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, } setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + + +} + +void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) +{ + if (value=="Ignore") + Compiler::ErrorHandler::setWarningsMode (0); + else if (value=="Normal") + Compiler::ErrorHandler::setWarningsMode (1); + else if (value=="Strict") + Compiler::ErrorHandler::setWarningsMode (2); } CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) @@ -58,11 +70,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); + + setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) { - + if (name=="script-editor/warnings" && !value.isEmpty()) + setWarningsMode (value.at (0)); } void CSVWorld::ScriptErrorTable::update (const std::string& source) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 791125c127..99557fb0d6 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -32,6 +32,8 @@ namespace CSVWorld void addMessage (const std::string& message, CSMDoc::Message::Severity severity, int line = -1); + void setWarningsMode (const QString& value); + public: ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); From 56ed0926bd9360365214450f61e3166f952f8ef3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 12:45:08 +0200 Subject: [PATCH 0737/1812] improved error table layout --- apps/opencs/view/world/scripterrortable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 29f1d6820a..dc28b8907a 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -66,7 +66,10 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); + horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); + verticalHeader()->hide(); Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); From 100af80388c197e191e71b6d6e533395b006d427 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:06:51 +0200 Subject: [PATCH 0738/1812] made error table read only --- apps/opencs/view/world/scripterrortable.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dc28b8907a..460bedefce 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,16 +34,22 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); + QTableWidgetItem *severityItem = new QTableWidgetItem ( + QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str())); + severityItem->setFlags (severityItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 0, severityItem); if (line!=-1) { - QTableWidgetItem *item = new QTableWidgetItem; - item->setData (Qt::DisplayRole, line+1); - setItem (row, 1, item); + QTableWidgetItem *lineItem = new QTableWidgetItem; + lineItem->setData (Qt::DisplayRole, line+1); + lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 1, lineItem); } - setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); + messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 2, messageItem); } From 0abd29a3b455e9fa0f55be0565ee8a1723473816 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:42:25 +0200 Subject: [PATCH 0739/1812] jump to line in source text when clicking on an error in error table --- apps/opencs/view/world/scripterrortable.cpp | 10 ++++++++++ apps/opencs/view/world/scripterrortable.hpp | 8 ++++++++ apps/opencs/view/world/scriptsubview.cpp | 16 ++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 4 files changed, 36 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 460bedefce..242d6c8ac9 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -77,10 +77,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setSelectionMode (QAbstractItemView::NoSelection); + Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); + + connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int))); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) @@ -112,3 +116,9 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); } } + +void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) +{ + int line = item (row, 1)->data (Qt::DisplayRole).toInt(); + emit highlightError (line-1); +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 99557fb0d6..5c6e751649 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -41,6 +41,14 @@ namespace CSVWorld void updateUserSetting (const QString& name, const QStringList& value); void update (const std::string& source); + + private slots: + + void cellClicked (int row, int column); + + signals: + + void highlightError (int line); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d48e647d9b..36e21d53b9 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -98,6 +98,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); mErrors->update (source.toUtf8().constData()); + + connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -244,3 +246,17 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) { switchToRow (mModel->getModelIndex (id, 0).row()); } + +void CSVWorld::ScriptSubView::highlightError (int line) +{ + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + { +// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + } + + mEditor->setFocus(); + mEditor->setTextCursor (cursor); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0b6f4d9239..6be943bb80 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -75,6 +75,8 @@ namespace CSVWorld void switchToRow (int row); void switchToId (const std::string& id); + + void highlightError (int line); }; } From f665919046bf1b923424ad0af7944f60f8a5d47b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:53:22 +0200 Subject: [PATCH 0740/1812] consider column when jumping to error in source text --- apps/opencs/view/world/scripterrortable.cpp | 20 +++++++++++++------- apps/opencs/view/world/scripterrortable.hpp | 4 ++-- apps/opencs/view/world/scriptsubview.cpp | 9 ++++----- apps/opencs/view/world/scriptsubview.hpp | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 242d6c8ac9..ec84a83284 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -18,7 +18,8 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compi stream << message << " (" << loc.mLiteral << ")"; addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? - CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, + loc.mLine, loc.mColumn-loc.mLiteral.length()); } void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) @@ -28,7 +29,7 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) } void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, - CSMDoc::Message::Severity severity, int line) + CSMDoc::Message::Severity severity, int line, int column) { int row = rowCount(); @@ -45,13 +46,16 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, lineItem->setData (Qt::DisplayRole, line+1); lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); setItem (row, 1, lineItem); + + QTableWidgetItem *columnItem = new QTableWidgetItem; + columnItem->setData (Qt::DisplayRole, column); + columnItem->setFlags (columnItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 3, columnItem); } QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); setItem (row, 2, messageItem); - - } void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) @@ -67,7 +71,7 @@ void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) : QTableWidget (parent), mContext (document.getData()) { - setColumnCount (3); + setColumnCount (4); QStringList headers; headers << "Severity" << "Line" << "Description"; @@ -76,6 +80,7 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setColumnHidden (3, true); setSelectionMode (QAbstractItemView::NoSelection); @@ -119,6 +124,7 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int line = item (row, 1)->data (Qt::DisplayRole).toInt(); - emit highlightError (line-1); + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); } diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 5c6e751649..f16a96a74c 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -30,7 +30,7 @@ namespace CSVWorld ///< Report a file related error void addMessage (const std::string& message, CSMDoc::Message::Severity severity, - int line = -1); + int line = -1, int column = -1); void setWarningsMode (const QString& value); @@ -48,7 +48,7 @@ namespace CSVWorld signals: - void highlightError (int line); + void highlightError (int line, int column); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 36e21d53b9..7b5b1131e3 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -99,7 +99,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mErrors->update (source.toUtf8().constData()); - connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); + connect (mErrors, SIGNAL (highlightError (int, int)), + this, SLOT (highlightError (int, int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -247,15 +248,13 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) switchToRow (mModel->getModelIndex (id, 0).row()); } -void CSVWorld::ScriptSubView::highlightError (int line) +void CSVWorld::ScriptSubView::highlightError (int line, int column) { QTextCursor cursor = mEditor->textCursor(); cursor.movePosition (QTextCursor::Start); if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) - { -// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); - } + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); mEditor->setFocus(); mEditor->setTextCursor (cursor); diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6be943bb80..a9c8dccb38 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -76,7 +76,7 @@ namespace CSVWorld void switchToId (const std::string& id); - void highlightError (int line); + void highlightError (int line, int column); }; } From 5febb96012ea68dda6cb367a18e1fe59a41cb39d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:59:50 +0200 Subject: [PATCH 0741/1812] do not try to jump to source location for errors that do not have a source location --- apps/opencs/view/world/scripterrortable.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index ec84a83284..20b197c54e 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -124,7 +124,10 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); - int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); - emit highlightError (scriptLine-1, scriptColumn); + if (item (row, 1)) + { + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); + } } From 72728b9c01058ee2d2a6625fd0e542eeb45b14db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 16:32:35 +0200 Subject: [PATCH 0742/1812] disable cusor when item/container is owned --- apps/openmw/mwgui/tooltips.cpp | 22 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 6 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 526cbaabe3..18f65e3ba1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -342,6 +343,27 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); + + // start owned check + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + if(allowed) + { + // if 'item' is not owned + wm->showCrosshair(true); + } + else + { + // if 'item' is owned + wm->showCrosshair(false); + } + } return tooltipSize; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5cc2ce2543..392d7fbbe4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -175,13 +175,15 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + }; } From df99d5a59d98410391cd2bfe70290db79748b7d9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 09:56:21 -0500 Subject: [PATCH 0743/1812] Move setup code for OSG when statically linked --- components/resource/texturemanager.cpp | 13 ------------- components/sdlutil/sdlcursormanager.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index eca711b3c1..62cbd6bb39 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,24 +1,11 @@ #include "texturemanager.hpp" #include -#include #include #include -#ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - -// Sets the default windowing system interface according to the OS. -// Necessary for OpenSceneGraph to do some things, like decompression. -USE_GRAPHICSWINDOW() -#endif - namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index d8d4b0b506..508d725898 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,9 +10,23 @@ #include #include #include +#include +#include #include "imagetosurface.hpp" +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From 66edae9b932988fbe0fff29260c3d5bf82d88bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:29:00 +0200 Subject: [PATCH 0744/1812] change collor of crosshair --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/hud.cpp | 16 +++++++++++- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 36 ++++++++++++++------------ apps/openmw/mwgui/tooltips.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2d..86b42c9f97 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,6 +219,7 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; + virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 76a7248ee4..0f107f4e39 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -518,7 +518,21 @@ namespace MWGui { mCrosshair->setVisible (visible); } - + + void HUD::setCrosshairOwned(bool owned) + { + MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); + MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); + if(owned) + { + mCrosshair->setColour(red); + } + else + { + mCrosshair->setColour(white); + } + } + void HUD::setHmsVisible(bool visible) { mHealth->setVisible(visible); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 72fc06f6a5..629613c982 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -47,6 +47,7 @@ namespace MWGui void unsetSelectedWeapon(); void setCrosshairVisible(bool visible); + void setCrosshairOwned(bool owned); void onFrame(float dt); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 18f65e3ba1..34762de5a7 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -299,7 +299,10 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); + } + + checkOwned(); } } @@ -344,29 +347,30 @@ namespace MWGui info.icon = ""; tooltipSize = createToolTip(info); - // start owned check + } + + return tooltipSize; + } + + void ToolTips::checkOwned() + { + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + + if(!mFocusObject.isEmpty()) + { MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if(allowed) - { - // if 'item' is not owned - wm->showCrosshair(true); - } - else - { - // if 'item' is owned - wm->showCrosshair(false); - } - - } - return tooltipSize; + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index d14993639a..a54888780d 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -95,6 +95,9 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size + + void checkOwned(); + /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a8261617..2588f2d86b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1423,6 +1423,12 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } + + void WindowManager::setCrosshairOwned (bool owned) + { + if (mHud) + mHud->setCrosshairOwned (owned); + } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a817..94538840bf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,6 +233,7 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); + virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 15107ca5cf4085792a57e10dbcdb7974e8d675b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:48:38 +0200 Subject: [PATCH 0745/1812] crosshair owned - settings option --- apps/openmw/mwgui/tooltips.cpp | 29 ++++++++++++++++------------- files/settings-default.cfg | 3 +++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 34762de5a7..51bdd97f96 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -354,22 +354,25 @@ namespace MWGui void ToolTips::checkOwned() { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - - if(!mFocusObject.isEmpty()) + if(Settings::Manager::getBool("show owned", "Game")) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + if(!mFocusObject.isEmpty()) + { + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0581d73562..4ec0c2480f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,6 +162,9 @@ best attack = false difficulty = 0 +# change crosshair color when pointing on owned object +show owned = false + [Saves] character = # Save when resting From c019f8e23dcef0a38ac9d934eb639eab2cf5cf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 18:49:47 +0200 Subject: [PATCH 0746/1812] use correct mechanics manager --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 ++++ apps/openmw/mwgui/tooltips.cpp | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 1d3619d3da..7889988e9e 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,6 +6,8 @@ #include #include +#include "../mwworld/ptr.hpp" + namespace osg { class Vec3f; @@ -211,6 +213,8 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 51bdd97f96..40df4a4b45 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,7 +17,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -364,7 +363,7 @@ namespace MWGui MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned wm->setCrosshairOwned(!allowed); From e68b388d161030ca1122bbebd4772017701b8dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 19:13:45 +0200 Subject: [PATCH 0747/1812] removed setCrosshairOwned from windowmanager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/tooltips.cpp | 32 +++++++++++--------------- apps/openmw/mwgui/tooltips.hpp | 6 ++--- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 86b42c9f97..f8bf157c2d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,7 +219,6 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; - virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 40df4a4b45..28ff472602 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -300,8 +300,6 @@ namespace MWGui mDynamicToolTipBox->setVisible(true); } - - checkOwned(); } } @@ -351,27 +349,23 @@ namespace MWGui return tooltipSize; } - void ToolTips::checkOwned() + bool ToolTips::checkOwned() { - if(Settings::Manager::getBool("show owned", "Game")) + // true=owned, false=notOwned + if(!mFocusObject.isEmpty()) { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; - if(!mFocusObject.isEmpty()) - { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); - } + return !allowed; + } + else + { + return false; } } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index a54888780d..26a4fe2c75 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -87,6 +87,9 @@ namespace MWGui static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace); static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass); static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); + + bool checkOwned(); + /// Checks if object is owned and sets correct crosshair mode private: MyGUI::Widget* mDynamicToolTipBox; @@ -95,9 +98,6 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size - - void checkOwned(); - /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2588f2d86b..2f8cfbf627 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1038,6 +1038,12 @@ namespace MWGui void WindowManager::setFocusObject(const MWWorld::Ptr& focus) { mToolTips->setFocusObject(focus); + + if(Settings::Manager::getBool("show owned", "Game") && mHud) + { + bool owned = mToolTips->checkOwned(); + mHud->setCrosshairOwned(owned); + } } void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) @@ -1423,12 +1429,6 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } - - void WindowManager::setCrosshairOwned (bool owned) - { - if (mHud) - mHud->setCrosshairOwned (owned); - } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 94538840bf..e6c8d0a817 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,7 +233,6 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); - virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 4a6d80612729e58d0a8c6441e39035423194ac7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 20:30:00 +0200 Subject: [PATCH 0748/1812] fixed comment, save settings to member variable, removed usless include, changed variable to const --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 5 +---- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7889988e9e..b66e60e1d6 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,8 +6,6 @@ #include #include -#include "../mwworld/ptr.hpp" - namespace osg { class Vec3f; @@ -25,6 +23,7 @@ namespace MWWorld { class Ptr; class CellStore; + class CellRef; } namespace Loading diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 28ff472602..22d5d14f7c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -298,7 +298,6 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); - } } } @@ -343,7 +342,6 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); - } return tooltipSize; @@ -351,10 +349,9 @@ namespace MWGui bool ToolTips::checkOwned() { - // true=owned, false=notOwned if(!mFocusObject.isEmpty()) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 26a4fe2c75..bd4a81c32c 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -89,8 +89,8 @@ namespace MWGui static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); bool checkOwned(); - /// Checks if object is owned and sets correct crosshair mode - + /// Returns True if taking mFocusObject would be crime + private: MyGUI::Widget* mDynamicToolTipBox; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2f8cfbf627..cb5d4442f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mShowOwned(false) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -261,6 +262,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); + + mShowOwned = Settings::Manager::getBool("show owned", "Game"); } void WindowManager::initUI() @@ -1039,7 +1042,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(Settings::Manager::getBool("show owned", "Game") && mHud) + if(mShowOwned && mHud) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a817..5c4b2d447d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -486,6 +486,8 @@ namespace MWGui float mFPS; std::map mFallbackMap; + + bool mShowOwned; /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. From 41bed4c7d9c2a1dc4a7f3e4444433a0d50df4a16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 20:49:10 +0200 Subject: [PATCH 0749/1812] Use multimap to speed up custom map marker code --- apps/openmw/mwgui/mapwindow.cpp | 118 ++++++++++++++----------- apps/openmw/mwgui/mapwindow.hpp | 12 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- components/esm/cellid.cpp | 23 +++++ components/esm/cellid.hpp | 1 + 5 files changed, 100 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 442fbeb081..7778569d2f 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -92,31 +92,41 @@ namespace MWGui void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent) { - mMarkers.push_back(marker); + mMarkers.insert(std::make_pair(marker.mCell, marker)); if (triggerEvent) eventMarkersChanged(); } void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - mMarkers.erase(it); - else - throw std::runtime_error("can't find marker to delete"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + mMarkers.erase(it); + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to delete"); } void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - it->mNote = newNote; - else - throw std::runtime_error("can't find marker to update"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + it->second.mNote = newNote; + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to update"); } void CustomMarkerCollection::clear() @@ -125,16 +135,21 @@ namespace MWGui eventMarkersChanged(); } - std::vector::const_iterator CustomMarkerCollection::begin() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::begin() const { return mMarkers.begin(); } - std::vector::const_iterator CustomMarkerCollection::end() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::end() const { return mMarkers.end(); } + CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId &cellId) const + { + return mMarkers.equal_range(cellId); + } + size_t CustomMarkerCollection::size() const { return mMarkers.size(); @@ -299,44 +314,43 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (int dX = -1; dX <= 1; ++dX) { - const ESM::CustomMarker& marker = *it; - - if (marker.mCell.mPaged != !mInterior) - continue; - if (mInterior) + for (int dY =-1; dY <= 1; ++dY) { - if (marker.mCell.mWorldspace != mPrefix) - continue; - } - else - { - if (std::abs(marker.mCell.mIndex.mX - mCurX) > 1) - continue; - if (std::abs(marker.mCell.mIndex.mY - mCurY) > 1) - continue; - } + ESM::CellId cellId; + cellId.mPaged = !mInterior; + cellId.mWorldspace = (mInterior ? mPrefix : "sys::default"); + cellId.mIndex.mX = mCurX+dX; + cellId.mIndex.mY = mCurY+dY; - MarkerUserData markerPos (mLocalMapRender); - MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + { + const ESM::CustomMarker& marker = it->second; - MyGUI::IntCoord widgetCoord(widgetPos.left - 8, - widgetPos.top - 8, - 16, 16); - MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", - widgetCoord, MyGUI::Align::Default); - markerWidget->setDepth(Local_MarkerAboveFogLayer); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); - markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); - markerWidget->setUserData(marker); - markerWidget->setNeedMouseFocus(true); - customMarkerCreated(markerWidget); - mCustomMarkerWidgets.push_back(markerWidget); + MarkerUserData markerPos (mLocalMapRender); + MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); + + MyGUI::IntCoord widgetCoord(widgetPos.left - 8, + widgetPos.top - 8, + 16, 16); + MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", + widgetCoord, MyGUI::Align::Default); + markerWidget->setDepth(Local_MarkerAboveFogLayer); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); + markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); + markerWidget->setUserData(marker); + markerWidget->setNeedMouseFocus(true); + customMarkerCreated(markerWidget); + mCustomMarkerWidgets.push_back(markerWidget); + } + } } + redraw(); } @@ -411,11 +425,9 @@ namespace MWGui MWBase::World::DoorMarker marker = *it; std::vector destNotes; - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) - { - if (it->mCell == marker.dest) - destNotes.push_back(it->mNote); - } + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); MarkerUserData data (mLocalMapRender); data.notes = destNotes; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 388103b5d2..ec42987862 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -42,14 +42,20 @@ namespace MWGui size_t size() const; - std::vector::const_iterator begin() const; - std::vector::const_iterator end() const; + typedef std::multimap ContainerType; + + typedef std::pair RangeType; + + ContainerType::const_iterator begin() const; + ContainerType::const_iterator end() const; + + RangeType getMarkers(const ESM::CellId& cellId) const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; private: - std::vector mMarkers; + ContainerType mMarkers; }; class LocalMapBase diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b190..4dbef8a745 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1672,10 +1672,10 @@ namespace MWGui writer.endRecord(ESM::REC_ASPL); } - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (CustomMarkerCollection::ContainerType::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { writer.startRecord(ESM::REC_MARK); - (*it).save(writer); + it->second.save(writer); writer.endRecord(ESM::REC_MARK); } } diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index 3c6e23ffd9..c77b27b227 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -35,3 +35,26 @@ bool ESM::operator!= (const CellId& left, const CellId& right) { return !(left==right); } + +bool ESM::operator < (const CellId& left, const CellId& right) +{ + if (left.mPaged < right.mPaged) + return true; + if (left.mPaged > right.mPaged) + return false; + + if (left.mPaged) + { + if (left.mIndex.mX < right.mIndex.mX) + return true; + if (left.mIndex.mX > right.mIndex.mX) + return false; + + if (left.mIndex.mY < right.mIndex.mY) + return true; + if (left.mIndex.mY > right.mIndex.mY) + return false; + } + + return left.mWorldspace < right.mWorldspace; +} diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 44a1b387a2..56d5a674ea 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -26,6 +26,7 @@ namespace ESM bool operator== (const CellId& left, const CellId& right); bool operator!= (const CellId& left, const CellId& right); + bool operator< (const CellId& left, const CellId& right); } #endif From 1b3cc957f836195cac56b0f7275ee0a646712c72 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:13:43 -0500 Subject: [PATCH 0750/1812] Move some OSG static library setup code --- components/resource/texturemanager.cpp | 8 ++++++++ components/sdlutil/sdlcursormanager.cpp | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb39..5da0a008a7 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -6,6 +6,14 @@ #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) +#endif + namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 508d725898..2004e806c2 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -16,12 +16,6 @@ #include "imagetosurface.hpp" #ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - // Sets the default windowing system interface according to the OS. // Necessary for OpenSceneGraph to do some things, like decompression. USE_GRAPHICSWINDOW() From 420789baa9f8418c146f0532d84171d697ec2f61 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:26:04 -0500 Subject: [PATCH 0751/1812] Remove an unused include --- components/sdlutil/sdlcursormanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 2004e806c2..89928d1651 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "imagetosurface.hpp" From 6e493500c9099a646598ae92984cd66f54aa6ca7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 00:14:11 +0200 Subject: [PATCH 0752/1812] Show custom map markers on the tooltip of the world map marker (Fixes #2711) --- apps/openmw/mwgui/mapwindow.cpp | 57 +++++++++++++++++++++++++++++---- apps/openmw/mwgui/mapwindow.hpp | 7 ++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7778569d2f..2485f3c948 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,15 +783,19 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); + + markerWidget->setUserString("Caption_TextOneLine", name); + + setGlobalMapMarkerTooltip(markerWidget, x, y); + + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setNeedMouseFocus(true); markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}"))); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); markerWidget->setDepth(Global_MarkerLayer); markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - mGlobalMapMarkers.push_back(markerWidget); + mGlobalMapMarkers[std::make_pair(x,y)] = markerWidget; } } @@ -816,6 +820,45 @@ namespace MWGui NoDrop::onFrame(dt); } + void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y) + { + ESM::CellId cellId; + cellId.mIndex.mX = x; + cellId.mIndex.mY = y; + cellId.mWorldspace = "sys::default"; + cellId.mPaged = true; + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + std::vector destNotes; + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); + + if (!destNotes.empty()) + { + MarkerUserData data (NULL); + data.notes = destNotes; + data.caption = markerWidget->getUserString("Caption_TextOneLine"); + markerWidget->setUserData(data); + markerWidget->setUserString("ToolTipType", "MapMarker"); + } + else + { + markerWidget->setUserString("ToolTipType", "Layout"); + } + } + + void MapWindow::updateCustomMarkers() + { + LocalMapBase::updateCustomMarkers(); + + for (std::map, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt) + { + int x = widgetIt->first.first; + int y = widgetIt->first.second; + MyGUI::Widget* markerWidget = widgetIt->second; + setGlobalMapMarkerTooltip(markerWidget, x, y); + } + } + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; @@ -913,8 +956,8 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - for (std::vector::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (std::map, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(it->second); mGlobalMapMarkers.clear(); } @@ -1034,6 +1077,8 @@ namespace MWGui bool LocalMapBase::MarkerUserData::isPositionExplored() const { + if (!mLocalMapRender) + return true; return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ec42987862..a5594bee82 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -126,7 +126,7 @@ namespace MWGui std::vector mMagicMarkerWidgets; std::vector mCustomMarkerWidgets; - void updateCustomMarkers(); + virtual void updateCustomMarkers(); void applyFogOfWar(); @@ -203,6 +203,8 @@ namespace MWGui void onFrame(float dt); + virtual void updateCustomMarkers(); + /// Clear all savegame-specific data void clear(); @@ -221,6 +223,7 @@ namespace MWGui void onNoteDoubleClicked(MyGUI::Widget* sender); void onChangeScrollWindowCoord(MyGUI::Widget* sender); void globalMapUpdatePlayer(); + void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); MyGUI::ScrollView* mGlobalMap; std::auto_ptr mGlobalMapTexture; @@ -248,7 +251,7 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; - std::vector mGlobalMapMarkers; + std::map, MyGUI::Widget*> mGlobalMapMarkers; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; From c783b50a8399411f705cad3c4fc91a0e60f13144 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 01:38:35 +0200 Subject: [PATCH 0753/1812] Fix config file priority in the launcher to match OpenMW --- apps/launcher/maindialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4b7c0504fd..99c40b88bd 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -309,11 +309,11 @@ bool Launcher::MainDialog::setupGameSettings() mGameSettings.readUserFile(stream); } - // Now the rest + // Now the rest - priority: user > local > global QStringList paths; - paths.append(userPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); paths.append(globalPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { qDebug() << "Loading config file:" << qPrintable(path); From f09e4620b6a730f0f2bbf660e18dd65d13a94d9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:01:06 +0200 Subject: [PATCH 0754/1812] Move OpenMW version information to a textfile instead of compiling it in Now we don't need to recompile 3 .cpp files and re-link whenever the current git HEAD changes. --- .gitignore | 1 - CMakeLists.txt | 2 ++ apps/launcher/maindialog.cpp | 47 +++++++++++++++----------- apps/launcher/maindialog.hpp | 2 ++ apps/openmw/engine.cpp | 5 +-- apps/openmw/main.cpp | 16 ++++----- apps/openmw/mwgui/mainmenu.cpp | 19 ++--------- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++- cmake/GitVersion.cmake | 2 +- components/CMakeLists.txt | 26 +++++++------- components/version/version.cpp | 41 ++++++++++++++++++++++ components/version/version.hpp | 28 +++++++++++++++ components/version/version.hpp.cmake | 13 ------- files/version.in | 3 ++ 16 files changed, 135 insertions(+), 81 deletions(-) create mode 100644 components/version/version.cpp create mode 100644 components/version/version.hpp delete mode 100644 components/version/version.hpp.cmake create mode 100644 files/version.in diff --git a/.gitignore b/.gitignore index 944fb84181..88f591aae9 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ resources ## generated objects apps/openmw/config.hpp -components/version/version.hpp docs/mainpage.hpp moc_*.cxx *.cxx_parameters diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a4..37680c13ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,6 +366,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) @@ -381,6 +382,7 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 99c40b88bd..c18c26cdda 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -57,26 +57,6 @@ Launcher::MainDialog::MainDialog(QWidget *parent) // Remove what's this? button setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); - // Add version information to bottom of the window - QString revision(OPENMW_VERSION_COMMITHASH); - QString tag(OPENMW_VERSION_TAGHASH); - - versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION)); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } - - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } - createIcons(); } @@ -186,11 +166,38 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; } +void Launcher::MainDialog::setVersionLabel() +{ + // Add version information to bottom of the window + Version::Version v = Version::getOpenmwVersion(mGameSettings.value("resources").toUtf8().constData()); + + QString revision(QString::fromUtf8(v.mCommitHash.c_str())); + QString tag(QString::fromUtf8(v.mTagHash.c_str())); + + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (!revision.isEmpty() && !tag.isEmpty()) + { + if (revision == tag) { + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + } else { + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); + } + + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); + } +} + bool Launcher::MainDialog::setup() { if (!setupGameSettings()) return false; + setVersionLabel(); + mLauncherSettings.setContentList(mGameSettings); if (!setupGraphicsSettings()) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c903099901..298682d207 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -72,6 +72,8 @@ namespace Launcher bool setupGameSettings(); bool setupGraphicsSettings(); + void setVersionLabel(); + void loadSettings(); void saveSettings(); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f373..fb879d2733 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include "mwinput/inputmanagerimp.hpp" @@ -493,7 +493,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) rootNode->addChild(guiRoot); MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, - mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); + mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap, + Version::getOpenmwVersionDescription(mResDir.string())); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 85a0dbe55d..3d631c7439 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -199,18 +199,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat return false; } - std::cout << "OpenMW version " << OPENMW_VERSION; - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0, 10); - std::cout << " (revision " << rev << ")"; - } - std::cout << std::endl; - if (variables.count ("version")) + { + cfgMgr.readConfiguration(variables, desc, true); + + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + std::cout << v.describe() << std::endl; return false; + } cfgMgr.readConfiguration(variables, desc); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e24894e89f..4093069865 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include #include @@ -28,7 +26,7 @@ namespace MWGui { - MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs) + MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) : Layout("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) @@ -38,20 +36,7 @@ namespace MWGui , mSaveGameDialog(NULL) { getWidget(mVersionText, "VersionText"); - std::stringstream sstream; - sstream << "OpenMW Version: " << OPENMW_VERSION; - - // adding info about git hash if available - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0,10); - sstream << "\nRevision: " << rev; - } - - std::string output = sstream.str(); - mVersionText->setCaption(output); + mVersionText->setCaption(versionDescription); mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index d01f67fbd2..fe256dc8ed 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -29,7 +29,7 @@ namespace MWGui public: - MainMenu(int w, int h, const VFS::Manager* vfs); + MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription); ~MainMenu(); void onResChange(int w, int h); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a8261617..a739ea6e7b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -113,7 +113,7 @@ namespace MWGui WindowManager::WindowManager( osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) : mResourceSystem(resourceSystem) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -272,7 +273,7 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mLocalMapRender = new MWRender::LocalMap(mViewer); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a817..38af1a79e5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -116,7 +116,7 @@ namespace MWGui WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); virtual ~WindowManager(); void initUI(); @@ -487,6 +487,8 @@ namespace MWGui std::map mFallbackMap; + std::string mVersionDescription; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 0087461a12..0679e406c2 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -21,4 +21,4 @@ else (SUCCESS) message(WARNING "Failed to get valid version information from Git") endif (SUCCESS) -configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) +configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d91bb5c30d..85e61cee51 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,23 +1,23 @@ project (Components) # Version file -set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) -set (VERSION_HPP ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp) +set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") +set (VERSION_FILE "${OpenMW_BINARY_DIR}/resources/version") if (GIT_CHECKOUT) - add_custom_target (git-version - COMMAND ${CMAKE_COMMAND} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -DVERSION_HPP_IN=${VERSION_HPP_IN} - -DVERSION_HPP=${VERSION_HPP} - -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} - -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} - -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} - -DOPENMW_VERSION=${OPENMW_VERSION} + -DVERSION_IN_FILE=${VERSION_IN_FILE} + -DVERSION_FILE=${VERSION_FILE} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake - VERBATIM) + VERBATIM) else (GIT_CHECKOUT) - configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) + configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) find_package(OpenGL REQUIRED) diff --git a/components/version/version.cpp b/components/version/version.cpp new file mode 100644 index 0000000000..c87943f9e2 --- /dev/null +++ b/components/version/version.cpp @@ -0,0 +1,41 @@ +#include "version.hpp" + +#include +#include + +namespace Version +{ + +Version getOpenmwVersion(const std::string &resourcePath) +{ + boost::filesystem::path path (resourcePath + "/version"); + + boost::filesystem::ifstream stream (path); + + Version v; + std::getline(stream, v.mVersion); + std::getline(stream, v.mCommitHash); + std::getline(stream, v.mTagHash); + return v; +} + +std::string Version::describe() +{ + std::string str = "OpenMW version " + mVersion; + std::string rev = mCommitHash; + std::string tag = mTagHash; + if (!rev.empty() && !tag.empty()) + { + rev = rev.substr(0, 10); + str += "\nRevision: " + rev; + } + return str; +} + +std::string getOpenmwVersionDescription(const std::string &resourcePath) +{ + Version v = getOpenmwVersion(resourcePath); + return v.describe(); +} + +} diff --git a/components/version/version.hpp b/components/version/version.hpp new file mode 100644 index 0000000000..7371e786e0 --- /dev/null +++ b/components/version/version.hpp @@ -0,0 +1,28 @@ +#ifndef VERSION_HPP +#define VERSION_HPP + +#include + +namespace Version +{ + + struct Version + { + std::string mVersion; + std::string mCommitHash; + std::string mTagHash; + + std::string describe(); + }; + + /// Read OpenMW version from the version file located in resourcePath. + Version getOpenmwVersion(const std::string& resourcePath); + + /// Helper function to getOpenmwVersion and describe() it + std::string getOpenmwVersionDescription(const std::string& resourcePath); + +} + + +#endif // VERSION_HPP + diff --git a/components/version/version.hpp.cmake b/components/version/version.hpp.cmake deleted file mode 100644 index 4cdfa32f08..0000000000 --- a/components/version/version.hpp.cmake +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef VERSION_HPP -#define VERSION_HPP - -#define OPENMW_VERSION_MAJOR @OPENMW_VERSION_MAJOR@ -#define OPENMW_VERSION_MINOR @OPENMW_VERSION_MINOR@ -#define OPENMW_VERSION_RELEASE @OPENMW_VERSION_RELEASE@ -#define OPENMW_VERSION "@OPENMW_VERSION@" - -#define OPENMW_VERSION_COMMITHASH "@OPENMW_VERSION_COMMITHASH@" -#define OPENMW_VERSION_TAGHASH "@OPENMW_VERSION_TAGHASH@" - -#endif // VERSION_HPP - diff --git a/files/version.in b/files/version.in new file mode 100644 index 0000000000..f894d3b4a5 --- /dev/null +++ b/files/version.in @@ -0,0 +1,3 @@ +@OPENMW_VERSION@ +@OPENMW_VERSION_COMMITHASH@ +@OPENMW_VERSION_TAGHASH@ From a33ca75742cc0be779041f236fcba2a3ef9f7320 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:23:41 +0200 Subject: [PATCH 0755/1812] Pass AnimPriority by const reference --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dab289f6c7..ee0ce6df1a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1cf2ce9bab..23f8072388 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -353,7 +353,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, + void play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 58720e6a28400a935733a3999229bceeb39c7a5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:52:38 +0200 Subject: [PATCH 0756/1812] Fix the OpenCS rendering crash on exit (Fixes #2735) --- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/data.hpp | 6 +++--- apps/opencs/view/render/cell.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 7 ++++--- apps/opencs/view/render/scenewidget.hpp | 8 +++++--- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a92a7ad793..3714117b6c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS()) + mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { int index = 0; @@ -537,14 +537,14 @@ CSMWorld::Data::~Data() delete mReader; } -Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() +boost::shared_ptr CSMWorld::Data::getResourceSystem() { - return &mResourceSystem; + return mResourceSystem; } -const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const +boost::shared_ptr CSMWorld::Data::getResourceSystem() const { - return &mResourceSystem; + return mResourceSystem; } const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6e651b3740..06f76607fd 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -113,7 +113,7 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; - Resource::ResourceSystem mResourceSystem; + boost::shared_ptr mResourceSystem; std::vector > mReaders; @@ -138,9 +138,9 @@ namespace CSMWorld const VFS::Manager* getVFS() const; - Resource::ResourceSystem* getResourceSystem(); + boost::shared_ptr getResourceSystem(); - const Resource::ResourceSystem* getResourceSystem() const; + boost::shared_ptr getResourceSystem() const; const IdCollection& getGlobals() const; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 063413248a..fe2eab0666 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -71,7 +71,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand->mX, esmLand->mY); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ea27b14320..973893a711 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -116,7 +116,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f0cbc939aa..f512a8bb6c 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -8,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable) +: SceneWidget (data.getResourceSystem(), parent), mData (data), mObject(data, mRootNode, id, referenceable) { mView->setCameraManipulator(new osgGA::TrackballManipulator); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 208a7a5b73..d91c075e17 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -132,9 +133,9 @@ void CompositeViewer::update() // --------------------------------------------------- -SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f) +SceneWidget::SceneWidget(boost::shared_ptr resourceSystem, QWidget *parent, Qt::WindowFlags f) : RenderWidget(parent, f) - , mSceneManager(sceneManager) + , mResourceSystem(resourceSystem) , mLighting(NULL) , mHasDefaultAmbient(false) { @@ -147,7 +148,7 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, SceneWidget::~SceneWidget() { // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects - mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); + mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } void SceneWidget::setLighting(Lighting *lighting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c269f355d1..f5c36b6418 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" @@ -13,7 +15,7 @@ namespace Resource { - class SceneManager; + class ResourceSystem; } namespace osg @@ -57,7 +59,7 @@ namespace CSVRender { Q_OBJECT public: - SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0); + SceneWidget(boost::shared_ptr resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~SceneWidget(); CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); @@ -73,7 +75,7 @@ namespace CSVRender void setAmbient(const osg::Vec4f& ambient); - Resource::SceneManager* mSceneManager; + boost::shared_ptr mResourceSystem; Lighting* mLighting; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3a70b7844f..39ce09f315 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -24,7 +24,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mSceneElements(0), mRun(0), mDocument(document), +: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0) { setAcceptDrops(true); From f8f03804138ad6f5c7e0422fe89b251b998b7a62 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 21:41:53 -0500 Subject: [PATCH 0757/1812] Fix for loading window icon on Windows --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f373..bfb8c71136 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -414,7 +414,7 @@ void OMW::Engine::setWindowIcon() { boost::filesystem::ifstream windowIconStream; std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); - windowIconStream.open(windowIcon); + windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) std::cerr << "Failed to open " << windowIcon << std::endl; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); From 39ab9948f637d5d30cf5ac780a5de2756ab1b053 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 11:40:18 +0200 Subject: [PATCH 0758/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index ce76c104e1..7774b5afa2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -59,6 +59,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 73b6df8280dee4ad747c5f296401f63eab9f1efd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 13:09:17 +0200 Subject: [PATCH 0759/1812] put script compilation in script subview behind a timer --- apps/opencs/view/world/scriptsubview.cpp | 29 ++++++++++++++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 6 +++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 7b5b1131e3..dfdca8b48a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -35,6 +36,12 @@ void CSVWorld::ScriptSubView::addButtonBar() mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } +void CSVWorld::ScriptSubView::recompile() +{ + if (!mCompileDelay->isActive()) + mCompileDelay->start (5000); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -101,6 +108,12 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mErrors, SIGNAL (highlightError (int, int)), this, SLOT (highlightError (int, int))); + + mCompileDelay = new QTimer (this); + mCompileDelay->setSingleShot (true); + connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); + + recompile(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -136,6 +149,9 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); mErrors->updateUserSetting (name, value); + + if (name=="script-editor/warnings") + recompile(); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -198,7 +214,7 @@ void CSVWorld::ScriptSubView::textChanged() mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); - mErrors->update (source.toUtf8().constData()); + recompile(); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -219,7 +235,7 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - mErrors->update (source.toUtf8().constData()); + recompile(); } } @@ -259,3 +275,12 @@ void CSVWorld::ScriptSubView::highlightError (int line, int column) mEditor->setFocus(); mEditor->setTextCursor (cursor); } + +void CSVWorld::ScriptSubView::updateRequest() +{ + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + QString source = mModel->data (index).toString(); + + mErrors->update (source.toUtf8().constData()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index a9c8dccb38..3481989f18 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -11,6 +11,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; class QSplitter; +class QTime; namespace CSMDoc { @@ -43,11 +44,14 @@ namespace CSVWorld QVBoxLayout mLayout; QSplitter *mMain; ScriptErrorTable *mErrors; + QTimer *mCompileDelay; private: void addButtonBar(); + void recompile(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -77,6 +81,8 @@ namespace CSVWorld void switchToId (const std::string& id); void highlightError (int line, int column); + + void updateRequest(); }; } From 8763a3b3c3e9250bd3399102b0f27fce102d7610 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 15:32:38 +0200 Subject: [PATCH 0760/1812] make compilation delay configurable via a user setting --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ apps/opencs/view/world/scriptsubview.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 673db4057a..5a4b582663 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -319,6 +319,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); toolbar->setDefaultValue ("true"); + Setting *delay = createSetting (Type_SpinBox, "compile-delay", + "Delay between updating of source errors"); + delay->setDefaultValue (100); + delay->setRange (0, 10000); + delay->setToolTip ("Delay in milliseconds"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dfdca8b48a..ee0adb6f5f 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -39,7 +39,8 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { if (!mCompileDelay->isActive()) - mCompileDelay->start (5000); + mCompileDelay->start ( + CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -144,6 +145,10 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr } } } + else if (name=="script-editor/compile-delay") + { + mCompileDelay->setInterval (value.at (0).toInt()); + } if (mButtons) mButtons->updateUserSetting (name, value); From df077f8649b89a0f85e2c6b3db4c355e92dd8c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 16:56:57 +0200 Subject: [PATCH 0761/1812] color tooltip red when taking item would result in crime --- apps/openmw/mwgui/tooltips.cpp | 9 +++++++++ files/mygui/openmw_hud_box.skin.xml | 12 ++++++++++++ files/mygui/openmw_windows.skin.xml | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 22d5d14f7c..e901714a56 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -369,6 +369,15 @@ namespace MWGui MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); + + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } std::string caption = info.caption; std::string image = info.icon; diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 4e63497680..7019351bdb 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -31,5 +31,17 @@
    + + + + + + + + + + + +
    diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index e740383914..29299dc06c 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -128,6 +128,14 @@ + + + + + + + + From f1ac440b7832dce0745c2e35bfa8c40ca4c66c36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:00:00 +0200 Subject: [PATCH 0762/1812] do not allow editing of deleted scripts --- apps/opencs/view/world/scripterrortable.cpp | 7 ++- apps/opencs/view/world/scripterrortable.hpp | 2 + apps/opencs/view/world/scriptsubview.cpp | 57 ++++++++++++++------- apps/opencs/view/world/scriptsubview.hpp | 5 ++ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 20b197c54e..3e80c5bd47 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -100,7 +100,7 @@ void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const Q void CSVWorld::ScriptErrorTable::update (const std::string& source) { - setRowCount (0); + clear(); try { @@ -122,6 +122,11 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) } } +void CSVWorld::ScriptErrorTable::clear() +{ + setRowCount (0); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index f16a96a74c..98db425cfd 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -42,6 +42,8 @@ namespace CSVWorld void update (const std::string& source); + void clear(); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index ee0adb6f5f..d405d17652 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -38,11 +38,31 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { - if (!mCompileDelay->isActive()) + if (!mCompileDelay->isActive() && !isDeleted()) mCompileDelay->start ( CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } +bool CSVWorld::ScriptSubView::isDeleted() const +{ + return mModel->data (mModel->getModelIndex (getUniversalId().getId(), mStateColumn)).toInt() + ==CSMWorld::RecordBase::State_Deleted; +} + +void CSVWorld::ScriptSubView::updateDeletedState() +{ + if (isDeleted()) + { + mErrors->clear(); + mEditor->setEnabled (false); + } + else + { + mEditor->setEnabled (true); + recompile(); + } +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -68,16 +88,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mModel = &dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); - for (int i=0; icolumnCount(); ++i) - if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_ScriptFile) - { - mColumn = i; - break; - } - - if (mColumn==-1) - throw std::logic_error ("Can't find script column"); + mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -114,7 +126,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mCompileDelay->setSingleShot (true); connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); - recompile(); + updateDeletedState(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -231,16 +243,21 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); - if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && - index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) { - QString source = mModel->data (index).toString(); + if (mStateColumn>=topLeft.column() && mStateColumn<=bottomRight.column()) + updateDeletedState(); - QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (source); - mEditor->setTextCursor (cursor); + if (mColumn>=topLeft.column() && mColumn<=bottomRight.column()) + { + QString source = mModel->data (index).toString(); - recompile(); + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (source); + mEditor->setTextCursor (cursor); + + recompile(); + } } } @@ -262,6 +279,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); + + updateDeletedState(); } void CSVWorld::ScriptSubView::switchToId (const std::string& id) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 3481989f18..6125dd259d 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; @@ -52,6 +53,10 @@ namespace CSVWorld void recompile(); + bool isDeleted() const; + + void updateDeletedState(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); From 75f59728984df63a43d9eaa2e42dee572738cb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 17:13:20 +0200 Subject: [PATCH 0763/1812] show owned - better settings --- apps/openmw/mwgui/tooltips.cpp | 18 ++++++++++++------ apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- files/mygui/openmw_windows.skin.xml | 2 +- files/settings-default.cfg | 8 ++++++-- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e901714a56..a51c68acf0 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -38,6 +38,7 @@ namespace MWGui , mLastMouseY(0) , mEnabled(true) , mFullHelp(false) + , mShowOwned(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -55,6 +56,8 @@ namespace MWGui { mMainWidget->getChildAt(i)->setVisible(false); } + + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void ToolTips::setEnabled(bool enabled) @@ -370,13 +373,16 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - if(checkOwned()) + if(mShowOwned == 1 || mShowOwned == 3) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); - } - else - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } } std::string caption = info.caption; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bd4a81c32c..b2f172076f 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -122,6 +122,8 @@ namespace MWGui bool mEnabled; bool mFullHelp; + + int mShowOwned; }; } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623c..7b618efa7d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,7 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) - , mShowOwned(false) + , mShowOwned(0) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -264,7 +264,7 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); - mShowOwned = Settings::Manager::getBool("show owned", "Game"); + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void WindowManager::initUI() @@ -1043,7 +1043,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(mShowOwned && mHud) + if(mHud && (mShowOwned == 2 || mShowOwned == 3)) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7dae502094..af82c27c0c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -487,7 +487,7 @@ namespace MWGui std::map mFallbackMap; - bool mShowOwned; + int mShowOwned; std::string mVersionDescription; diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 29299dc06c..47f8cada84 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,7 +131,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4ec0c2480f..d84291a24a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,8 +162,12 @@ best attack = false difficulty = 0 -# change crosshair color when pointing on owned object -show owned = false +# Change crosshair/toolTip color when pointing on owned object +#0: nothing changed +#1: tint toolTip +#2: tint crosshair +#3: both +show owned = 0 [Saves] character = From cdfa3006a3b94e8cf2f1b0ca50acf783aaa3ec45 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:47:50 +0200 Subject: [PATCH 0764/1812] incorrect sBribe GMSTs for new omwgame files (Fixes #2785) --- apps/opencs/model/doc/document.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 215dbd304a..44e6142b07 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -798,9 +798,9 @@ void CSMDoc::Document::addGmsts() "sBookSkillMessage", "sBounty", "sBreath", - "sBribe", - "sBribe", - "sBribe", + "sBribe 10 Gold", + "sBribe 100 Gold", + "sBribe 1000 Gold", "sBribeFail", "sBribeSuccess", "sBuy", From 77f1387da8180c2e8603d6642bc41e366effa7c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 19:40:31 +0200 Subject: [PATCH 0765/1812] Include cleanup --- apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/companionitemmodel.cpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 3 --- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/inventoryitemmodel.cpp | 2 -- apps/openmw/mwgui/inventorywindow.cpp | 4 +--- apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/mainmenu.cpp | 4 ---- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 5 +---- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/spellbuyingwindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 4 +--- 19 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 1122a40690..de86140042 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index 983ef50173..0ff0b648e1 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -1,6 +1,5 @@ #include "companionitemmodel.hpp" -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index b61d464003..fc4a984896 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -3,11 +3,8 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2f874119d4..b2cc09b43a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -11,13 +11,11 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" #include "countdialog.hpp" -#include "tradewindow.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0cb0475c91..ce33a74dda 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -16,12 +16,12 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "widgets.hpp" #include "bookpage.hpp" diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 43f2493a98..61a935a6fb 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e39..7307e6f871 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,7 +10,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index e8354b7406..b80850ba1b 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -4,8 +4,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/creaturestats.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 39f4764035..9c9138ed51 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,19 +16,17 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7e733686db..9b99ad7bf6 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -17,9 +17,7 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" - #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 4093069865..258f0dfb08 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -12,12 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/journal.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/statemanager.hpp" -#include "../mwstate/character.hpp" - #include "savegamedialog.hpp" #include "confirmationdialog.hpp" #include "backgroundimage.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2485f3c948..d564dfcbc5 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -27,7 +27,6 @@ #include "../mwrender/globalmap.hpp" #include "../mwrender/localmap.hpp" -#include "widgets.hpp" #include "confirmationdialog.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index a0550ae25a..ab0d02f950 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,8 +1,8 @@ #include "pickpocketitemmodel.hpp" #include +#include -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8c919e8bd5..3f896bae2b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -15,18 +15,15 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwgui/inventorywindow.hpp" -#include "windowmanagerimp.hpp" #include "itemselection.hpp" - #include "spellview.hpp" - - #include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 76961af5da..69c5c61c4f 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -7,8 +7,6 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index ae7b7588ab..61dd599e74 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -12,7 +12,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 1c5dc46323..0ae661eb3c 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -15,7 +15,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623c..31eef5c016 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -45,6 +45,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwrender/vismask.hpp" @@ -58,8 +59,6 @@ #include "../mwrender/localmap.hpp" -#include "../mwsound/soundmanagerimp.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "journalviewmodel.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72ff..d436eca317 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,12 +7,10 @@ #include #include #include -#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/player.hpp" @@ -22,7 +20,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwrender/animation.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" From 278a078e9d39340fbf907ba156931b00bf0c0376 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 20:39:45 +0200 Subject: [PATCH 0766/1812] Unify magic effect tick functions - Removes duplicated code - Handle some zero-duration instant effects that were not handled before (disintegrate, sun damage, elemental damage) --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 + apps/openmw/mwclass/npc.cpp | 7 +- apps/openmw/mwmechanics/actors.cpp | 165 ++----------- .../mwmechanics/mechanicsmanagerimp.cpp | 21 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 5 + apps/openmw/mwmechanics/spellcasting.cpp | 228 ++++++++++++++---- apps/openmw/mwmechanics/spellcasting.hpp | 3 + 7 files changed, 229 insertions(+), 205 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b66e60e1d6..2c4a22c075 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,6 +129,11 @@ namespace MWBase OffenseType type, int arg=0, bool victimAware=false) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c7b407fb88..d0dd9f994c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -751,12 +751,7 @@ namespace MWClass attacker.getClass().getNpcStats(attacker).addWerewolfKill(); } - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d436eca317..4a08176d13 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -67,44 +67,6 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } -bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) -{ - if (ptr.getClass().hasInventoryStore(ptr)) - { - MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); - MWWorld::ContainerStoreIterator item = - inv.getSlot(slot); - if (item != inv.end()) - { - if (!item->getClass().hasItemHealth(*item)) - return false; - int charge = item->getClass().getItemHealth(*item); - - if (charge == 0) - return false; - - // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. - // This was also a bug in the original engine. - charge -= - std::min(static_cast(disintegrate), - charge); - item->getCellRef().setCharge(charge); - - if (charge == 0) - { - // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - inv.autoEquip(ptr); - else - inv.unequipItem(*item, ptr); - } - - return true; - } - } - return false; -} - class CheckActorCommanded : public MWMechanics::EffectSourceVisitor { MWWorld::Ptr mActor; @@ -516,8 +478,12 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - // FIXME: effect ticks should go into separate functions so they can be used with either - // magnitude (instant effect) or magnitude*duration + // tickable effects (i.e. effects having a lasting impact after expiry) + // these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here + for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + } // attributes for(int i = 0;i < ESM::Attribute::Length;++i) @@ -527,9 +493,6 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); - creatureStats.setAttribute(i, stat); } @@ -559,12 +522,6 @@ namespace MWMechanics // Fatigue can be decreased below zero meaning the actor will be knocked out i == 2); - - float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).getMagnitude(); - stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2); - creatureStats.setDynamic(i, stat); } @@ -592,90 +549,11 @@ namespace MWMechanics creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } - // Apply disintegration (reduces item health) - float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).getMagnitude(); - if (disintegrateWeapon > 0) - disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration); - float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).getMagnitude(); - if (disintegrateArmor > 0) - { - // According to UESP - int priorities[] = { - MWWorld::InventoryStore::Slot_CarriedLeft, - MWWorld::InventoryStore::Slot_Cuirass, - MWWorld::InventoryStore::Slot_LeftPauldron, - MWWorld::InventoryStore::Slot_RightPauldron, - MWWorld::InventoryStore::Slot_LeftGauntlet, - MWWorld::InventoryStore::Slot_RightGauntlet, - MWWorld::InventoryStore::Slot_Helmet, - MWWorld::InventoryStore::Slot_Greaves, - MWWorld::InventoryStore::Slot_Boots - }; - - for (unsigned int i=0; i 0.0f - || creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth).getMagnitude() > 0.0f) - receivedMagicDamage = true; - - // Apply damage ticks - int damageEffects[] = { - ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, - ESM::MagicEffect::SunDamage - }; - - DynamicStat health = creatureStats.getHealth(); - for (unsigned int i=0; iisExterior()) - continue; - float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); - float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); - float damageScale = 1.f - timeDiff / 7.f; - // When cloudy, the sun damage effect is halved - static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fMagicSunBlockedMult")->getFloat(); - - int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); - if (weather > 1) - damageScale *= fMagicSunBlockedMult; - health.setCurrent(health.getCurrent() - magnitude * duration * damageScale); - - if (magnitude * damageScale > 0.0f) - receivedMagicDamage = true; - } - else - { - health.setCurrent(health.getCurrent() - magnitude * duration); - - if (magnitude > 0.0f) - receivedMagicDamage = true; - } - } - - if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); - - creatureStats.setHealth(health); - if (!wasDead && creatureStats.isDead()) { // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - bool murderedByPlayer = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { @@ -685,33 +563,29 @@ namespace MWMechanics { int effectId = effectIt->mEffectId; bool isDamageEffect = false; + + int damageEffects[] = { + ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, + ESM::MagicEffect::SunDamage, ESM::MagicEffect::DamageHealth, ESM::MagicEffect::AbsorbHealth + }; + for (unsigned int i=0; isearchPtrViaActorId(spell.mCasterActorId); if (isDamageEffect && caster == player) - { killedByPlayer = true; - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - if (ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 - && ptr != player) - murderedByPlayer = true; - } } } - if (murderedByPlayer) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); - if (killedByPlayer && player.getClass().getNpcStats(player).isWerewolf()) - player.getClass().getNpcStats(player).addWerewolfKill(); + if (killedByPlayer) + { + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player); + if (player.getClass().getNpcStats(player).isWerewolf()) + player.getClass().getNpcStats(player).addWerewolfKill(); + } } // TODO: dirty flag for magic effects to avoid some unnecessary work below? @@ -795,9 +669,6 @@ namespace MWMechanics skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); - - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fef99dc616..e9ef99454c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1330,6 +1330,27 @@ namespace MWMechanics return true; } + void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) + { + if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + + if (victim == attacker) + return; // known to happen + + if (!victim.getClass().isNpc()) + return; // TODO: implement animal rights + + const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim); + + // Simple check for who attacked first: if the player attacked first, a crimeId should be set + // Doesn't handle possible edge case where no one reported the assault, but in such a case, + // for bystanders it is not possible to tell who attacked first, anyway. + if (victimStats.getCrimeId() != -1) + MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + + } + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 392d7fbbe4..6386b4a2ad 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -120,6 +120,11 @@ namespace MWMechanics OffenseType type, int arg=0, bool victimAware=false); /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a47da7bf41..1613300d76 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,6 +19,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" + #include "../mwrender/animation.hpp" #include "magiceffects.hpp" @@ -65,57 +67,6 @@ namespace target.getClass().getCreatureStats(target).setDynamic(attribute, value); } - // TODO: refactor the effect tick functions in Actors so they can be reused here - void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) - { - int effectId = effect.mId; - if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - } - } namespace MWMechanics @@ -530,7 +481,14 @@ namespace MWMechanics else { if (hasDuration && target.getClass().isActor()) - applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); + { + bool wasDead = target.getClass().getCreatureStats(target).isDead(); + effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude); + bool isDead = target.getClass().getCreatureStats(target).isDead(); + + if (!wasDead && isDead) + MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); + } else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); } @@ -960,4 +918,170 @@ namespace MWMechanics || (effectId >= ESM::MagicEffect::SummonFabricant && effectId <= ESM::MagicEffect::SummonCreature05)); } + + bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) + { + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); + MWWorld::ContainerStoreIterator item = + inv.getSlot(slot); + if (item != inv.end()) + { + if (!item->getClass().hasItemHealth(*item)) + return false; + int charge = item->getClass().getItemHealth(*item); + + if (charge == 0) + return false; + + // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. + // This was also a bug in the original engine. + charge -= + std::min(static_cast(disintegrate), + charge); + item->getCellRef().setCharge(charge); + + if (charge == 0) + { + // Will unequip the broken item and try to find a replacement + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + inv.autoEquip(ptr); + else + inv.unequipItem(*item, ptr); + } + + return true; + } + } + return false; + } + + void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude) + { + DynamicStat stat = creatureStats.getDynamic(index); + stat.setCurrent(stat.getCurrent() + magnitude, index == 2); + creatureStats.setDynamic(index, stat); + } + + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) + { + if (magnitude == 0.f) + return; + + bool receivedMagicDamage = false; + + switch (effectKey.mId) + { + case ESM::MagicEffect::DamageAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.damage(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.restore(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreHealth: + case ESM::MagicEffect::RestoreMagicka: + case ESM::MagicEffect::RestoreFatigue: + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude); + break; + case ESM::MagicEffect::DamageHealth: + case ESM::MagicEffect::DamageMagicka: + case ESM::MagicEffect::DamageFatigue: + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + break; + case ESM::MagicEffect::AbsorbHealth: + case ESM::MagicEffect::AbsorbMagicka: + case ESM::MagicEffect::AbsorbFatigue: + if (magnitude > 0.f) + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + break; + + case ESM::MagicEffect::DisintegrateArmor: + { + // According to UESP + int priorities[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + for (unsigned int i=0; iisExterior()) + break; + float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); + float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); + float damageScale = 1.f - timeDiff / 7.f; + // When cloudy, the sun damage effect is halved + static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fMagicSunBlockedMult")->getFloat(); + + int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); + if (weather > 1) + damageScale *= fMagicSunBlockedMult; + + adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); + if (magnitude * damageScale > 0.f) + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::FireDamage: + case ESM::MagicEffect::ShockDamage: + case ESM::MagicEffect::FrostDamage: + case ESM::MagicEffect::Poison: + { + adjustDynamicStat(creatureStats, 0, -magnitude); + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + { + if (!actor.getClass().isNpc()) + break; + NpcStats &npcStats = actor.getClass().getNpcStats(actor); + SkillValue& skill = npcStats.getSkill(effectKey.mArg); + if (effectKey.mId == ESM::MagicEffect::RestoreSkill) + skill.restore(magnitude); + else + skill.damage(magnitude); + break; + } + + } + + if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + } + } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2540b87db4..418e9f56dc 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,6 +17,7 @@ namespace MWMechanics { struct EffectKey; class MagicEffects; + class CreatureStats; ESM::Skill::SkillEnum spellSchoolToSkill(int school); @@ -60,6 +61,8 @@ namespace MWMechanics int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + class CastSpell { private: From cbc44b33ba01ae4aa4eac7386fcde048b7eeb613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 21:29:38 +0200 Subject: [PATCH 0767/1812] define crosshair owned colour in openmw_hud_box.skin.xml --- AUTHORS.md | 2 +- apps/openmw/mwgui/hud.cpp | 6 ++---- apps/openmw/mwgui/tooltips.cpp | 2 +- files/mygui/openmw_hud.layout | 3 +-- files/mygui/openmw_hud_box.skin.xml | 19 +++++++++++++++++-- files/mygui/openmw_windows.skin.xml | 5 +++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 7774b5afa2..2bd96e3a16 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,7 @@ Programmers jeaye Jeffrey Haines (Jyby) Jengerer + Jiří Kuneš (kunesj) Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers @@ -59,7 +60,6 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) - kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e39..c8d8b61d56 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -521,15 +521,13 @@ namespace MWGui void HUD::setCrosshairOwned(bool owned) { - MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); - MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); if(owned) { - mCrosshair->setColour(red); + mCrosshair->changeWidgetSkin("HUD_Crosshair_Owned"); } else { - mCrosshair->setColour(white); + mCrosshair->changeWidgetSkin("HUD_Crosshair"); } } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a51c68acf0..dbf27ad91d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -377,7 +377,7 @@ namespace MWGui { if(checkOwned()) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); } else { diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index dd114097e5..97b0184696 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -122,8 +122,7 @@
    - - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 7019351bdb..dfe717c6f5 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -32,16 +32,31 @@ - + - + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 47f8cada84..c9a1f1ccc6 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -129,9 +129,10 @@ - - + + + From a5b4e087c56518c6e0a75413f9c7f5cfa9f377a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 22:17:46 +0200 Subject: [PATCH 0768/1812] define owned colours in settings.cfg --- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++++++++++++-- files/mygui/openmw_hud_box.skin.xml | 2 +- files/mygui/openmw_windows.skin.xml | 3 +-- files/settings-default.cfg | 4 ++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7b618efa7d..0fe71632aa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1095,11 +1095,22 @@ namespace MWGui void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { std::string tag(_tag); + + std::string MyGuiPrefix = "setting="; + size_t MyGuiPrefixLength = MyGuiPrefix.length(); std::string tokenToFind = "sCell="; size_t tokenLength = tokenToFind.length(); - - if (tag.compare(0, tokenLength, tokenToFind) == 0) + + if(tag.compare(0, MyGuiPrefixLength, MyGuiPrefix) == 0) + { + tag = tag.substr(MyGuiPrefixLength, tag.length()); + std::string settingSection = tag.substr(0, tag.find(",")); + std::string settingTag = tag.substr(tag.find(",")+1, tag.length()); + + _result = Settings::Manager::getString(settingTag, settingSection); + } + else if (tag.compare(0, tokenLength, tokenToFind) == 0) { _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); } diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index dfe717c6f5..33199d6aeb 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -53,7 +53,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index c9a1f1ccc6..682d89ebcc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,8 +131,7 @@ - - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d84291a24a..dcb9b8893e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -36,6 +36,10 @@ werewolf overlay = true stretch menu background = false +# colour definitions (red green blue alpha) +color background owned = 0.15 0 0 1 +color crosshair owned = 1 0.15 0.15 1 + [General] # Camera field of view field of view = 55 From 115666884308dca010d2ce60c8e40b25d0b88e9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 00:45:02 +0200 Subject: [PATCH 0769/1812] Render certain map markers on top of the player arrow (Fixes #2559) --- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d564dfcbc5..e26c076e72 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -37,8 +37,8 @@ namespace enum LocalMapWidgetDepth { - Local_CompassLayer = 0, - Local_MarkerAboveFogLayer = 1, + Local_MarkerAboveFogLayer = 0, + Local_CompassLayer = 1, Local_FogLayer = 2, Local_MarkerLayer = 3, Local_MapLayer = 4 From b01abe4d19c32e15945c9193c032ca7a141f8df8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 02:08:24 +0200 Subject: [PATCH 0770/1812] Stop title music when the game starts (Fixes #2468) --- apps/openmw/engine.cpp | 3 --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 001ce27507..8d25a923fe 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -646,9 +646,6 @@ void OMW::Engine::go() prepareEngine (settings); - // Play some good 'ol tunes - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - if (!mSaveGameFile.empty()) { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72ff..ee3f4b8f47 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1200,18 +1200,18 @@ namespace MWMechanics killDeadActors(); // check if we still have any player enemies to switch music - static bool isBattleMusic = false; + static int currentMusic = 0; - if (isBattleMusic && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getSoundManager()->isMusicPlaying())) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - isBattleMusic = false; + currentMusic = 1; } - else if (!isBattleMusic && hostilesCount > 0) + else if (currentMusic != 2 && hostilesCount > 0) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); - isBattleMusic = true; + currentMusic = 2; } static float sneakTimer = 0.f; // times update of sneak icon From 3ebe9fb34f99c59979adbb68df1d6621e5d9b931 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:00:49 +1200 Subject: [PATCH 0771/1812] renamed mRotate to mTurnActorGivingGreetingToFacePlayer --- apps/openmw/mwmechanics/aiwander.cpp | 32 ++++++++++++++-------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1375b5807a..43fd67be18 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -51,10 +51,10 @@ namespace MWMechanics /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { - // the z rotation angle (degrees) we want to reach - // used every frame when mRotate is true + // the z rotation angle to reach + // when mTurnActorGivingGreetingToFacePlayer is true float mTargetAngleRadians; - bool mRotate; + bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently @@ -75,7 +75,7 @@ namespace MWMechanics AiWanderStorage(): mTargetAngleRadians(0), - mRotate(false), + mTurnActorGivingGreetingToFacePlayer(false), mReaction(0), mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), @@ -240,15 +240,13 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - - float& targetAngleRadians = storage.mTargetAngleRadians; - bool& rotate = storage.mRotate; + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; if (rotate) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f))) + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) rotate = false; } @@ -491,14 +489,7 @@ namespace MWMechanics getRandomIdle(storage.mPlayedIdle); } - if (!storage.mRotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - storage.mTargetAngleRadians = faceAngleRadians; - storage.mRotate = true; - } + turnActorToFacePlayer(actorPos, playerPos, storage); if (greetingTimer >= GREETING_SHOULD_END) { @@ -515,6 +506,15 @@ namespace MWMechanics } } + void AiWander::turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage) + { + osg::Vec3f dir = playerPosition - actorPosition; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mTurnActorGivingGreetingToFacePlayer = true; + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 82baeedf36..d068876004 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -75,6 +75,7 @@ namespace MWMechanics void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); + void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ed6e95c07d4eab8fb2e95eb980215695710ab64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:01:25 +1200 Subject: [PATCH 0772/1812] Got rid of some radians to degrees to radians conversions. --- apps/openmw/mwmechanics/aicombat.cpp | 8 ++++---- apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 4eeea6f1f6..6a39178ce0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -36,13 +36,13 @@ namespace float getZAngleToDir(const osg::Vec3f& dir) { - return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y())); + return std::atan2(dir.x(), dir.y()); } float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) { float len = (dirLen > 0.0f)? dirLen : dir.length(); - return osg::RadiansToDegrees(-std::asin(dir.z() / len)); + return -std::asin(dir.z() / len); } @@ -221,12 +221,12 @@ namespace MWMechanics if(movement.mRotation[2] != 0) { - if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0; + if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; } if(movement.mRotation[0] != 0) { - if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; + if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; } bool& attack = storage.mAttack; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 22c9075887..0e68d9d79b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -104,7 +104,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things @@ -117,7 +117,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); return false; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 43fd67be18..9f50d07b43 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -234,7 +234,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; evadeObstacles(actor, storage, duration); @@ -397,7 +397,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 3c1a40fe0e..79cee9f326 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -264,7 +264,7 @@ namespace MWMechanics float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; - return osg::RadiansToDegrees(std::atan2(directionX, directionY)); + return std::atan2(directionX, directionY); } bool PathFinder::checkPathCompleted(float x, float y, float tolerance) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index a4886a8400..4000f5d800 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -40,7 +40,7 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. - /// In degrees + /// In radians float getZAngleToNext(float x, float y) const; bool isPathConstructed() const From 22f49128ccb2a6e12a36fb31f992155a6a967c38 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:02:13 +1200 Subject: [PATCH 0773/1812] replaced multiple booleans with single state variable. --- apps/openmw/mwmechanics/aiwander.cpp | 65 ++++++++++------------------ apps/openmw/mwmechanics/aiwander.hpp | 7 +++ 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 9f50d07b43..fc730cc894 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -64,10 +64,7 @@ namespace MWMechanics const MWWorld::CellStore* mCell; // for detecting cell change // AiWander states - bool mChooseAction; - bool mIdleNow; - bool mMoveNow; - bool mWalking; + AiWander::WanderState mState; unsigned short mPlayedIdle; @@ -80,10 +77,7 @@ namespace MWMechanics mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), mCell(NULL), - mChooseAction(true), - mIdleNow(false), - mMoveNow(false), - mWalking(false), + mState(AiWander::Wander_ChooseAction), mPlayedIdle(0) {}; }; @@ -200,38 +194,33 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - bool& idleNow = storage.mIdleNow; - bool& moveNow = storage.mMoveNow; - bool& walking = storage.mWalking; + WanderState& wanderState = storage.mState; // Check if an idle actor is too close to a door - if so start walking mDoorCheckDuration += duration; if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { mDoorCheckDuration = 0; // restart timer if(mDistance && // actor is not intended to be stationary - idleNow && // but is in idle - !walking && // FIXME: some actors are idle while walking + (wanderState == Wander_IdleNow) && // but is in idle proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { - idleNow = false; - moveNow = true; + wanderState = Wander_MoveNow; mTrimCurrentNode = false; // just in case } } // Are we there yet? - bool& chooseAction = storage.mChooseAction; - if(walking && + if ((wanderState == Wander_Walking) && storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - chooseAction = true; + wanderState = Wander_ChooseAction; mHasReturnPosition = false; } - if(walking) // have not yet reached the destination + if (wanderState == Wander_Walking) // have not yet reached the destination { // turn towards the next point in mPath zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); @@ -253,24 +242,23 @@ namespace MWMechanics // Check if idle animation finished short unsigned& playedIdle = storage.mPlayedIdle; GreetingState& greetingState = storage.mSaidGreeting; - if(idleNow && !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + if ((wanderState == Wander_IdleNow) && + !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) { playedIdle = 0; - idleNow = false; - chooseAction = true; + wanderState = Wander_ChooseAction; } MWBase::World *world = MWBase::Environment::get().getWorld(); - if(chooseAction) + if (wanderState == Wander_ChooseAction) { playedIdle = 0; getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection if(!playedIdle && mDistance) { - chooseAction = false; - moveNow = true; + wanderState = Wander_MoveNow; } else { @@ -278,8 +266,7 @@ namespace MWMechanics MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; playIdle(actor, playedIdle); - chooseAction = false; - idleNow = true; + wanderState = Wander_IdleNow; } } @@ -332,9 +319,6 @@ namespace MWMechanics mHasReturnPosition = false; if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) { - chooseAction = false; - idleNow = false; - if (!storage.mPathFinder.isPathConstructed()) { ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); @@ -347,19 +331,18 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - moveNow = false; - walking = true; + wanderState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting - if(idleNow || walking) + if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); } - if(moveNow && mDistance) + if ((wanderState == Wander_MoveNow) && mDistance) { // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) @@ -386,8 +369,7 @@ namespace MWMechanics trimAllowedNodes(mAllowedNodes, storage.mPathFinder); mObstacleCheck.clear(); storage.mPathFinder.clearPath(); - storage.mWalking = false; - storage.mMoveNow = true; + storage.mState = Wander_MoveNow; } else // probably walking into another NPC { @@ -409,7 +391,7 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mChooseAction = true; + storage.mState = Wander_ChooseAction; mStuckCount = 0; } //#endif @@ -481,11 +463,11 @@ namespace MWMechanics { greetingTimer++; - if (storage.mWalking) + if (storage.mState == Wander_Walking) { stopWalking(actor, storage); mObstacleCheck.clear(); - storage.mIdleNow = true; + storage.mState = Wander_IdleNow; getRandomIdle(storage.mPlayedIdle); } @@ -539,8 +521,7 @@ namespace MWMechanics mAllowedNodes.push_back(mCurrentNode); mCurrentNode = temp; - storage.mMoveNow = false; - storage.mWalking = true; + storage.mState = Wander_Walking; } // Choose a different node and delete this one from possible nodes because it is uncreachable: else @@ -591,8 +572,6 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; - storage.mMoveNow = false; - storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d068876004..8a4921b833 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -63,6 +63,13 @@ namespace MWMechanics Greet_InProgress, Greet_Done }; + + enum WanderState { + Wander_ChooseAction, + Wander_IdleNow, + Wander_MoveNow, + Wander_Walking, + }; private: // NOTE: mDistance and mDuration must be set already void init(); From 00eef585afde4b0a2ef532a06a82938d7cc1d43c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:04:42 +1200 Subject: [PATCH 0774/1812] renamed mPlayedIdle to mIdleAnimation. --- apps/openmw/mwmechanics/aiwander.cpp | 23 +++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fc730cc894..5c9949a5a3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -66,7 +66,7 @@ namespace MWMechanics // AiWander states AiWander::WanderState mState; - unsigned short mPlayedIdle; + unsigned short mIdleAnimation; PathFinder mPathFinder; @@ -78,7 +78,7 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mPlayedIdle(0) + mIdleAnimation(0) {}; }; @@ -240,12 +240,11 @@ namespace MWMechanics } // Check if idle animation finished - short unsigned& playedIdle = storage.mPlayedIdle; + short unsigned& idleAnimation = storage.mIdleAnimation; GreetingState& greetingState = storage.mSaidGreeting; if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) { - playedIdle = 0; wanderState = Wander_ChooseAction; } @@ -253,10 +252,9 @@ namespace MWMechanics if (wanderState == Wander_ChooseAction) { - playedIdle = 0; - getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection + idleAnimation = getRandomIdle(); - if(!playedIdle && mDistance) + if(!idleAnimation && mDistance) { wanderState = Wander_MoveNow; } @@ -265,7 +263,7 @@ namespace MWMechanics // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, playedIdle); + playIdle(actor, idleAnimation); wanderState = Wander_IdleNow; } } @@ -468,7 +466,6 @@ namespace MWMechanics stopWalking(actor, storage); mObstacleCheck.clear(); storage.mState = Wander_IdleNow; - getRandomIdle(storage.mPlayedIdle); } turnActorToFacePlayer(actorPos, playerPos, storage); @@ -605,9 +602,10 @@ namespace MWMechanics } } - void AiWander::getRandomIdle(short unsigned& playedIdle) + short unsigned AiWander::getRandomIdle() { unsigned short idleRoll = 0; + short unsigned selectedAnimation = 0; for(unsigned int counter = 0; counter < mIdle.size(); counter++) { @@ -618,10 +616,11 @@ namespace MWMechanics unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { - playedIdle = counter+2; + selectedAnimation = counter + GroupIndex_MinIdle; idleRoll = randSelect; } } + return selectedAnimation; } void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 8a4921b833..df389a34ef 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); - void getRandomIdle(unsigned short& playedIdle); + short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); From ad353e6dd0b41e388e2ec3fbcc4bf15d1ef71e57 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 19:52:31 +0300 Subject: [PATCH 0775/1812] Refine DELE handling in ESM records. Add position-independent DELE search --- components/esm/cellref.cpp | 126 +++++++++++++--------- components/esm/esmreader.cpp | 5 + components/esm/esmreader.hpp | 3 + components/esm/loadacti.cpp | 23 ++-- components/esm/loadalch.cpp | 28 +++-- components/esm/loadappa.cpp | 27 +++-- components/esm/loadarmo.cpp | 26 +++-- components/esm/loadbody.cpp | 24 +++-- components/esm/loadbook.cpp | 25 +++-- components/esm/loadbsgn.cpp | 20 +++- components/esm/loadclas.cpp | 25 +++-- components/esm/loadclot.cpp | 26 +++-- components/esm/loadcont.cpp | 32 ++++-- components/esm/loadcrea.cpp | 33 ++++-- components/esm/loaddial.cpp | 46 +++++--- components/esm/loaddoor.cpp | 23 ++-- components/esm/loadench.cpp | 25 +++-- components/esm/loadfact.cpp | 28 +++-- components/esm/loadglob.cpp | 31 +++--- components/esm/loadinfo.cpp | 189 +++++++++++++-------------------- components/esm/loadinfo.hpp | 3 +- components/esm/loadingr.cpp | 24 +++-- components/esm/loadlevlist.cpp | 87 +++++++++------ components/esm/loadligh.cpp | 25 +++-- components/esm/loadlock.cpp | 26 +++-- components/esm/loadltex.cpp | 43 ++++++-- components/esm/loadmisc.cpp | 27 +++-- components/esm/loadnpc.cpp | 34 +++--- components/esm/loadprob.cpp | 27 +++-- components/esm/loadregn.cpp | 105 +++++++++++------- components/esm/loadrepa.cpp | 27 +++-- components/esm/loadscpt.cpp | 29 +++-- components/esm/loadsndg.cpp | 38 ++++--- components/esm/loadsoun.cpp | 27 +++-- components/esm/loadspel.cpp | 30 ++++-- components/esm/loadstat.cpp | 39 +++++-- components/esm/loadweap.cpp | 24 +++-- 37 files changed, 861 insertions(+), 519 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index e43a37b668..c6fb899b31 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "util.hpp" ESM::CellRef::CellRef() : mScale(1.0f), @@ -38,7 +37,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) { - mIsDeleted = false; loadId(esm, wideRefNum); loadData(esm); } @@ -55,62 +53,90 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); + mIsDeleted = false; } void ESM::CellRef::loadData(ESMReader &esm) { - // Again, UNAM sometimes appears after NAME and sometimes later. - // Or perhaps this UNAM means something different? - mReferenceBlocked = -1; - esm.getHNOT (mReferenceBlocked, "UNAM"); - - mScale = 1.0; - esm.getHNOT (mScale, "XSCL"); - - mOwner = esm.getHNOString ("ANAM"); - mGlobalVariable = esm.getHNOString ("BNAM"); - mSoul = esm.getHNOString ("XSOL"); - - mFaction = esm.getHNOString ("CNAM"); + mScale = 1.0f; mFactionRank = -2; - esm.getHNOT (mFactionRank, "INDX"); - - mGoldValue = 1; mChargeInt = -1; mEnchantmentCharge = -1; + mGoldValue = 1; + mLockLevel = 0; + mReferenceBlocked = -1; + mTeleport = false; + mIsDeleted = false; - esm.getHNOT (mEnchantmentCharge, "XCHG"); - - esm.getHNOT (mChargeInt, "INTV"); - - esm.getHNOT (mGoldValue, "NAM9"); - - // Present for doors that teleport you to another cell. - if (esm.isNextSub ("DODT")) + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - mTeleport = true; - esm.getHT (mDoorDest); - mDestCell = esm.getHNOString ("DNAM"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'U','N','A','M'>::value: + esm.getHT(mReferenceBlocked); + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mOwner = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mGlobalVariable = esm.getHString(); + break; + case ESM::FourCC<'X','S','O','L'>::value: + mSoul = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mFactionRank); + break; + case ESM::FourCC<'X','C','H','G'>::value: + esm.getHT(mEnchantmentCharge); + break; + case ESM::FourCC<'I','N','T','V'>::value: + esm.getHT(mChargeInt); + break; + case ESM::FourCC<'N','A','M','9'>::value: + esm.getHT(mGoldValue); + break; + case ESM::FourCC<'D','O','D','T'>::value: + esm.getHT(mDoorDest); + mTeleport = true; + break; + case ESM::FourCC<'D','N','A','M'>::value: + mDestCell = esm.getHString(); + break; + case ESM::FourCC<'F','L','T','V'>::value: + esm.getHT(mLockLevel); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mKey = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTrap = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mPos, 24); + break; + case ESM::FourCC<'N','A','M','0'>::value: + esm.skipHSub(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } - else - mTeleport = false; - - mLockLevel = 0; //Set to 0 to indicate no lock - esm.getHNOT (mLockLevel, "FLTV"); - - mKey = esm.getHNOString ("KNAM"); - mTrap = esm.getHNOString ("TNAM"); - - esm.getHNOT (mReferenceBlocked, "UNAM"); - if (esm.isNextSub("FLTV")) // no longer used - esm.skipHSub(); - - esm.getHNOT(mPos, "DATA", 24); - - if (esm.isNextSub("NAM0")) - esm.skipHSub(); - - mIsDeleted = readDeleSubRecord (esm); } void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const @@ -149,7 +175,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons } if (!inInventory && mLockLevel != 0) { - esm.writeHNT("FLTV", mLockLevel); + esm.writeHNT("FLTV", mLockLevel); } if (!inInventory) @@ -166,7 +192,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } } diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 4be334970e..1bf176842f 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -187,6 +187,11 @@ bool ESMReader::peekNextSub(const char *name) return mCtx.subName == name; } +void ESMReader::cacheSubName() +{ + mCtx.subCached = true; +} + // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. void ESMReader::getSubName() diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index c3e6bbbd30..4772aeb6fc 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -185,6 +185,9 @@ public: bool peekNextSub(const char* name); + // Store the current subrecord name for the next call of getSubName() + void cacheSubName(); + // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. void getSubName(); diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 14a3abe54a..c32cea1a6b 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,18 +14,23 @@ namespace ESM void Activator::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -38,15 +42,20 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Activator::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 5faeb99e16..c1213583dd 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Potion::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,17 +54,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing ALDT"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing ALDT subrecord"); } void Potion::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index ea375aa7f6..edf1f473b8 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing AADT"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing AADT subrecord"); } void Apparatus::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index d23a71cac9..d5b9fdd446 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -46,13 +45,9 @@ namespace ESM void Armor::load(ESMReader &esm) { mParts.mParts.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -60,6 +55,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -84,18 +87,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CTDT subrecord"); } void Armor::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index e0ebfd5390..e2c6ad7b2e 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -40,19 +44,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 2824b62000..2d0d3ce755 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Book::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -52,17 +56,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing BKDT subrecord"); } void Book::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 8cdeed3f6e..9f5cd72705 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -16,16 +16,23 @@ namespace ESM void BirthSign::load(ESMReader &esm) { mPowers.mList.clear(); + mIsDeleted = false; - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -40,16 +47,21 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void BirthSign::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 1384a6280d..b58c35d90a 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -5,7 +5,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -45,12 +44,9 @@ namespace ESM void Class::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -58,6 +54,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -72,17 +76,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CLDT subrecord"); } void Class::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 88f2e57154..18f7cd44fb 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Clothing::load(ESMReader &esm) { mParts.mParts.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -54,18 +57,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 3d3d7fced8..fadfe5f0fe 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -26,19 +25,17 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; Container::Container() - : mIsDeleted(false) + : mWeight(0), + mFlags(0x8), + mIsDeleted(false) {} void Container::load(ESMReader &esm) { mInventory.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasWeight = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -47,6 +44,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -73,20 +78,25 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasWeight) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasWeight && !mIsDeleted) esm.fail("Missing CNDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void Container::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 57e911e701..f360c87489 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -3,14 +3,15 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int Creature::sRecordId = REC_CREA; Creature::Creature() - : mIsDeleted(false) + : mFlags(0), + mScale(0.0f), + mIsDeleted(false) {} void Creature::load(ESMReader &esm) @@ -22,14 +23,11 @@ namespace ESM { mSpells.mList.clear(); mTransport.mList.clear(); - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - mScale = 1.f; mHasAI = false; + mIsDeleted = false; + + bool hasName = false; bool hasNpdt = false; bool hasFlags = false; while (esm.hasMoreSubs()) @@ -38,6 +36,14 @@ namespace ESM { uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -85,20 +91,25 @@ namespace ESM { break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasNpdt) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasNpdt && !mIsDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void Creature::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index fcdb57c8db..c517dc7222 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -7,7 +7,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -31,20 +30,36 @@ namespace ESM void Dialogue::loadData(ESMReader &esm) { - esm.getSubNameIs("DATA"); - esm.getSubHeader(); - int si = esm.getSubSize(); - if (si == 1) - esm.getT(mType); - else if (si == 4) // The dialogue is deleted + while (esm.hasMoreSubs()) { - int32_t empty; - esm.getT(empty); // Skip an empty DATA - mIsDeleted = readDeleSubRecord(esm); - mType = Unknown; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + if (size == 1) + { + esm.getT(mType); + } + else + { + esm.skip(size); + } + break; + } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mType = Unknown; + mIsDeleted = true; + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - else - esm.fail("Unknown sub record size"); } void Dialogue::save(ESMWriter &esm) const @@ -52,8 +67,7 @@ namespace ESM esm.writeHNCString("NAME", mId); if (mIsDeleted) { - esm.writeHNT("DATA", static_cast(0)); - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } else { @@ -138,7 +152,7 @@ namespace ESM { for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) { - if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted) + if (it->mIsDeleted) it = mInfo.erase(it); else ++it; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 87382fa7b1..4f58a42611 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,18 +14,23 @@ namespace ESM void Door::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -44,16 +48,21 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Door::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 1518e0385a..0e480c379d 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Enchantment::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -30,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'E','N','D','T'>::value: esm.getHT(mData, 16); hasData = true; @@ -42,16 +45,20 @@ namespace ESM break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 53f3aa5a6c..8538b0b95d 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -5,7 +5,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -33,17 +32,13 @@ namespace ESM void Faction::load(ESMReader &esm) { + mIsDeleted = false; mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - - int rankCounter=0; + int rankCounter = 0; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -51,6 +46,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -75,18 +78,23 @@ namespace ESM } default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 392df02b54..5f96aff1f3 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,30 +14,38 @@ namespace ESM void Global::load (ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + mId = esm.getHNString ("NAME"); - mValue.read (esm, ESM::Variant::Format_Global); + if (esm.isNextSub ("DELE")) + { + esm.skipHSub(); + mIsDeleted = true; + } + else + { + mValue.read (esm, ESM::Variant::Format_Global); + } } void Global::save (ESMWriter &esm) const { - esm.writeHNCString("NAME", mId); + esm.writeHNCString ("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); - return; + esm.writeHNCString ("DELE", ""); + } + else + { + mValue.write (esm, ESM::Variant::Format_Global); } - - mValue.write (esm, ESM::Variant::Format_Global); } void Global::blank() { mValue.setType (ESM::VT_None); + mIsDeleted = false; } bool operator== (const Global& left, const Global& right) diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 8f5f0f28b0..89fd4e0cd6 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -3,14 +3,15 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; DialInfo::DialInfo() - : mIsDeleted(false) + : mFactionLess(false), + mQuestStatus(QS_None), + mIsDeleted(false) {} void DialInfo::load(ESMReader &esm) @@ -29,6 +30,7 @@ namespace ESM { mQuestStatus = QS_None; mFactionLess = false; + mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -36,118 +38,77 @@ namespace ESM // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings mSelects.clear(); - // If the info is deleted, NAME and DELE sub-records are followed after NNAM - if (esm.isNextSub("NAME")) + while (esm.hasMoreSubs()) { - mResponse = esm.getHString(); - mIsDeleted = readDeleSubRecord(esm); - return; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + break; + case ESM::FourCC<'O','N','A','M'>::value: + mActor = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + { + mFaction = esm.getHString(); + if (mFaction == "FFFF") + { + mFactionLess = true; + } + break; + } + case ESM::FourCC<'A','N','A','M'>::value: + mCell = esm.getHString(); + break; + case ESM::FourCC<'D','N','A','M'>::value: + mPcFaction = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'N','A','M','E'>::value: + mResponse = esm.getHString(); + break; + case ESM::FourCC<'S','C','V','R'>::value: + { + SelectStruct ss; + ss.mSelectRule = esm.getHString(); + ss.mValue.read(esm, Variant::Format_Info); + mSelects.push_back(ss); + break; + } + case ESM::FourCC<'B','N','A','M'>::value: + mResultScript = esm.getHString(); + break; + case ESM::FourCC<'Q','S','T','N'>::value: + mQuestStatus = QS_Name; + esm.skipRecord(); + break; + case ESM::FourCC<'Q','S','T','F'>::value: + mQuestStatus = QS_Finished; + esm.skipRecord(); + break; + case ESM::FourCC<'Q','S','T','R'>::value: + mQuestStatus = QS_Restart; + esm.skipRecord(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - - esm.getSubNameIs("DATA"); - esm.getHT(mData, 12); - - if (!esm.hasMoreSubs()) - return; - - // What follows is somewhat spaghetti-ish, but it's worth if for - // an extra speedup. INFO is by far the most common record type. - - // subName is a reference to the original, so it changes whenever - // a new sub name is read. esm.isEmptyOrGetName() will get the - // next name for us, or return true if there are no more records. - esm.getSubName(); - const NAME &subName = esm.retSubName(); - - if (subName.val == REC_ONAM) - { - mActor = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_RNAM) - { - mRace = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_CNAM) - { - mClass = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_FNAM) - { - mFaction = esm.getHString(); - if (mFaction == "FFFF") - mFactionLess = true; - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_ANAM) - { - mCell = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_DNAM) - { - mPcFaction = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_SNAM) - { - mSound = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - if (subName.val == REC_NAME) - { - mResponse = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - while (subName.val == REC_SCVR) - { - SelectStruct ss; - - ss.mSelectRule = esm.getHString(); - - ss.mValue.read (esm, Variant::Format_Info); - - mSelects.push_back(ss); - - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_BNAM) - { - mResultScript = esm.getHString(); - if (esm.isEmptyOrGetName()) - return; - } - - if (subName.val == REC_QSTN) - mQuestStatus = QS_Name; - else if (subName.val == REC_QSTF) - mQuestStatus = QS_Finished; - else if (subName.val == REC_QSTR) - mQuestStatus = QS_Restart; - else if (subName.val == REC_DELE) - mQuestStatus = QS_Deleted; - else - esm.fail( - "Don't know what to do with " + subName.toString() - + " in INFO " + mId); - - if (mQuestStatus != QS_None) - // Skip rest of record - esm.skipRecord(); } void DialInfo::save(ESMWriter &esm) const @@ -158,8 +119,7 @@ namespace ESM if (mIsDeleted) { - esm.writeHNCString("NAME", mResponse); - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } @@ -186,7 +146,6 @@ namespace ESM case QS_Name: esm.writeHNT("QSTN",'\1'); break; case QS_Finished: esm.writeHNT("QSTF", '\1'); break; case QS_Restart: esm.writeHNT("QSTR", '\1'); break; - case QS_Deleted: esm.writeHNT("DELE", '\1'); break; default: break; } } diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index c243cd50e0..65363d1be8 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -59,8 +59,7 @@ struct DialInfo QS_None = 0, QS_Name = 1, QS_Finished = 2, - QS_Restart = 3, - QS_Deleted + QS_Restart = 3 }; // Rules for when to include this item in the final list of options diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index a7018b36db..51a1f48059 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Ingredient::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,10 +50,13 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing IRDT subrecord"); // horrible hack to fix broken data in records @@ -79,9 +86,10 @@ namespace ESM void Ingredient::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 1e07086bcd..9c34ef6578 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -13,49 +12,67 @@ namespace ESM void LevelledListBase::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + mIsDeleted = false; + + bool hasName = false; + while (esm.hasMoreSubs()) { - return; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','N','A','M'>::value: + esm.getHT(mChanceNone); + break; + case ESM::FourCC<'I','N','D','X'>::value: + { + int length = 0; + esm.getHT(length); + mList.resize(length); + + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + break; + } + default: + mList.clear(); + esm.skipRecord(); + break; + } } - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) - { - int len; - esm.getHT(len); - mList.resize(len); - } - else - { - // Original engine ignores rest of the record, even if there are items following - mList.clear(); - esm.skipRecord(); - return; - } - - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. - - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); - } + if (!hasName) + esm.fail("Missing NAME subrecord"); } + void LevelledListBase::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index a153d500a0..441e96d0ac 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Light::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -49,17 +53,22 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing LHDT subrecord"); } void Light::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 3b169af33e..5ee041daba 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,23 @@ namespace ESM void Lockpick::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +49,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing LKDT subrecord"); } void Lockpick::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 13315e6848..7c14536edf 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,17 +14,49 @@ namespace ESM void LandTexture::load(ESMReader &esm) { - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - esm.getHNT(mIndex, "INTV"); - mTexture = esm.getHNString("DATA"); + mIsDeleted = false; + + bool hasName = false; + bool hasIndex = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = false; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'I','N','T','V'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + mTexture = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasIndex) + esm.fail("Missing INTV subrecord"); } void LandTexture::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNCString("NAME", mId); esm.writeHNT("INTV", mIndex); esm.writeHNCString("DATA", mTexture); diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 08cbcf7414..de9ccdd6aa 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Miscellaneous::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -44,18 +48,25 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + default: + esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing MCDT subrecord"); } void Miscellaneous::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index eadf23a21a..ff3213ee93 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,40 +3,45 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; NPC::NPC() - : mIsDeleted(false) + : mFlags(0), + mHasAI(false), + mIsDeleted(false) {} void NPC::load(ESMReader &esm) { + mIsDeleted = false; mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); mInventory.mList.clear(); mTransport.mList.clear(); mAiPackage.mList.clear(); + mHasAI = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasNpdt = false; bool hasFlags = false; - mHasAI = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -105,19 +110,24 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasNpdt) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasNpdt && !mIsDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags) + if (!hasFlags && !mIsDeleted) esm.fail("Missing FLAG subrecord"); } void NPC::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index f5287f9869..4ce9b9d9c7 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,24 @@ namespace ESM void Probe::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing PBDT subrecord"); } void Probe::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 2d99947b0c..b48ffa4b7b 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -3,64 +3,95 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int Region::sRecordId = REC_REGN; Region::Region() - : mIsDeleted(false) + : mMapColor(0), + mIsDeleted(false) {} void Region::load(ESMReader &esm) { - mIsDeleted = readDeleSubRecord(esm); - mId = esm.getHNString("NAME"); - mName = esm.getHNOString("FNAM"); + mIsDeleted = false; - esm.getSubNameIs("WEAT"); - esm.getSubHeader(); - if (esm.getVer() == VER_12) - { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData) - 2); - } - else if (esm.getVer() == VER_13) - { - // May include the additional two bytes (but not necessarily) - if (esm.getSubSize() == sizeof(mData)) - esm.getExact(&mData, sizeof(mData)); - else - { - mData.mA = 0; - mData.mB = 0; - esm.getExact(&mData, sizeof(mData)-2); - } - } - else - esm.fail("Don't know what to do in this version"); - - mSleepList = esm.getHNOString("BNAM"); - - esm.getHNT(mMapColor, "CNAM"); - - mSoundList.clear(); + bool hasName = false; while (esm.hasMoreSubs()) { - SoundRef sr; - esm.getHNT(sr, "SNAM", 33); - mSoundList.push_back(sr); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','E','A','T'>::value: + { + esm.getSubHeader(); + if (esm.getVer() == VER_12) + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData) - 2); + } + else if (esm.getVer() == VER_13) + { + // May include the additional two bytes (but not necessarily) + if (esm.getSubSize() == sizeof(mData)) + { + esm.getExact(&mData, sizeof(mData)); + } + else + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData)-2); + } + } + else + { + esm.fail("Don't know what to do in this version"); + } + break; + } + case ESM::FourCC<'B','N','A','M'>::value: + mSleepList = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + esm.getHT(mMapColor); + break; + case ESM::FourCC<'S','N','A','M'>::value: + SoundRef sr; + esm.getHT(sr, 33); + mSoundList.push_back(sr); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Region::save(ESMWriter &esm) const { if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } + esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index fb213efd83..74e682d63e 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,19 +14,24 @@ namespace ESM void Repair::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; - bool hasData = true; + bool hasName = false; + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,18 +50,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 529f0a66d4..333389ba41 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" #include @@ -64,23 +63,27 @@ namespace ESM void Script::load(ESMReader &esm) { - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - // In scripts DELE sub-record appears after a header. - // The script data is following after DELE in this case. - mIsDeleted = readDeleSubRecord(esm); - mVarNames.clear(); + mIsDeleted = false; + bool hasHeader = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'S','C','H','D'>::value: + SCHD data; + esm.getHT(data, 52); + mData = data.mData; + mId = data.mName.toString(); + hasHeader = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'S','C','V','R'>::value: // list of local variables loadSCVR(esm); @@ -95,8 +98,12 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } + + if (!hasHeader) + esm.fail("Missing SCHD subrecord"); } void Script::save(ESMWriter &esm) const @@ -116,7 +123,7 @@ namespace ESM if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); } if (!mVarNames.empty()) diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 261087be05..a20e6ee519 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -3,24 +3,21 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; SoundGenerator::SoundGenerator() - : mIsDeleted(false) + : mType(LeftFoot), + mIsDeleted(false) {} void SoundGenerator::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +25,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mType, 4); hasData = true; @@ -40,23 +45,26 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing DATA"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing DATA subrecord"); } void SoundGenerator::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) - { - writeDeleSubRecord(esm); - return; - } - esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } } void SoundGenerator::blank() diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 9a1a52b1e5..55fe692929 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Sound::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mSound = esm.getHString(); break; @@ -37,18 +41,23 @@ namespace ESM break; default: esm.fail("Unknown subrecord"); + break; } } - if (!hasData) - esm.fail("Missing DATA"); + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing DATA subrecord"); } void Sound::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index d2d8c7d6df..28feffd209 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -16,13 +15,9 @@ namespace ESM void Spell::load(ESMReader &esm) { mEffects.mList.clear(); + mIsDeleted = false; - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } - + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -31,6 +26,14 @@ namespace ESM switch (val) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -43,18 +46,25 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; + default: + esm.fail("Unknown subrecord"); + break; } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing SPDT subrecord"); } void Spell::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } @@ -70,9 +80,7 @@ namespace ESM mData.mFlags = 0; mName.clear(); - mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 2fde46bd2b..9a146a3705 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,24 +14,46 @@ namespace ESM void Static::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) + mIsDeleted = false; + + bool hasName = false; + while (esm.hasMoreSubs()) { - return; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } } - mModel = esm.getHNString("MODL"); + if (!hasName) + esm.fail("Missing NAME subrecord"); } void Static::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); if (mIsDeleted) { - writeDeleSubRecord(esm); - return; + esm.writeHNCString("DELE", ""); + } + else + { + esm.writeHNCString("MODL", mModel); } - - esm.writeHNCString("MODL", mModel); } void Static::blank() diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 38fb94adbf..98302c13d5 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { @@ -15,12 +14,9 @@ namespace ESM void Weapon::load(ESMReader &esm) { - mId = esm.getHNString("NAME"); - if (mIsDeleted = readDeleSubRecord(esm)) - { - return; - } + mIsDeleted = false; + bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { @@ -28,6 +24,14 @@ namespace ESM uint32_t name = esm.retSubName().val; switch (name) { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,15 +55,19 @@ namespace ESM esm.fail("Unknown subrecord"); } } - if (!hasData) + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) esm.fail("Missing WPDT subrecord"); } void Weapon::save(ESMWriter &esm) const { esm.writeHNCString("NAME", mId); + if (mIsDeleted) { - writeDeleSubRecord(esm); + esm.writeHNCString("DELE", ""); return; } From e65ff723ce6e71da7d00e68820250682512418c1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 22:17:49 +0300 Subject: [PATCH 0776/1812] More ESM records have DELE handling. Changed records: Race, Land, Pathgrid, StartScript, DebugProfile, Filter --- components/esm/debugprofile.cpp | 45 +++- components/esm/debugprofile.hpp | 4 + components/esm/filter.cpp | 41 +++- components/esm/filter.hpp | 4 + components/esm/loadland.cpp | 393 +++++++++++++++++--------------- components/esm/loadland.hpp | 4 +- components/esm/loadpgrd.cpp | 194 +++++++++------- components/esm/loadpgrd.hpp | 4 + components/esm/loadrace.cpp | 96 +++++--- components/esm/loadrace.hpp | 4 + components/esm/loadsscr.cpp | 18 ++ components/esm/loadsscr.hpp | 4 + 12 files changed, 504 insertions(+), 307 deletions(-) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 9c8164d299..d1e27debcf 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -7,17 +7,53 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; +ESM::DebugProfile::DebugProfile() + : mIsDeleted(false) +{} + void ESM::DebugProfile::load (ESMReader& esm) { - mId = esm.getHNString ("NAME"); - mDescription = esm.getHNString ("DESC"); - mScriptText = esm.getHNString ("SCRP"); - esm.getHNT (mFlags, "FLAG"); + mIsDeleted = false; + + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','P'>::value: + mScriptText = esm.getHString(); + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } } void ESM::DebugProfile::save (ESMWriter& esm) const { esm.writeHNCString ("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + esm.writeHNCString ("DESC", mDescription); esm.writeHNCString ("SCRP", mScriptText); esm.writeHNT ("FLAG", mFlags); @@ -28,4 +64,5 @@ void ESM::DebugProfile::blank() mDescription.clear(); mScriptText.clear(); mFlags = 0; + mIsDeleted = false; } diff --git a/components/esm/debugprofile.hpp b/components/esm/debugprofile.hpp index b54e8ff5fc..1709136f51 100644 --- a/components/esm/debugprofile.hpp +++ b/components/esm/debugprofile.hpp @@ -27,6 +27,10 @@ namespace ESM unsigned int mFlags; + bool mIsDeleted; + + DebugProfile(); + void load (ESMReader& esm); void save (ESMWriter& esm) const; diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index ee2c678692..57cb59454a 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -7,16 +7,50 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; +ESM::Filter::Filter() + : mIsDeleted(false) +{} + void ESM::Filter::load (ESMReader& esm) { - mId = esm.getHNString ("NAME"); - mFilter = esm.getHNString ("FILT"); - mDescription = esm.getHNString ("DESC"); + mIsDeleted = false; + + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','I','L','T'>::value: + mFilter = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } } void ESM::Filter::save (ESMWriter& esm) const { esm.writeHNCString ("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + esm.writeHNCString ("FILT", mFilter); esm.writeHNCString ("DESC", mDescription); } @@ -25,4 +59,5 @@ void ESM::Filter::blank() { mFilter.clear(); mDescription.clear(); + mIsDeleted = false; } diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp index bc3dd7bdcb..1a8af92298 100644 --- a/components/esm/filter.hpp +++ b/components/esm/filter.hpp @@ -18,6 +18,10 @@ namespace ESM std::string mFilter; + bool mIsDeleted; + + Filter(); + void load (ESMReader& esm); void save (ESMWriter& esm) const; diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b0897ec67d..6acaa6e6a3 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -8,211 +8,234 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) -{ - if (mDataTypes & Land::DATA_VNML) { - esm.writeHNT("VNML", mNormals, sizeof(mNormals)); - } - if (mDataTypes & Land::DATA_VHGT) { - VHGT offsets; - offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE; - offsets.mUnk1 = mUnk1; - offsets.mUnk2 = mUnk2; + void Land::LandData::save(ESMWriter &esm) + { + if (mDataTypes & Land::DATA_VNML) { + esm.writeHNT("VNML", mNormals, sizeof(mNormals)); + } + if (mDataTypes & Land::DATA_VHGT) { + VHGT offsets; + offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE; + offsets.mUnk1 = mUnk1; + offsets.mUnk2 = mUnk2; - float prevY = mHeights[0]; - int number = 0; // avoid multiplication - for (int i = 0; i < LAND_SIZE; ++i) { - float diff = (mHeights[number] - prevY) / HEIGHT_SCALE; - offsets.mHeightData[number] = - (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); - - float prevX = prevY = mHeights[number]; - ++number; - - for (int j = 1; j < LAND_SIZE; ++j) { - diff = (mHeights[number] - prevX) / HEIGHT_SCALE; + float prevY = mHeights[0]; + int number = 0; // avoid multiplication + for (int i = 0; i < LAND_SIZE; ++i) { + float diff = (mHeights[number] - prevY) / HEIGHT_SCALE; offsets.mHeightData[number] = (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); - prevX = mHeights[number]; + float prevX = prevY = mHeights[number]; ++number; - } - } - esm.writeHNT("VHGT", offsets, sizeof(VHGT)); - } - if (mDataTypes & Land::DATA_WNAM) { - esm.writeHNT("WNAM", mWnam, 81); - } - if (mDataTypes & Land::DATA_VCLR) { - esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS); - } - if (mDataTypes & Land::DATA_VTEX) { - static uint16_t vtex[LAND_NUM_TEXTURES]; - transposeTextureData(mTextures, vtex); - esm.writeHNT("VTEX", vtex, sizeof(vtex)); - } -} -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) -{ - int readPos = 0; //bit ugly, but it works - for ( int y1 = 0; y1 < 4; y1++ ) - for ( int x1 = 0; x1 < 4; x1++ ) - for ( int y2 = 0; y2 < 4; y2++) - for ( int x2 = 0; x2 < 4; x2++ ) - out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++]; -} + for (int j = 1; j < LAND_SIZE; ++j) { + diff = (mHeights[number] - prevX) / HEIGHT_SCALE; + offsets.mHeightData[number] = + (diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5); -Land::Land() - : mFlags(0) - , mX(0) - , mY(0) - , mPlugin(0) - , mEsm(NULL) - , mDataTypes(0) - , mDataLoaded(false) - , mLandData(NULL) -{ -} - -Land::~Land() -{ - delete mLandData; -} - -void Land::load(ESMReader &esm) -{ - mEsm = &esm; - mPlugin = mEsm->getIndex(); - - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(mX); - esm.getT(mY); - - esm.getHNT(mFlags, "DATA"); - - // Store the file position - mContext = esm.getContext(); - - // Skip these here. Load the actual data when the cell is loaded. - if (esm.isNextSub("VNML")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VNML; - } - if (esm.isNextSub("VHGT")) - { - esm.skipHSubSize(4232); - mDataTypes |= DATA_VHGT; - } - if (esm.isNextSub("WNAM")) - { - esm.skipHSubSize(81); - mDataTypes |= DATA_WNAM; - } - if (esm.isNextSub("VCLR")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VCLR; - } - if (esm.isNextSub("VTEX")) - { - esm.skipHSubSize(512); - mDataTypes |= DATA_VTEX; - } - - mDataLoaded = 0; - mLandData = NULL; -} - -void Land::save(ESMWriter &esm) const -{ - esm.startSubRecord("INTV"); - esm.writeT(mX); - esm.writeT(mY); - esm.endRecord("INTV"); - - esm.writeHNT("DATA", mFlags); -} - -void Land::loadData(int flags) -{ - // Try to load only available data - flags = flags & mDataTypes; - // Return if all required data is loaded - if ((mDataLoaded & flags) == flags) { - return; - } - // Create storage if nothing is loaded - if (mLandData == NULL) { - mLandData = new LandData; - mLandData->mDataTypes = mDataTypes; - } - mEsm->restoreContext(mContext); - - if (mEsm->isNextSub("VNML")) { - condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); - } - - if (mEsm->isNextSub("VHGT")) { - static VHGT vhgt; - if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { - float rowOffset = vhgt.mHeightOffset; - for (int y = 0; y < LAND_SIZE; y++) { - rowOffset += vhgt.mHeightData[y * LAND_SIZE]; - - mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE; - - float colOffset = rowOffset; - for (int x = 1; x < LAND_SIZE; x++) { - colOffset += vhgt.mHeightData[y * LAND_SIZE + x]; - mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE; + prevX = mHeights[number]; + ++number; } } - mLandData->mUnk1 = vhgt.mUnk1; - mLandData->mUnk2 = vhgt.mUnk2; + esm.writeHNT("VHGT", offsets, sizeof(VHGT)); + } + if (mDataTypes & Land::DATA_WNAM) { + esm.writeHNT("WNAM", mWnam, 81); + } + if (mDataTypes & Land::DATA_VCLR) { + esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS); + } + if (mDataTypes & Land::DATA_VTEX) { + static uint16_t vtex[LAND_NUM_TEXTURES]; + transposeTextureData(mTextures, vtex); + esm.writeHNT("VTEX", vtex, sizeof(vtex)); } } - if (mEsm->isNextSub("WNAM")) { - condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); + void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) + { + int readPos = 0; //bit ugly, but it works + for ( int y1 = 0; y1 < 4; y1++ ) + for ( int x1 = 0; x1 < 4; x1++ ) + for ( int y2 = 0; y2 < 4; y2++) + for ( int x2 = 0; x2 < 4; x2++ ) + out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++]; } - if (mEsm->isNextSub("VCLR")) - condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); - if (mEsm->isNextSub("VTEX")) { - static uint16_t vtex[LAND_NUM_TEXTURES]; - if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { - LandData::transposeTextureData(vtex, mLandData->mTextures); - } - } -} -void Land::unloadData() -{ - if (mDataLoaded) + Land::Land() + : mFlags(0) + , mX(0) + , mY(0) + , mPlugin(0) + , mEsm(NULL) + , mDataTypes(0) + , mDataLoaded(false) + , mLandData(NULL) + , mIsDeleted(false) + { + } + + Land::~Land() { delete mLandData; - mLandData = NULL; + } + + void Land::load(ESMReader &esm) + { + mEsm = &esm; + mPlugin = mEsm->getIndex(); + mIsDeleted = false; + + // Get the grid location + esm.getSubNameIs("INTV"); + esm.getSubHeaderIs(8); + esm.getT(mX); + esm.getT(mY); + + esm.getHNT(mFlags, "DATA"); + + if (esm.isNextSub("DELE")) + { + esm.skipHSub(); + mIsDeleted = true; + } + + // Store the file position + mContext = esm.getContext(); + + // Skip these here. Load the actual data when the cell is loaded. + if (esm.isNextSub("VNML")) + { + esm.skipHSubSize(12675); + mDataTypes |= DATA_VNML; + } + if (esm.isNextSub("VHGT")) + { + esm.skipHSubSize(4232); + mDataTypes |= DATA_VHGT; + } + if (esm.isNextSub("WNAM")) + { + esm.skipHSubSize(81); + mDataTypes |= DATA_WNAM; + } + if (esm.isNextSub("VCLR")) + { + esm.skipHSubSize(12675); + mDataTypes |= DATA_VCLR; + } + if (esm.isNextSub("VTEX")) + { + esm.skipHSubSize(512); + mDataTypes |= DATA_VTEX; + } + mDataLoaded = 0; + mLandData = NULL; } -} -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) -{ - if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { - mEsm->getHExact(ptr, size); - mDataLoaded |= dataFlag; - return true; + void Land::save(ESMWriter &esm) const + { + esm.startSubRecord("INTV"); + esm.writeT(mX); + esm.writeT(mY); + esm.endRecord("INTV"); + + esm.writeHNT("DATA", mFlags); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } + + if (mLandData != NULL) + { + mLandData->save(esm); + } } - mEsm->skipHSubSize(size); - return false; -} -bool Land::isDataLoaded(int flags) const -{ - return (mDataLoaded & flags) == (flags & mDataTypes); -} + void Land::blank() + { + mIsDeleted = false; + } + + void Land::loadData(int flags) + { + // Try to load only available data + flags = flags & mDataTypes; + // Return if all required data is loaded + if ((mDataLoaded & flags) == flags) { + return; + } + // Create storage if nothing is loaded + if (mLandData == NULL) { + mLandData = new LandData; + mLandData->mDataTypes = mDataTypes; + } + mEsm->restoreContext(mContext); + + if (mEsm->isNextSub("VNML")) { + condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); + } + + if (mEsm->isNextSub("VHGT")) { + static VHGT vhgt; + if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { + float rowOffset = vhgt.mHeightOffset; + for (int y = 0; y < LAND_SIZE; y++) { + rowOffset += vhgt.mHeightData[y * LAND_SIZE]; + + mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE; + + float colOffset = rowOffset; + for (int x = 1; x < LAND_SIZE; x++) { + colOffset += vhgt.mHeightData[y * LAND_SIZE + x]; + mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE; + } + } + mLandData->mUnk1 = vhgt.mUnk1; + mLandData->mUnk2 = vhgt.mUnk2; + } + } + + if (mEsm->isNextSub("WNAM")) { + condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); + } + if (mEsm->isNextSub("VCLR")) + condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); + if (mEsm->isNextSub("VTEX")) { + static uint16_t vtex[LAND_NUM_TEXTURES]; + if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { + LandData::transposeTextureData(vtex, mLandData->mTextures); + } + } + } + + void Land::unloadData() + { + if (mDataLoaded) + { + delete mLandData; + mLandData = NULL; + mDataLoaded = 0; + } + } + + bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) + { + if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { + mEsm->getHExact(ptr, size); + mDataLoaded |= dataFlag; + return true; + } + mEsm->skipHSubSize(size); + return false; + } + + bool Land::isDataLoaded(int flags) const + { + return (mDataLoaded & flags) == (flags & mDataTypes); + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 61ce4855eb..d9ee0015a4 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -97,10 +97,12 @@ struct Land LandData *mLandData; + bool mIsDeleted; + void load(ESMReader &esm); void save(ESMWriter &esm) const; - void blank() {} + void blank(); /** * Actually loads data diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index fc0974c9d8..5e8de9d573 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -32,98 +32,137 @@ namespace ESM { } -void Pathgrid::load(ESMReader &esm) -{ - esm.getHNT(mData, "DATA", 12); - mCell = esm.getHNString("NAME"); + Pathgrid::Pathgrid() + : mIsDeleted(false) + {} - mPoints.clear(); - mEdges.clear(); - - // keep track of total connections so we can reserve edge vector size - int edgeCount = 0; - - if (esm.isNextSub("PGRP")) + void Pathgrid::load(ESMReader &esm) { - esm.getSubHeader(); - int size = esm.getSubSize(); - // Check that the sizes match up. Size = 16 * s2 (path points) - if (size != static_cast (sizeof(Point) * mData.mS2)) - esm.fail("Path point subrecord size mismatch"); - else - { - int pointCount = mData.mS2; - mPoints.reserve(pointCount); - for (int i = 0; i < pointCount; ++i) - { - Point p; - esm.getExact(&p, sizeof(Point)); - mPoints.push_back(p); - edgeCount += p.mConnectionNum; - } - } - } + mPoints.clear(); + mEdges.clear(); - if (esm.isNextSub("PGRC")) - { - esm.getSubHeader(); - int size = esm.getSubSize(); - if (size % sizeof(int) != 0) - esm.fail("PGRC size not a multiple of 4"); - else - { - int rawConnNum = size / sizeof(int); - std::vector rawConnections; - rawConnections.reserve(rawConnNum); - for (int i = 0; i < rawConnNum; ++i) - { - int currentValue; - esm.getT(currentValue); - rawConnections.push_back(currentValue); - } + // keep track of total connections so we can reserve edge vector size + int edgeCount = 0; - std::vector::const_iterator rawIt = rawConnections.begin(); - int pointIndex = 0; - mEdges.reserve(edgeCount); - for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex) + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) { - unsigned char connectionNum = (*it).mConnectionNum; - for (int i = 0; i < connectionNum; ++i) { - Edge edge; - edge.mV0 = pointIndex; - edge.mV1 = *rawIt; - ++rawIt; - mEdges.push_back(edge); + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mCell = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'P','G','R','P'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + // Check that the sizes match up. Size = 16 * s2 (path points) + if (size != static_cast (sizeof(Point) * mData.mS2)) + esm.fail("Path point subrecord size mismatch"); + else + { + int pointCount = mData.mS2; + mPoints.reserve(pointCount); + for (int i = 0; i < pointCount; ++i) + { + Point p; + esm.getExact(&p, sizeof(Point)); + mPoints.push_back(p); + edgeCount += p.mConnectionNum; + } + } + break; } + case ESM::FourCC<'P','G','R','C'>::value: + { + esm.getSubHeader(); + int size = esm.getSubSize(); + if (size % sizeof(int) != 0) + esm.fail("PGRC size not a multiple of 4"); + else + { + int rawConnNum = size / sizeof(int); + std::vector rawConnections; + rawConnections.reserve(rawConnNum); + for (int i = 0; i < rawConnNum; ++i) + { + int currentValue; + esm.getT(currentValue); + rawConnections.push_back(currentValue); + } + + std::vector::const_iterator rawIt = rawConnections.begin(); + int pointIndex = 0; + mEdges.reserve(edgeCount); + for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex) + { + unsigned char connectionNum = (*it).mConnectionNum; + for (int i = 0; i < connectionNum; ++i) { + Edge edge; + edge.mV0 = pointIndex; + edge.mV1 = *rawIt; + ++rawIt; + mEdges.push_back(edge); + } + } + } + break; + } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + default: + esm.fail("Unknown subrecord"); + break; } } - } -} -void Pathgrid::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mData, 12); - esm.writeHNCString("NAME", mCell); - if (!mPoints.empty()) - { - esm.startSubRecord("PGRP"); - for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it) - { - esm.writeT(*it); - } - esm.endRecord("PGRP"); + if (!hasData) + esm.fail("Missing DATA subrecord"); + if (!hasName) + esm.fail("Missing NAME subrecord"); } - if (!mEdges.empty()) + void Pathgrid::save(ESMWriter &esm) const { - esm.startSubRecord("PGRC"); - for (std::vector::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it) + esm.writeHNT("DATA", mData, 12); + esm.writeHNCString("NAME", mCell); + + if (mIsDeleted) { - esm.writeT(it->mV1); + esm.writeHNCString("DELE", ""); + return; + } + + if (!mPoints.empty()) + { + esm.startSubRecord("PGRP"); + for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it) + { + esm.writeT(*it); + } + esm.endRecord("PGRP"); + } + + if (!mEdges.empty()) + { + esm.startSubRecord("PGRC"); + for (std::vector::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it) + { + esm.writeT(it->mV1); + } + esm.endRecord("PGRC"); } - esm.endRecord("PGRC"); } -} void Pathgrid::blank() { @@ -134,5 +173,6 @@ void Pathgrid::save(ESMWriter &esm) const mData.mS2 = 0; mPoints.clear(); mEdges.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index f33ccbedf9..4b82d95711 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -53,6 +53,10 @@ struct Pathgrid typedef std::vector EdgeList; EdgeList mEdges; + bool mIsDeleted; + + Pathgrid(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 3feb06c927..12762bda3b 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -8,6 +8,10 @@ namespace ESM { unsigned int Race::sRecordId = REC_RACE; + Race::Race() + : mIsDeleted(false) + {} + int Race::MaleFemale::getValue (bool male) const { return male ? mMale : mFemale; @@ -18,47 +22,65 @@ namespace ESM return static_cast(male ? mMale : mFemale); } -void Race::load(ESMReader &esm) -{ - mPowers.mList.clear(); - - mId = esm.getHNString("NAME"); - - bool hasData = false; - while (esm.hasMoreSubs()) + void Race::load(ESMReader &esm) { - esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + mPowers.mList.clear(); + mIsDeleted = false; + + bool hasName = false; + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'R','A','D','T'>::value: - esm.getHT(mData, 140); - hasData = true; - break; - case ESM::FourCC<'D','E','S','C'>::value: - mDescription = esm.getHString(); - break; - case ESM::FourCC<'N','P','C','S'>::value: - mPowers.add(esm); - break; - default: - esm.fail("Unknown subrecord"); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData && !mIsDeleted) + esm.fail("Missing RADT subrecord"); + } + void Race::save(ESMWriter &esm) const + { + esm.writeHNCString("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("RADT", mData, 140); + mPowers.save(esm); + esm.writeHNOString("DESC", mDescription); } - if (!hasData) - esm.fail("Missing RADT subrecord"); -} -void Race::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mId); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("RADT", mData, 140); - mPowers.save(esm); - esm.writeHNOString("DESC", mDescription); -} void Race::blank() { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 553d2e68b1..e8e9a442bb 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -68,6 +68,10 @@ struct Race std::string mId, mName, mDescription; SpellList mPowers; + bool mIsDeleted; + + Race(); + void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 7380dd0a7f..076f73742b 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,8 +8,14 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; + StartScript::StartScript() + : mIsDeleted(false) + {} + void StartScript::load(ESMReader &esm) { + mIsDeleted = false; + bool hasData = false; bool hasName = false; while (esm.hasMoreSubs()) @@ -26,10 +32,16 @@ namespace ESM mId = esm.getHString(); hasName = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + mIsDeleted = true; + break; default: esm.fail("Unknown subrecord"); + break; } } + if (!hasData) esm.fail("Missing DATA"); if (!hasName) @@ -39,10 +51,16 @@ namespace ESM { esm.writeHNString("DATA", mData); esm.writeHNString("NAME", mId); + + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); + } } void StartScript::blank() { mData.clear(); + mIsDeleted = false; } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index dc7ad6a42a..e475abd866 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -26,6 +26,10 @@ struct StartScript std::string mData; std::string mId; + bool mIsDeleted; + + StartScript(); + // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm) const; From 5fd48efd28e45336a03f5ee2f5b68f799159650e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 22:31:59 +0300 Subject: [PATCH 0777/1812] Some refactoring. Remove unused code --- apps/openmw/mwworld/store.cpp | 33 +++- components/esm/loadbsgn.cpp | 1 - components/esm/loadcell.cpp | 274 +++++++++++++++++----------------- components/esm/loadlock.cpp | 1 + components/esm/loadltex.cpp | 2 +- components/esm/util.cpp | 75 ---------- components/esm/util.hpp | 47 ------ 7 files changed, 173 insertions(+), 260 deletions(-) delete mode 100644 components/esm/util.cpp diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 8f55bb466e..55fb43e000 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -194,7 +194,7 @@ namespace MWWorld if (inserted.second) mShared.push_back(&inserted.first->second); - return RecordId(record.mId, ESM::isRecordDeleted(record)); + return RecordId(record.mId, record.mIsDeleted); } template void Store::setUp() @@ -327,7 +327,7 @@ namespace MWWorld record.load (reader); insert (record); - return RecordId(record.mId, ESM::isRecordDeleted(record)); + return RecordId(record.mId, record.mIsDeleted); } // LandTexture @@ -1083,6 +1083,35 @@ namespace MWWorld return RecordId(script.mId); } + + // GameSetting + // Need to specialize load() and read() methods, because GameSetting can't + // be deleted (has no mIsDeleted flag) + //========================================================================= + + template <> + inline RecordId Store::load(ESM::ESMReader &reader) + { + ESM::GameSetting setting; + setting.load(reader); + Misc::StringUtils::toLower(setting.mId); + + std::pair inserted = mStatic.insert(std::make_pair(setting.mId, setting)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + return RecordId(setting.mId); + } + + template <> + inline RecordId Store::read(ESM::ESMReader &reader) + { + ESM::GameSetting setting; + setting.load(reader); + insert(setting); + + return RecordId(setting.mId); + } } template class MWWorld::Store; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 9f5cd72705..54de009aad 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -3,7 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" -#include "util.hpp" namespace ESM { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 67701a5b74..7e02f0f85f 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -12,7 +12,6 @@ #include "esmwriter.hpp" #include "defs.hpp" #include "cellid.hpp" -#include "util.hpp" namespace { @@ -53,171 +52,178 @@ namespace ESM return ref.mRefNum == refNum; } -void Cell::load(ESMReader &esm, bool saveContext) -{ - loadName(esm); - loadData(esm); - loadCell(esm, saveContext); -} - -void Cell::loadName(ESMReader &esm) -{ - mName = esm.getHNString("NAME"); - mIsDeleted = readDeleSubRecord(esm); -} - -void Cell::loadCell(ESMReader &esm, bool saveContext) -{ - mRefNumCounter = 0; - - if (mData.mFlags & Interior) + void Cell::load(ESMReader &esm, bool saveContext) { - // Interior cells - if (esm.isNextSub("INTV")) - { - int waterl; - esm.getHT(waterl); - mWater = (float) waterl; - mWaterInt = true; - } - else if (esm.isNextSub("WHGT")) - { - esm.getHT(mWater); - } + loadName(esm); + loadData(esm); + loadCell(esm, saveContext); + } - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if (mData.mFlags & QuasiEx) + void Cell::loadName(ESMReader &esm) + { + mName = esm.getHNString("NAME"); + + mIsDeleted = false; + if (esm.isNextSub("DELE")) + { + esm.skipHSub(); + mIsDeleted = true; + } + } + + void Cell::loadCell(ESMReader &esm, bool saveContext) + { + mRefNumCounter = 0; + + if (mData.mFlags & Interior) + { + // Interior cells + if (esm.isNextSub("INTV")) + { + int waterl; + esm.getHT(waterl); + mWater = (float) waterl; + mWaterInt = true; + } + else if (esm.isNextSub("WHGT")) + { + esm.getHT(mWater); + } + + // Quasi-exterior cells have a region (which determines the + // weather), pure interior cells have ambient lighting + // instead. + if (mData.mFlags & QuasiEx) + mRegion = esm.getHNOString("RGNN"); + else if (esm.isNextSub("AMBI")) + esm.getHT(mAmbi); + } + else + { + // Exterior cells mRegion = esm.getHNOString("RGNN"); - else if (esm.isNextSub("AMBI")) - esm.getHT(mAmbi); + + mMapColor = 0; + esm.getHNOT(mMapColor, "NAM5"); + } + if (esm.isNextSub("NAM0")) { + esm.getHT(mRefNumCounter); + } + + if (saveContext) { + mContextList.push_back(esm.getContext()); + esm.skipRecord(); + } } - else + + void Cell::loadData(ESMReader &esm) { - // Exterior cells - mRegion = esm.getHNOString("RGNN"); - - mMapColor = 0; - esm.getHNOT(mMapColor, "NAM5"); - } - if (esm.isNextSub("NAM0")) { - esm.getHT(mRefNumCounter); + esm.getHNT(mData, "DATA", 12); } - if (saveContext) { + void Cell::postLoad(ESMReader &esm) + { + // Save position of the cell references and move on mContextList.push_back(esm.getContext()); esm.skipRecord(); } -} -void Cell::loadData(ESMReader &esm) -{ - esm.getHNT(mData, "DATA", 12); -} - -void Cell::postLoad(ESMReader &esm) -{ - // Save position of the cell references and move on - mContextList.push_back(esm.getContext()); - esm.skipRecord(); -} - -void Cell::save(ESMWriter &esm) const -{ - esm.writeHNCString("NAME", mName); - if (mIsDeleted) + void Cell::save(ESMWriter &esm) const { - writeDeleSubRecord(esm); - } + esm.writeHNCString("NAME", mName); - esm.writeHNT("DATA", mData, 12); - if (mData.mFlags & Interior) - { - if (mWaterInt) { - int water = - (mWater >= 0) ? (int) (mWater + 0.5) : (int) (mWater - 0.5); - esm.writeHNT("INTV", water); - } else { - esm.writeHNT("WHGT", mWater); + if (mIsDeleted) + { + esm.writeHNCString("DELE", ""); } - if (mData.mFlags & QuasiEx) + esm.writeHNT("DATA", mData, 12); + if (mData.mFlags & Interior) + { + if (mWaterInt) { + int water = + (mWater >= 0) ? (int) (mWater + 0.5) : (int) (mWater - 0.5); + esm.writeHNT("INTV", water); + } else { + esm.writeHNT("WHGT", mWater); + } + + if (mData.mFlags & QuasiEx) + esm.writeHNOCString("RGNN", mRegion); + else + esm.writeHNT("AMBI", mAmbi, 16); + } + else + { esm.writeHNOCString("RGNN", mRegion); - else - esm.writeHNT("AMBI", mAmbi, 16); - } - else - { - esm.writeHNOCString("RGNN", mRegion); - if (mMapColor != 0) - esm.writeHNT("NAM5", mMapColor); + if (mMapColor != 0) + esm.writeHNT("NAM5", mMapColor); + } + + if (mRefNumCounter != 0) + esm.writeHNT("NAM0", mRefNumCounter); } - if (mRefNumCounter != 0 && !mIsDeleted) - esm.writeHNT("NAM0", mRefNumCounter); -} - -void Cell::restore(ESMReader &esm, int iCtx) const -{ - esm.restoreContext(mContextList.at (iCtx)); -} - -std::string Cell::getDescription() const -{ - if (mData.mFlags & Interior) + void Cell::restore(ESMReader &esm, int iCtx) const { - return mName; + esm.restoreContext(mContextList.at (iCtx)); } - else - { - std::ostringstream stream; - stream << mData.mX << ", " << mData.mY; - return stream.str(); - } -} -bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) -{ - // TODO: Try and document reference numbering, I don't think this has been done anywhere else. - if (!esm.hasMoreSubs()) - return false; - - // NOTE: We should not need this check. It is a safety check until we have checked - // more plugins, and how they treat these moved references. - if (esm.isNextSub("MVRF")) + std::string Cell::getDescription() const { - if (ignoreMoves) + if (mData.mFlags & Interior) { - esm.getHT (mref->mRefNum.mIndex); - esm.getHNOT (mref->mTarget, "CNDT"); - adjustRefNum (mref->mRefNum, esm); + return mName; } else { - // skip rest of cell record (moved references), they are handled elsewhere - esm.skipRecord(); // skip MVRF, CNDT + std::ostringstream stream; + stream << mData.mX << ", " << mData.mY; + return stream.str(); + } + } + + bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) + { + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. + if (!esm.hasMoreSubs()) return false; + + // NOTE: We should not need this check. It is a safety check until we have checked + // more plugins, and how they treat these moved references. + if (esm.isNextSub("MVRF")) + { + if (ignoreMoves) + { + esm.getHT (mref->mRefNum.mIndex); + esm.getHNOT (mref->mTarget, "CNDT"); + adjustRefNum (mref->mRefNum, esm); + } + else + { + // skip rest of cell record (moved references), they are handled elsewhere + esm.skipRecord(); // skip MVRF, CNDT + return false; + } } + + ref.load (esm); + + // Identify references belonging to a parent file and adapt the ID accordingly. + adjustRefNum (ref.mRefNum, esm); + + return true; } - ref.load (esm); + bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) + { + esm.getHT(mref.mRefNum.mIndex); + esm.getHNOT(mref.mTarget, "CNDT"); - // Identify references belonging to a parent file and adapt the ID accordingly. - adjustRefNum (ref.mRefNum, esm); + adjustRefNum (mref.mRefNum, esm); - return true; -} - -bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) -{ - esm.getHT(mref.mRefNum.mIndex); - esm.getHNOT(mref.mTarget, "CNDT"); - - adjustRefNum (mref.mRefNum, esm); - - return true; -} + return true; + } void Cell::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 5ee041daba..2cfe43743b 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -26,6 +26,7 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); + hasName = true; break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 7c14536edf..6bd48d8011 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -26,7 +26,7 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); - hasName = false; + hasName = true; break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); diff --git a/components/esm/util.cpp b/components/esm/util.cpp deleted file mode 100644 index a5ec377a31..0000000000 --- a/components/esm/util.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "util.hpp" - -#include - -namespace ESM -{ - bool readDeleSubRecord(ESMReader &esm) - { - if (esm.isNextSub("DELE")) - { - esm.skipHSub(); - return true; - } - return false; - } - - void writeDeleSubRecord(ESMWriter &esm) - { - esm.writeHNT("DELE", static_cast(0)); - } - - template <> - bool isRecordDeleted(const StartScript &script) - { - return false; - } - - template <> - bool isRecordDeleted(const Race &race) - { - return false; - } - - template <> - bool isRecordDeleted(const GameSetting &gmst) - { - return false; - } - - template <> - bool isRecordDeleted(const Skill &skill) - { - return false; - } - - template <> - bool isRecordDeleted(const MagicEffect &mgef) - { - return false; - } - - template <> - bool isRecordDeleted(const Pathgrid &pgrd) - { - return false; - } - - template <> - bool isRecordDeleted(const Land &land) - { - return false; - } - - template <> - bool isRecordDeleted(const DebugProfile &profile) - { - return false; - } - - template <> - bool isRecordDeleted(const Filter &filter) - { - return false; - } -} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 531e7eb762..e16603b84f 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -8,16 +8,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "loadsscr.hpp" -#include "loadglob.hpp" -#include "loadrace.hpp" -#include "loadgmst.hpp" -#include "loadskil.hpp" -#include "loadmgef.hpp" -#include "loadland.hpp" -#include "loadpgrd.hpp" -#include "debugprofile.hpp" -#include "filter.hpp" namespace ESM { @@ -63,43 +53,6 @@ struct Vector3 } }; -bool readDeleSubRecord(ESMReader &esm); -void writeDeleSubRecord(ESMWriter &esm); - -template -bool isRecordDeleted(const RecordT &record) -{ - return record.mIsDeleted; -} - -// The following records can't be deleted (for now) -template <> -bool isRecordDeleted(const StartScript &script); - -template <> -bool isRecordDeleted(const Race &race); - -template <> -bool isRecordDeleted(const GameSetting &gmst); - -template <> -bool isRecordDeleted(const Skill &skill); - -template <> -bool isRecordDeleted(const MagicEffect &mgef); - -template <> -bool isRecordDeleted(const Pathgrid &pgrd); - -template <> -bool isRecordDeleted(const Land &land); - -template <> -bool isRecordDeleted(const DebugProfile &profile); - -template <> -bool isRecordDeleted(const Filter &filter); - } #endif From a4d3e59e5c7380ffb27b4d17d4574009e2b45379 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 18 Jul 2015 15:55:24 +0300 Subject: [PATCH 0778/1812] Add a separate method to check whether a record is deleted or not for IdCollection --- apps/opencs/model/world/idcollection.cpp | 3 +++ apps/opencs/model/world/idcollection.hpp | 4 ++-- apps/opencs/model/world/land.hpp | 10 ---------- apps/opencs/model/world/pathgrid.hpp | 10 ---------- apps/opencs/model/world/record.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/record.hpp | 23 +++++++++++++++++++++++ 6 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 apps/opencs/model/world/idcollection.cpp diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp new file mode 100644 index 0000000000..9571ed7734 --- /dev/null +++ b/apps/opencs/model/world/idcollection.cpp @@ -0,0 +1,3 @@ +#include "idcollection.hpp" + + diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index d08abce5b3..4acfdc4744 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -2,9 +2,9 @@ #define CSM_WOLRD_IDCOLLECTION_H #include -#include #include "collection.hpp" +#include "record.hpp" namespace CSMWorld { @@ -48,7 +48,7 @@ namespace CSMWorld std::string id = IdAccessorT().getId (record); int index = searchId (id); - if (ESM::isRecordDeleted (record)) + if (isRecordDeleted(record)) { if (index==-1) { diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index adf5c03317..e97a2d7dd8 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -4,7 +4,6 @@ #include #include #include -#include namespace CSMWorld { @@ -27,13 +26,4 @@ namespace CSMWorld }; } -namespace ESM -{ - template <> - bool isRecordDeleted(const CSMWorld::Land &land) - { - return false; - } -} - #endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index cd5e472c8b..7e7b7c3bb6 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -5,7 +5,6 @@ #include #include -#include namespace CSMWorld { @@ -27,13 +26,4 @@ namespace CSMWorld }; } -namespace ESM -{ - template <> - bool isRecordDeleted(const CSMWorld::Pathgrid &pgrd) - { - return false; - } -} - #endif diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index ef2f4d3202..87f5090fe4 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -19,3 +19,27 @@ bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } + +template<> +bool CSMWorld::isRecordDeleted(const CSMWorld::Land &land) +{ + return land.mLand->mIsDeleted; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::GameSetting &setting) +{ + return false; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::MagicEffect &effect) +{ + return false; +} + +template<> +bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) +{ + return false; +} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 3362f9f963..c43a8b6ca2 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -3,6 +3,12 @@ #include +#include +#include +#include + +#include "land.hpp" + namespace CSMWorld { struct RecordBase @@ -154,6 +160,23 @@ namespace CSMWorld mState = State_Erased; } } + + // Not all records can be deleted (may be changed in the future), + // so we need to use a separate method to check whether a record is deleted or not. + template + bool isRecordDeleted(const ESXRecordT &record) + { + return record.mIsDeleted; + } + + template<> + bool isRecordDeleted(const Land &land); + template<> + bool isRecordDeleted(const ESM::GameSetting &setting); + template<> + bool isRecordDeleted(const ESM::MagicEffect &effect); + template<> + bool isRecordDeleted(const ESM::Skill &skill); } #endif From e04e32bcffa3c95f7c2a007d5fcf09641fff0b03 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 18 Jul 2015 20:32:10 +0300 Subject: [PATCH 0779/1812] Delete infos of deleted dialogue when loading a content file --- apps/opencs/model/world/data.cpp | 4 +-- apps/opencs/model/world/infocollection.cpp | 36 ++++++++++++++++++++++ apps/opencs/model/world/infocollection.hpp | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 348656a7ca..91ccda73cd 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -998,11 +998,11 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (mJournals.tryDelete (record.mId)) { - /// \todo handle info records + mJournalInfos.removeDialogueInfos(record.mId); } else if (mTopics.tryDelete (record.mId)) { - /// \todo handle info records + mTopicInfos.removeDialogueInfos(record.mId); } else { diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 1b95c1505e..665b497d00 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -188,3 +188,39 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s return Range (begin, end); } + +void CSMWorld::InfoCollection::removeDialogueInfos(const std::string& dialogueId) +{ + std::string id = Misc::StringUtils::lowerCase(dialogueId); + std::vector erasedRecords; + + std::map::const_iterator current = getIdMap().lower_bound(id); + std::map::const_iterator end = getIdMap().end(); + for (; current != end; ++current) + { + Record record = getRecord(current->second); + + if (Misc::StringUtils::ciEqual(dialogueId, record.get().mTopicId)) + { + if (record.mState == RecordBase::State_ModifiedOnly) + { + erasedRecords.push_back(current->second); + } + else + { + record.mState = RecordBase::State_Deleted; + setRecord(current->second, record); + } + } + else + { + break; + } + } + + while (!erasedRecords.empty()) + { + removeRows(erasedRecords.back(), 1); + erasedRecords.pop_back(); + } +} diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index 6db47373d0..e5a5575c78 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -44,6 +44,8 @@ namespace CSMWorld Range getTopicRange (const std::string& topic) const; ///< Return iterators that point to the beginning and past the end of the range for /// the given topic. + + void removeDialogueInfos(const std::string& dialogueId); }; } From 8e6a7be6f543a112c6aa3e814f572a9d2839ab15 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 11:42:05 +0300 Subject: [PATCH 0780/1812] Implement saving of deleted records --- apps/opencs/model/doc/savingstages.cpp | 176 ++++++++++--------------- apps/opencs/model/doc/savingstages.hpp | 26 ++-- apps/opencs/model/world/collection.hpp | 6 + apps/opencs/model/world/record.cpp | 24 ++++ apps/opencs/model/world/record.hpp | 16 +++ 5 files changed, 125 insertions(+), 123 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd6..dbfa4651b7 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -100,84 +100,72 @@ int CSMDoc::WriteDialogueCollectionStage::setup() void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages) { + ESM::ESMWriter& writer = mState.getWriter(); const CSMWorld::Record& topic = mTopics.getRecord (stage); - CSMWorld::RecordBase::State state = topic.mState; - - if (state==CSMWorld::RecordBase::State_Deleted) + if (topic.mState == CSMWorld::RecordBase::State_Deleted) { // if the topic is deleted, we do not need to bother with INFO records. + ESM::Dialogue dialogue = topic.get(); + dialogue.mIsDeleted = true; - /// \todo wrote record with delete flag - + writer.startRecord(dialogue.sRecordId); + dialogue.save(writer); + writer.endRecord(dialogue.sRecordId); return; } // Test, if we need to save anything associated info records. bool infoModified = false; - CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId); for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; - - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly || - state==CSMWorld::RecordBase::State_Deleted) + if (topic.isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { infoModified = true; break; } } - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly || - infoModified) + if (topic.isModified() || infoModified) { - mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); - topic.mModified.save (mState.getWriter()); - mState.getWriter().endRecord (topic.mModified.sRecordId); + ESM::Dialogue dialogue = topic.get(); + + writer.startRecord (dialogue.sRecordId); + dialogue.save (writer); + writer.endRecord (dialogue.sRecordId); // write modified selected info records - for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; - ++iter) + for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; - - if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo wrote record with delete flag - } - else if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); + info.mIsDeleted = (iter->mState == CSMWorld::RecordBase::State_Deleted); + info.mPrev = ""; if (iter!=range.first) { CSMWorld::InfoCollection::RecordConstIterator prev = iter; --prev; - info.mPrev = - prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1); + info.mPrev = prev->get().mId.substr (prev->get().mId.find_last_of ('#')+1); } CSMWorld::InfoCollection::RecordConstIterator next = iter; ++next; + info.mNext = ""; if (next!=range.second) { - info.mNext = - next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1); + info.mNext = next->get().mId.substr (next->get().mId.find_last_of ('#')+1); } - mState.getWriter().startRecord (info.sRecordId); - mState.getWriter().writeHNCString ("INAM", info.mId); - info.save (mState.getWriter()); - mState.getWriter().endRecord (info.sRecordId); + writer.startRecord (info.sRecordId); + info.save (writer); + writer.endRecord (info.sRecordId); } } } @@ -269,36 +257,35 @@ int CSMDoc::WriteCellCollectionStage::setup() void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& cell = - mDocument.getData().getCells().getRecord (stage); + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& cell = mDocument.getData().getCells().getRecord (stage); std::map >::const_iterator references = mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); - if (cell.mState==CSMWorld::RecordBase::State_Modified || - cell.mState==CSMWorld::RecordBase::State_ModifiedOnly || + if (cell.isModified() || + cell.mState == CSMWorld::RecordBase::State_Deleted || references!=mState.getSubRecords().end()) { - bool interior = cell.get().mId.substr (0, 1)!="#"; + CSMWorld::Cell cellRecord = cell.get(); + bool interior = cellRecord.mId.substr (0, 1)!="#"; // write cell data - mState.getWriter().startRecord (cell.mModified.sRecordId); - - mState.getWriter().writeHNOCString ("NAME", cell.get().mName); - - ESM::Cell cell2 = cell.get(); + writer.startRecord (cellRecord.sRecordId); if (interior) - cell2.mData.mFlags |= ESM::Cell::Interior; + cellRecord.mData.mFlags |= ESM::Cell::Interior; else { - cell2.mData.mFlags &= ~ESM::Cell::Interior; + cellRecord.mData.mFlags &= ~ESM::Cell::Interior; - std::istringstream stream (cell.get().mId.c_str()); + std::istringstream stream (cellRecord.mId.c_str()); char ignore; - stream >> ignore >> cell2.mData.mX >> cell2.mData.mY; + stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY; } - cell2.save (mState.getWriter()); + + cellRecord.mIsDeleted = (cell.mState == CSMWorld::RecordBase::State_Deleted); + cellRecord.save (writer); // write references if (references!=mState.getSubRecords().end()) @@ -309,24 +296,25 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) const CSMWorld::Record& ref = mDocument.getData().getReferences().getRecord (*iter); - if (ref.mState==CSMWorld::RecordBase::State_Modified || - ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted) { + CSMWorld::CellRef refRecord = ref.get(); + // recalculate the ref's cell location std::ostringstream stream; if (!interior) { - std::pair index = ref.get().getCellIndex(); + std::pair index = refRecord.getCellIndex(); stream << "#" << index.first << " " << index.second; } // An empty mOriginalCell is meant to indicate that it is the same as // the current cell. It is possible that a moved ref is moved again. - if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell) + if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != stream.str() && !interior) { ESM::MovedCellRef moved; - moved.mRefNum = ref.get().mRefNum; + moved.mRefNum = refRecord.mRefNum; // Need to fill mTarget with the ref's new position. std::istringstream istream (stream.str().c_str()); @@ -334,24 +322,17 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) char ignore; istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; - ref.get().mRefNum.save (mState.getWriter(), false, "MVRF"); - mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); + refRecord.mRefNum.save (writer, false, "MVRF"); + writer.writeHNT ("CNDT", moved.mTarget, 8); } - ref.get().save (mState.getWriter()); - } - else if (ref.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + refRecord.mIsDeleted = (ref.mState == CSMWorld::RecordBase::State_Deleted); + refRecord.save (writer); } } } - mState.getWriter().endRecord (cell.mModified.sRecordId); - } - else if (cell.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + writer.endRecord (cellRecord.sRecordId); } } @@ -368,11 +349,11 @@ int CSMDoc::WritePathgridCollectionStage::setup() void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& pathgrid = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& pathgrid = mDocument.getData().getPathgrids().getRecord (stage); - if (pathgrid.mState==CSMWorld::RecordBase::State_Modified || - pathgrid.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (pathgrid.isModified() || pathgrid.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Pathgrid record = pathgrid.get(); @@ -385,15 +366,10 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message else record.mCell = record.mId; - mState.getWriter().startRecord (record.sRecordId); - - record.save (mState.getWriter()); - - mState.getWriter().endRecord (record.sRecordId); - } - else if (pathgrid.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + record.mIsDeleted = (pathgrid.mState == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } @@ -410,25 +386,18 @@ int CSMDoc::WriteLandCollectionStage::setup() void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& land = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& land = mDocument.getData().getLand().getRecord (stage); - if (land.mState==CSMWorld::RecordBase::State_Modified || - land.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Land record = land.get(); - mState.getWriter().startRecord (record.mLand->sRecordId); - - record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); - - mState.getWriter().endRecord (record.mLand->sRecordId); - } - else if (land.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + record.mLand->mIsDeleted = (land.mState == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.mLand->sRecordId); + record.mLand->save (writer); + writer.endRecord (record.mLand->sRecordId); } } @@ -445,23 +414,18 @@ int CSMDoc::WriteLandTextureCollectionStage::setup() void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) { - const CSMWorld::Record& landTexture = + ESM::ESMWriter& writer = mState.getWriter(); + const CSMWorld::Record& landTexture = mDocument.getData().getLandTextures().getRecord (stage); - if (landTexture.mState==CSMWorld::RecordBase::State_Modified || - landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::LandTexture record = landTexture.get(); + record.mIsDeleted = (landTexture.mState == CSMWorld::RecordBase::State_Deleted); - mState.getWriter().startRecord (record.sRecordId); - - record.save (mState.getWriter()); - - mState.getWriter().endRecord (record.sRecordId); - } - else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 188f22f961..9dbb5bee33 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -100,26 +100,18 @@ namespace CSMDoc if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope) return; + ESM::ESMWriter& writer = mState.getWriter(); CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; + CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); - if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + if (state == CSMWorld::RecordBase::State_Modified || + state == CSMWorld::RecordBase::State_ModifiedOnly || + state == CSMWorld::RecordBase::State_Deleted) { - // FIXME: A quick Workaround to support records which should not write - // NAME, including SKIL, MGEF and SCPT. If there are many more - // idcollection records that doesn't use NAME then a more generic - // solution may be required. - uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; - mState.getWriter().startRecord (name); - - if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); - mCollection.getRecord (stage).mModified.save (mState.getWriter()); - mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); - } - else if (state==CSMWorld::RecordBase::State_Deleted) - { - /// \todo write record with delete flag + CSMWorld::setRecordDeleted (record, state == CSMWorld::RecordBase::State_Deleted); + writer.startRecord (record.sRecordId); + record.save (writer); + writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index b0571bbed1..16f5ce51f4 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -43,6 +43,12 @@ namespace CSMWorld template > class Collection : public CollectionBase { + public: + + typedef ESXRecordT ESXRecord; + + private: + std::vector > mRecords; std::map mIndex; std::vector *> mColumns; diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 87f5090fe4..7563c4cfd9 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -43,3 +43,27 @@ bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) { return false; } + +template<> +void CSMWorld::setRecordDeleted(CSMWorld::Land &land, bool isDeleted) +{ + land.mLand->mIsDeleted = isDeleted; +} + +template<> +void CSMWorld::setRecordDeleted(ESM::GameSetting &setting, bool isDeleted) +{ + // GameSetting doesn't have a Deleted flag +} + +template<> +void CSMWorld::setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted) +{ + // MagicEffect doesn't have a Deleted flag +} + +template<> +void CSMWorld::setRecordDeleted(ESM::Skill &skill, bool isDeleted) +{ + // Skill doesn't have a Deleted flag +} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index c43a8b6ca2..8e39cd705e 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -177,6 +177,22 @@ namespace CSMWorld bool isRecordDeleted(const ESM::MagicEffect &effect); template<> bool isRecordDeleted(const ESM::Skill &skill); + + // ... and also a separate method for setting the deleted flag of a record + template + void setRecordDeleted(ESXRecordT &record, bool isDeleted = false) + { + record.mIsDeleted = isDeleted; + } + + template<> + void setRecordDeleted(Land &land, bool isDeleted); + template<> + void setRecordDeleted(ESM::GameSetting &setting, bool isDeleted); + template<> + void setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted); + template<> + void setRecordDeleted(ESM::Skill &skill, bool isDeleted); } #endif From ede4bfcf52a77f371058e0fdce655534d6879056 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 14:55:54 +0300 Subject: [PATCH 0781/1812] Rework EsmTool code. Remove explicit NAME handling --- apps/esmtool/esmtool.cpp | 97 +++++++++++++++++----------------------- apps/esmtool/record.cpp | 75 ++++++++++++++++++++++++++++++- apps/esmtool/record.hpp | 18 +++++--- 3 files changed, 126 insertions(+), 64 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 5b6e50b965..c2507ccdc4 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -251,8 +251,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) ESM::CellRef ref; if(!quiet) std::cout << " References:\n"; - bool deleted = false; - while(cell.getNextRef(esm, ref, deleted)) + while(cell.getNextRef(esm, ref)) { if (save) { info.data.mCellRefs[&cell].push_back(ref); @@ -270,7 +269,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; - std::cout << " Deleted: " << deleted << std::endl; + std::cout << " Deleted: " << ref.mIsDeleted << std::endl; if (!ref.mKey.empty()) std::cout << " Key: '" << ref.mKey << "'" << std::endl; } @@ -352,30 +351,9 @@ int load(Arguments& info) uint32_t flags; esm.getRecHeader(flags); - // Is the user interested in this record type? - bool interested = true; - if (!info.types.empty()) - { - std::vector::iterator match; - match = std::find(info.types.begin(), info.types.end(), - n.toString()); - if (match == info.types.end()) interested = false; - } - - std::string id = esm.getHNOString("NAME"); - if (id.empty()) - id = esm.getHNOString("INAM"); - - if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, id)) - interested = false; - - if(!quiet && interested) - std::cout << "\nRecord: " << n.toString() - << " '" << id << "'\n"; - EsmTool::RecordBase *record = EsmTool::RecordBase::create(n); - - if (record == 0) { + if (record == 0) + { if (std::find(skipped.begin(), skipped.end(), n.val) == skipped.end()) { std::cout << "Skipping " << n.toString() << " records." << std::endl; @@ -385,28 +363,46 @@ int load(Arguments& info) esm.skipRecord(); if (quiet) break; std::cout << " Skipping\n"; - } else { - if (record->getType().val == ESM::REC_GMST) { - // preset id for GameSetting record - record->cast()->get().mId = id; - } - record->setId(id); - record->setFlags((int) flags); - record->setPrintPlain(info.plain_given); - record->load(esm); - if (!quiet && interested) record->print(); - if (record->getType().val == ESM::REC_CELL && loadCells && interested) { - loadCell(record->cast()->get(), esm, info); - } - - if (save) { - info.data.mRecords.push_back(record); - } else { - delete record; - } - ++info.data.mRecordStats[n.val]; + continue; } + + record->setFlags(static_cast(flags)); + record->setPrintPlain(info.plain_given); + record->load(esm); + + // Is the user interested in this record type? + bool interested = true; + if (!info.types.empty()) + { + std::vector::iterator match; + match = std::find(info.types.begin(), info.types.end(), n.toString()); + if (match == info.types.end()) interested = false; + } + + if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, record->getId())) + interested = false; + + if(!quiet && interested) + { + std::cout << "\nRecord: " << n.toString() << " '" << record->getId() << "'\n"; + record->print(); + } + + if (record->getType().val == ESM::REC_CELL && loadCells && interested) + { + loadCell(record->cast()->get(), esm, info); + } + + if (save) + { + info.data.mRecords.push_back(record); + } + else + { + delete record; + } + ++info.data.mRecordStats[n.val]; } } catch(std::exception &e) { @@ -493,20 +489,11 @@ int clone(Arguments& info) for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it) { EsmTool::RecordBase *record = *it; - name.val = record->getType().val; esm.startRecord(name.toString(), record->getFlags()); - // TODO wrap this with std::set - if (ESMData::sLabeledRec.count(name.val) > 0) { - esm.writeHNCString("NAME", record->getId()); - } else { - esm.writeHNOString("NAME", record->getId()); - } - record->save(esm); - if (name.val == ESM::REC_CELL) { ESM::Cell *ptr = &record->cast()->get(); if (!info.data.mCellRefs[ptr].empty()) { diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bbf..a033182626 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -405,6 +405,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Script: " << mData.mScript << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -419,6 +420,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -447,6 +449,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -461,6 +464,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -474,6 +478,7 @@ void Record::print() std::cout << " Part: " << meshPartLabel(mData.mData.mPart) << " (" << (int)mData.mData.mPart << ")" << std::endl; std::cout << " Vampire: " << (int)mData.mData.mVampire << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -502,6 +507,7 @@ void Record::print() { std::cout << " Text: [skipped]" << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -513,6 +519,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit) std::cout << " Power: " << *pit << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -541,6 +548,7 @@ void Record::print() std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } @@ -563,6 +571,7 @@ void Record::print() for (int i = 0; i != 5; i++) std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -589,6 +598,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -604,6 +614,7 @@ void Record::print() for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -670,6 +681,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -677,6 +689,7 @@ void Record::print() { std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? @@ -693,6 +706,7 @@ void Record::print() std::cout << " Script: " << mData.mScript << std::endl; std::cout << " OpenSound: " << mData.mOpenSound << std::endl; std::cout << " CloseSound: " << mData.mCloseSound << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -704,6 +718,7 @@ void Record::print() std::cout << " Charge: " << mData.mData.mCharge << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutocalc << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -737,12 +752,14 @@ void Record::print() std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit) std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> void Record::print() { std::cout << " " << mData.mValue << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -809,6 +826,7 @@ void Record::print() std::cout << " Result Script: [skipped]" << std::endl; } } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -832,6 +850,7 @@ void Record::print() std::cout << " Attribute: " << attributeLabel(mData.mData.mAttributes[i]) << " (" << mData.mData.mAttributes[i] << ")" << std::endl; } + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -854,6 +873,7 @@ void Record::print() std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; } if (!wasLoaded) mData.unloadData(); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -866,6 +886,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -878,6 +899,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -898,6 +920,7 @@ void Record::print() std::cout << " Duration: " << mData.mData.mTime << std::endl; std::cout << " Radius: " << mData.mData.mRadius << std::endl; std::cout << " Color: " << mData.mData.mColor << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -912,6 +935,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -926,6 +950,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -940,6 +965,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -948,6 +974,7 @@ void Record::print() std::cout << " Id: " << mData.mId << std::endl; std::cout << " Index: " << mData.mIndex << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -998,6 +1025,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Is Key: " << mData.mData.mIsKey << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1083,6 +1111,8 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1117,6 +1147,8 @@ void Record::print() std::cout << " BAD POINT IN EDGE!" << std::endl; i++; } + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1157,6 +1189,8 @@ void Record::print() std::vector::iterator sit; for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit) std::cout << " Power: " << *sit << std::endl; + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1216,6 +1250,8 @@ void Record::print() { std::cout << " Script: [skipped]" << std::endl; } + + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1239,6 +1275,7 @@ void Record::print() std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Type: " << soundTypeLabel(mData.mType) << " (" << mData.mType << ")" << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1249,6 +1286,7 @@ void Record::print() if (mData.mData.mMinRange != 0 && mData.mData.mMaxRange != 0) std::cout << " Range: " << (int)mData.mData.mMinRange << " - " << (int)mData.mData.mMaxRange << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1260,13 +1298,15 @@ void Record::print() std::cout << " Flags: " << spellFlags(mData.mData.mFlags) << std::endl; std::cout << " Cost: " << mData.mData.mCost << std::endl; printEffectList(mData.mEffects); + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> void Record::print() { - std::cout << "Start Script: " << mData.mId << std::endl; - std::cout << "Start Data: " << mData.mData << std::endl; + std::cout << " Start Script: " << mData.mId << std::endl; + std::cout << " Start Data: " << mData.mData << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; } template<> @@ -1307,6 +1347,37 @@ void Record::print() if (mData.mData.mThrust[0] != 0 && mData.mData.mThrust[1] != 0) std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" << (int)mData.mData.mThrust[1] << std::endl; + std::cout << " Deleted: " << mData.mIsDeleted << std::endl; +} + +template<> +std::string Record::getId() const +{ + return mData.mName; +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Land record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for MagicEffect record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Pathgrid record +} + +template<> +std::string Record::getId() const +{ + return ""; // No ID for Skill record } } // end namespace diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c1b90ac2bc..a10fda40b0 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -32,13 +32,7 @@ namespace EsmTool virtual ~RecordBase() {} - const std::string &getId() const { - return mId; - } - - void setId(const std::string &id) { - mId = id; - } + virtual std::string getId() const = 0; uint32_t getFlags() const { return mFlags; @@ -75,6 +69,10 @@ namespace EsmTool T mData; public: + std::string getId() const { + return mData.mId; + } + T &get() { return mData; } @@ -89,6 +87,12 @@ namespace EsmTool void print(); }; + + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; + template<> std::string Record::getId() const; template<> void Record::print(); template<> void Record::print(); From 6b21da7f8e6b50de71047248c36d4ee9ec51751e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 16:07:56 +0300 Subject: [PATCH 0782/1812] Rework ESS importer code. Remove explicit NAME handling for ESM records --- apps/essimporter/converter.cpp | 6 ++---- apps/essimporter/converter.hpp | 36 +++++++++++++--------------------- apps/essimporter/importer.cpp | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2ef10ee34b..9827531345 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -158,8 +158,6 @@ namespace ESSImport void ConvertCell::read(ESM::ESMReader &esm) { ESM::Cell cell; - std::string id = esm.getHNString("NAME"); - cell.mName = id; cell.load(esm, false); // I wonder what 0x40 does? @@ -169,7 +167,7 @@ namespace ESSImport } // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position - if (id == mContext->mPlayerCellName) + if (cell.mName == mContext->mPlayerCellName) { mContext->mPlayer.mCellId = cell.getCellId(); } @@ -277,7 +275,7 @@ namespace ESSImport if (cell.isExterior()) mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell; else - mIntCells[id] = newcell; + mIntCells[cell.mName] = newcell; } void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index fb8fb8c9fd..3bb5d2eaed 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -78,10 +78,9 @@ public: virtual void read(ESM::ESMReader& esm) { - std::string id = esm.getHNString("NAME"); T record; record.load(esm); - mRecords[id] = record; + mRecords[record.mId] = record; } virtual void write(ESM::ESMWriter& esm) @@ -89,7 +88,6 @@ public: for (typename std::map::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it) { esm.startRecord(T::sRecordId); - esm.writeHNString("NAME", it->first); it->second.save(esm); esm.endRecord(T::sRecordId); } @@ -105,14 +103,13 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::NPC npc; - std::string id = esm.getHNString("NAME"); npc.load(esm); - if (id != "player") + if (npc.mId != "player") { // Handles changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. - mContext->mNpcs[Misc::StringUtils::lowerCase(id)] = npc; + mContext->mNpcs[Misc::StringUtils::lowerCase(npc.mId)] = npc; } else { @@ -142,9 +139,8 @@ public: { // See comment in ConvertNPC ESM::Creature creature; - std::string id = esm.getHNString("NAME"); creature.load(esm); - mContext->mCreatures[Misc::StringUtils::lowerCase(id)] = creature; + mContext->mCreatures[Misc::StringUtils::lowerCase(creature.mId)] = creature; } }; @@ -157,18 +153,17 @@ class ConvertGlobal : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Global global; global.load(esm); - if (Misc::StringUtils::ciEqual(id, "gamehour")) + if (Misc::StringUtils::ciEqual(global.mId, "gamehour")) mContext->mHour = global.mValue.getFloat(); - if (Misc::StringUtils::ciEqual(id, "day")) + if (Misc::StringUtils::ciEqual(global.mId, "day")) mContext->mDay = global.mValue.getInteger(); - if (Misc::StringUtils::ciEqual(id, "month")) + if (Misc::StringUtils::ciEqual(global.mId, "month")) mContext->mMonth = global.mValue.getInteger(); - if (Misc::StringUtils::ciEqual(id, "year")) + if (Misc::StringUtils::ciEqual(global.mId, "year")) mContext->mYear = global.mValue.getInteger(); - mRecords[id] = global; + mRecords[global.mId] = global; } }; @@ -177,14 +172,13 @@ class ConvertClass : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Class class_; class_.load(esm); - if (id == "NEWCLASSID_CHARGEN") + if (class_.mId == "NEWCLASSID_CHARGEN") mContext->mCustomPlayerClassName = class_.mName; - mRecords[id] = class_; + mRecords[class_.mId] = class_; } }; @@ -193,13 +187,12 @@ class ConvertBook : public DefaultConverter public: virtual void read(ESM::ESMReader &esm) { - std::string id = esm.getHNString("NAME"); ESM::Book book; book.load(esm); if (book.mData.mSkillID == -1) - mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(id)); + mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId)); - mRecords[id] = book; + mRecords[book.mId] = book; } }; @@ -371,11 +364,10 @@ class ConvertFACT : public Converter public: virtual void read(ESM::ESMReader& esm) { - std::string id = esm.getHNString("NAME"); ESM::Faction faction; faction.load(esm); + std::string id = Misc::StringUtils::toLower(faction.mId); - Misc::StringUtils::toLower(id); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) { std::string faction2 = Misc::StringUtils::lowerCase(it->first); diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 624241039d..4fbf062170 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -394,7 +394,7 @@ namespace ESSImport } writer.startRecord(ESM::REC_NPC_); - writer.writeHNString("NAME", "player"); + context.mPlayerBase.mId = "player"; context.mPlayerBase.save(writer); writer.endRecord(ESM::REC_NPC_); From 7924ecef3e640f68ddd3ddf5d59bff97713af3b5 Mon Sep 17 00:00:00 2001 From: Koncord Date: Sun, 19 Jul 2015 23:37:20 +0900 Subject: [PATCH 0783/1812] Fix definition conflict --- components/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 85e61cee51..cf0c83fbda 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -201,7 +201,10 @@ if (GIT_CHECKOUT) endif (GIT_CHECKOUT) if (WIN32) -target_link_libraries(components shlwapi) + target_link_libraries(components shlwapi) + if(MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOGDI") + endif(MINGW) endif() # Fix for not visible pthreads functions for linker with glibc 2.15 From a14a3c82ded2f4d2702abaeefd74905b35e21e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sun, 19 Jul 2015 19:52:50 +0200 Subject: [PATCH 0784/1812] added description of new syntax to the onRetrieveTag function comment --- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index af82c27c0c..336a2a19a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -495,6 +495,7 @@ namespace MWGui * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: * #{GMSTName}: retrieves String value of the GMST called GMSTName + * #{setting=CATEGORY_NAME,SETTING_NAME}: retrieves String value of SETTING_NAME under category CATEGORY_NAME from settings.cfg * #{sCell=CellID}: retrieves translated name of the given CellID (used only by some Morrowind localisations, in others cell ID is == cell name) * #{fontcolour=FontColourName}: retrieves the value of the fallback setting "FontColor_color_" from openmw.cfg, * in the format "r g b a", float values in range 0-1. Useful for "Colour" and "TextColour" properties in skins. From f5745749a6e7875c487ac417dead00446af805c2 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 22:50:42 +0300 Subject: [PATCH 0785/1812] Remove include file from loaddial.cpp --- components/esm/loaddial.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index c517dc7222..74a708805c 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -2,8 +2,6 @@ #include -#include - #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" From 1e8182220ae7c14de13ab634c82f2b14444c0e69 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 23:27:51 +0300 Subject: [PATCH 0786/1812] Fix build errors & warnings --- apps/opencs/model/doc/savingstages.hpp | 2 +- apps/opencs/model/world/idcollection.hpp | 8 ++++---- components/esm/cellref.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 9dbb5bee33..a7d9704b02 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -102,7 +102,7 @@ namespace CSMDoc ESM::ESMWriter& writer = mState.getWriter(); CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; - CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); + typename CollectionT::ESXRecord record = mCollection.getRecord (stage).get(); if (state == CSMWorld::RecordBase::State_Modified || state == CSMWorld::RecordBase::State_ModifiedOnly || diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4acfdc4744..9d3ec990ef 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -46,7 +46,7 @@ namespace CSMWorld loadRecord (record, reader); std::string id = IdAccessorT().getId (record); - int index = searchId (id); + int index = this->searchId (id); if (isRecordDeleted(record)) { @@ -60,13 +60,13 @@ namespace CSMWorld if (base) { - removeRows (index, 1); + this->removeRows (index, 1); return -1; } - Record baseRecord = getRecord (index); + Record baseRecord = this->getRecord (index); baseRecord.mState = RecordBase::State_Deleted; - setRecord (index, baseRecord); + this->setRecord (index, baseRecord); return index; } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c6fb899b31..bcf3de8076 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -7,10 +7,12 @@ ESM::CellRef::CellRef() : mScale(1.0f), mFactionRank(-2), - mEnchantmentCharge(-1), - mGoldValue(1), mChargeInt(-1), + mEnchantmentCharge(-1.0f), + mGoldValue(1), + mTeleport(false), mLockLevel(0), + mReferenceBlocked(-1), mIsDeleted(false) {} From 75e50235904d1394f95269d3a98db950bdce0ec4 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:05:52 +0900 Subject: [PATCH 0787/1812] fix code duplication --- apps/openmw/mwclass/misc.cpp | 20 ++++++++------------ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 8 +++----- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b7c39b50a7..0c80209f29 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -25,20 +25,16 @@ #include -namespace -{ -bool isGold (const MWWorld::Ptr& ptr) -{ - return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); -} -} - namespace MWClass { + bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const + { + return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); + } std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 66699f9df7..394c9ffc01 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -62,6 +62,8 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool isKey (const MWWorld::Ptr &ptr) const; + + virtual bool isGold (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d4aadc6c7a..26fcc33cb7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,6 +13,8 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwclass/misc.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -298,11 +300,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100")) + if(MWClass::Miscellaneous().isGold(ptr)) { int realCount = count * ptr.getClass().getValue(ptr); From aefcd1ad07181b92d1daaebdb2e504efb42d81ad Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:20:28 +0900 Subject: [PATCH 0788/1812] Fix "additem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 26fcc33cb7..9d4ec552e8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -302,20 +302,18 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (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(MWClass::Miscellaneous().isGold(ptr)) { - int realCount = count * ptr.getClass().getValue(ptr); - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + realCount); + iter->getRefData().setCount(iter->getRefData().getCount() + count); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); - return addNewStack(ref.getPtr(), realCount); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); + return addNewStack(ref.getPtr(), count); } // determine whether to stack or not From 9485aa5e44dfb1cec74f2d36156fbd7e5b3251ed Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 09:53:08 +0900 Subject: [PATCH 0789/1812] Fix "removeitem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 9d4ec552e8..c21fdd6628 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -362,8 +362,18 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; + std::string id = itemId; + + if(Misc::StringUtils::ciEqual(itemId, "gold_005") + || Misc::StringUtils::ciEqual(itemId, "gold_010") + || Misc::StringUtils::ciEqual(itemId, "gold_025") + || Misc::StringUtils::ciEqual(itemId, "gold_100")) + { + id = MWWorld::ContainerStore::sGoldId; + } + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From a24df8cb66e68eca2b665d25121d7cfb5989fb5b Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:43:58 +0900 Subject: [PATCH 0790/1812] Revert addImp() and remove() add isGold() in MWWorld::Class --- apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 22 +++++++--------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7ef1735550..3f091380f2 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -284,6 +284,8 @@ namespace MWWorld virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual bool isGold(const MWWorld::Ptr& ptr) const { return false; }; + /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c21fdd6628..f7ede6c984 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -300,20 +300,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if(MWClass::Miscellaneous().isGold(ptr)) + if(ptr.getClass().isGold(ptr)) { + int realCount = count * ptr.getClass().getValue(ptr); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + count); + iter->getRefData().setCount(iter->getRefData().getCount() + realCount); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); - return addNewStack(ref.getPtr(), count); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); + return addNewStack(ref.getPtr(), realCount); } // determine whether to stack or not @@ -362,18 +364,8 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; - std::string id = itemId; - - if(Misc::StringUtils::ciEqual(itemId, "gold_005") - || Misc::StringUtils::ciEqual(itemId, "gold_010") - || Misc::StringUtils::ciEqual(itemId, "gold_025") - || Misc::StringUtils::ciEqual(itemId, "gold_100")) - { - id = MWWorld::ContainerStore::sGoldId; - } - for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From 7a86c8d8b6e880cd1212cc07bcd40efa6d098f42 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:48:19 +0900 Subject: [PATCH 0791/1812] Fix OpAddItem, OpGetItemCount and OpRemoveItem. --- apps/openmw/mwscript/containerextensions.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 70475d8e2f..ac9bbef663 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,6 +56,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); // Spawn a messagebox (only for items added to player's inventory and if player is talking to someone) @@ -91,6 +97,12 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); runtime.push (store.count(item)); @@ -119,6 +131,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); std::string itemName; From 2a4d35b98c0ad0fcab06f25bd8ba113dcf87ab41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 20 Jul 2015 18:20:57 +1200 Subject: [PATCH 0792/1812] fixed "comma at end of enumerator list" warning. --- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index df389a34ef..d1dab3f50e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -68,7 +68,7 @@ namespace MWMechanics Wander_ChooseAction, Wander_IdleNow, Wander_MoveNow, - Wander_Walking, + Wander_Walking }; private: // NOTE: mDistance and mDuration must be set already From 6c3c85f0d4f0ebead4fbf0856e98ace2b2b888e0 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 21:53:20 +0900 Subject: [PATCH 0793/1812] Fix indent Remove misc.hpp in containerstore.cpp --- apps/openmw/mwscript/containerextensions.cpp | 8 ++++---- apps/openmw/mwworld/containerstore.cpp | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ac9bbef663..ba18d8e37c 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -132,10 +132,10 @@ namespace MWScript return; if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) - item = "gold_001"; + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index f7ede6c984..3a7c023327 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,8 +13,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" -#include "../mwclass/misc.hpp" - #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" From 3c3bd7976ecd5a43c9eddf1fb45e3a25967ca7d3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 22 Jul 2015 08:36:06 +0200 Subject: [PATCH 0794/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2bd96e3a16..def0b2b896 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -60,6 +60,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + Koncord Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 4a16eba716d6795bb9aadc492c4417d1a05828ef Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 20 Jul 2015 17:23:14 +0300 Subject: [PATCH 0795/1812] Make deleted flag a parameter of load/save methods (instead of a record member) in ESM records --- components/esm/cellref.cpp | 93 +++++++++------------- components/esm/cellref.hpp | 12 ++- components/esm/debugprofile.cpp | 24 +++--- components/esm/debugprofile.hpp | 8 +- components/esm/esmreader.cpp | 1 + components/esm/filter.cpp | 21 ++--- components/esm/filter.hpp | 8 +- components/esm/loadacti.cpp | 24 +++--- components/esm/loadacti.hpp | 8 +- components/esm/loadalch.cpp | 27 +++---- components/esm/loadalch.hpp | 8 +- components/esm/loadappa.cpp | 26 +++--- components/esm/loadappa.hpp | 8 +- components/esm/loadarmo.cpp | 27 +++---- components/esm/loadarmo.hpp | 8 +- components/esm/loadbody.cpp | 27 +++---- components/esm/loadbody.hpp | 8 +- components/esm/loadbook.cpp | 26 +++--- components/esm/loadbook.hpp | 8 +- components/esm/loadbsgn.cpp | 25 +++--- components/esm/loadbsgn.hpp | 8 +- components/esm/loadcell.cpp | 136 +++++++++++++++++++------------- components/esm/loadcell.hpp | 20 ++--- components/esm/loadclas.cpp | 27 +++---- components/esm/loadclas.hpp | 8 +- components/esm/loadclot.cpp | 27 +++---- components/esm/loadclot.hpp | 8 +- components/esm/loadcont.cpp | 31 +++----- components/esm/loadcont.hpp | 8 +- components/esm/loadcrea.cpp | 31 +++----- components/esm/loadcrea.hpp | 8 +- components/esm/loaddial.cpp | 64 +++++++-------- components/esm/loaddial.hpp | 16 ++-- components/esm/loaddoor.cpp | 24 +++--- components/esm/loaddoor.hpp | 8 +- components/esm/loadench.cpp | 27 +++---- components/esm/loadench.hpp | 8 +- components/esm/loadfact.cpp | 28 +++---- components/esm/loadfact.hpp | 8 +- components/esm/loadglob.cpp | 16 ++-- components/esm/loadglob.hpp | 8 +- components/esm/loadgmst.cpp | 6 +- components/esm/loadgmst.hpp | 4 +- components/esm/loadinfo.cpp | 32 +++----- components/esm/loadinfo.hpp | 10 +-- components/esm/loadingr.cpp | 27 +++---- components/esm/loadingr.hpp | 8 +- components/esm/loadland.cpp | 109 ++++++++++++++----------- components/esm/loadland.hpp | 8 +- components/esm/loadlevlist.cpp | 43 +++++----- components/esm/loadlevlist.hpp | 8 +- components/esm/loadligh.cpp | 26 +++--- components/esm/loadligh.hpp | 8 +- components/esm/loadlock.cpp | 26 +++--- components/esm/loadlock.hpp | 8 +- components/esm/loadltex.cpp | 24 +++--- components/esm/loadltex.hpp | 8 +- components/esm/loadmgef.cpp | 9 ++- components/esm/loadmgef.hpp | 4 +- components/esm/loadmisc.cpp | 26 +++--- components/esm/loadmisc.hpp | 8 +- components/esm/loadnpc.cpp | 31 +++----- components/esm/loadnpc.hpp | 8 +- components/esm/loadpgrd.cpp | 18 ++--- components/esm/loadpgrd.hpp | 8 +- components/esm/loadprob.cpp | 26 +++--- components/esm/loadprob.hpp | 8 +- components/esm/loadrace.cpp | 26 +++--- components/esm/loadrace.hpp | 8 +- components/esm/loadregn.cpp | 24 ++---- components/esm/loadregn.hpp | 8 +- components/esm/loadrepa.cpp | 26 +++--- components/esm/loadrepa.hpp | 8 +- components/esm/loadscpt.cpp | 26 +++--- components/esm/loadscpt.hpp | 8 +- components/esm/loadskil.cpp | 9 ++- components/esm/loadskil.hpp | 4 +- components/esm/loadsndg.cpp | 27 +++---- components/esm/loadsndg.hpp | 8 +- components/esm/loadsoun.cpp | 27 +++---- components/esm/loadsoun.hpp | 8 +- components/esm/loadspel.cpp | 28 +++---- components/esm/loadspel.hpp | 8 +- components/esm/loadsscr.cpp | 18 ++--- components/esm/loadsscr.hpp | 8 +- components/esm/loadstat.cpp | 24 +++--- components/esm/loadstat.hpp | 8 +- components/esm/loadweap.cpp | 27 +++---- components/esm/loadweap.hpp | 8 +- components/esm/objectstate.cpp | 3 +- 90 files changed, 715 insertions(+), 1051 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index bcf3de8076..9a0c8f1cc6 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -4,18 +4,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -ESM::CellRef::CellRef() - : mScale(1.0f), - mFactionRank(-2), - mChargeInt(-1), - mEnchantmentCharge(-1.0f), - mGoldValue(1), - mTeleport(false), - mLockLevel(0), - mReferenceBlocked(-1), - mIsDeleted(false) -{} - void ESM::RefNum::load (ESMReader& esm, bool wide) { if (wide) @@ -37,10 +25,37 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +void ESM::CellRef::clearData() +{ + mScale = 1; + mOwner.clear(); + mGlobalVariable.clear(); + mSoul.clear(); + mFaction.clear(); + mFactionRank = -2; + mChargeInt = -1; + mEnchantmentCharge = -1; + mGoldValue = 0; + mDestCell.clear(); + mLockLevel = 0; + mKey.clear(); + mTrap.clear(); + mReferenceBlocked = -1; + mTeleport = false; + + for (int i=0; i<3; ++i) + { + mDoorDest.pos[i] = 0; + mDoorDest.rot[i] = 0; + mPos.pos[i] = 0; + mPos.rot[i] = 0; + } +} + +void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, bool wideRefNum) { loadId(esm, wideRefNum); - loadData(esm); + loadData(esm, isDeleted); } void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) @@ -55,27 +70,19 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); - mIsDeleted = false; } -void ESM::CellRef::loadData(ESMReader &esm) +void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) { - mScale = 1.0f; - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 1; - mLockLevel = 0; - mReferenceBlocked = -1; - mTeleport = false; - mIsDeleted = false; + isDeleted = false; + + clearData(); bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'U','N','A','M'>::value: esm.getHT(mReferenceBlocked); @@ -131,7 +138,7 @@ void ESM::CellRef::loadData(ESMReader &esm) break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.cacheSubName(); @@ -141,7 +148,7 @@ void ESM::CellRef::loadData(ESMReader &esm) } } -void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const +void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool isDeleted) const { mRefNum.save (esm, wideRefNum); @@ -192,7 +199,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (!inInventory) esm.writeHNT("DATA", mPos, 24); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -202,31 +209,7 @@ void ESM::CellRef::blank() { mRefNum.unset(); mRefID.clear(); - mScale = 1; - mOwner.clear(); - mGlobalVariable.clear(); - mSoul.clear(); - mFaction.clear(); - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 0; - mDestCell.clear(); - mLockLevel = 0; - mKey.clear(); - mTrap.clear(); - mReferenceBlocked = -1; - mTeleport = false; - - for (int i=0; i<3; ++i) - { - mDoorDest.pos[i] = 0; - mDoorDest.rot[i] = 0; - mPos.pos[i] = 0; - mPos.rot[i] = 0; - } - - mIsDeleted = false; + clearData(); } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 553dbaae32..a9edd291e0 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -33,6 +33,8 @@ namespace ESM class CellRef { + void clearData(); + public: // Reference number @@ -99,19 +101,15 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; - bool mIsDeleted; - - CellRef(); - /// Calls loadId and loadData - void load (ESMReader& esm, bool wideRefNum = false); + void load (ESMReader& esm, bool &isDeleted, bool wideRefNum = false); void loadId (ESMReader& esm, bool wideRefNum = false); /// Implicitly called by load - void loadData (ESMReader& esm); + void loadData (ESMReader& esm, bool &isDeleted); - void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false) const; + void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index d1e27debcf..16fc90eece 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -7,27 +7,18 @@ unsigned int ESM::DebugProfile::sRecordId = REC_DBGP; -ESM::DebugProfile::DebugProfile() - : mIsDeleted(false) -{} - -void ESM::DebugProfile::load (ESMReader& esm) +void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; @@ -37,6 +28,10 @@ void ESM::DebugProfile::load (ESMReader& esm) case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -44,11 +39,11 @@ void ESM::DebugProfile::load (ESMReader& esm) } } -void ESM::DebugProfile::save (ESMWriter& esm) const +void ESM::DebugProfile::save (ESMWriter& esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -64,5 +59,4 @@ void ESM::DebugProfile::blank() mDescription.clear(); mScriptText.clear(); mFlags = 0; - mIsDeleted = false; } diff --git a/components/esm/debugprofile.hpp b/components/esm/debugprofile.hpp index 1709136f51..c056750a88 100644 --- a/components/esm/debugprofile.hpp +++ b/components/esm/debugprofile.hpp @@ -27,12 +27,8 @@ namespace ESM unsigned int mFlags; - bool mIsDeleted; - - DebugProfile(); - - void load (ESMReader& esm); - void save (ESMWriter& esm) const; + void load (ESMReader& esm, bool &isDeleted); + void save (ESMWriter& esm, bool isDeleted = false) const; /// Set record to default state (does not touch the ID). void blank(); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 1bf176842f..6ef14a70e0 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -281,6 +281,7 @@ void ESMReader::skipRecord() { skip(mCtx.leftRec); mCtx.leftRec = 0; + mCtx.subCached = false; } void ESMReader::getRecHeader(uint32_t &flags) diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index 57cb59454a..b485169f26 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -7,13 +7,9 @@ unsigned int ESM::Filter::sRecordId = REC_FILT; -ESM::Filter::Filter() - : mIsDeleted(false) -{} - -void ESM::Filter::load (ESMReader& esm) +void ESM::Filter::load (ESMReader& esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; while (esm.hasMoreSubs()) { @@ -24,16 +20,16 @@ void ESM::Filter::load (ESMReader& esm) case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','I','L','T'>::value: mFilter = esm.getHString(); break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -41,11 +37,11 @@ void ESM::Filter::load (ESMReader& esm) } } -void ESM::Filter::save (ESMWriter& esm) const +void ESM::Filter::save (ESMWriter& esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -59,5 +55,4 @@ void ESM::Filter::blank() { mFilter.clear(); mDescription.clear(); - mIsDeleted = false; } diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp index 1a8af92298..b1c511ebba 100644 --- a/components/esm/filter.hpp +++ b/components/esm/filter.hpp @@ -18,12 +18,8 @@ namespace ESM std::string mFilter; - bool mIsDeleted; - - Filter(); - - void load (ESMReader& esm); - void save (ESMWriter& esm) const; + void load (ESMReader& esm, bool &isDeleted); + void save (ESMWriter& esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index c32cea1a6b..14db45c342 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; - Activator::Activator() - : mIsDeleted(false) - {} - - void Activator::load(ESMReader &esm) + void Activator::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -40,6 +31,10 @@ namespace ESM case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -49,11 +44,11 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); } - void Activator::save(ESMWriter &esm) const + void Activator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -69,6 +64,5 @@ namespace ESM mName.clear(); mScript.clear(); mModel.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 93de07b250..4cc72d5283 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -17,12 +17,8 @@ struct Activator std::string mId, mName, mScript, mModel; - bool mIsDeleted; - - Activator(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index c1213583dd..ceff4ba7d7 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,31 +8,23 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; - Potion::Potion() - : mIsDeleted(false) - {} - - void Potion::load(ESMReader &esm) + void Potion::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -52,6 +44,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -60,14 +56,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing ALDT subrecord"); } - void Potion::save(ESMWriter &esm) const + void Potion::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -91,6 +87,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index 921585a9dc..9ef390ebd9 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -33,12 +33,8 @@ struct Potion std::string mId, mName, mModel, mIcon, mScript; EffectList mEffects; - bool mIsDeleted; - - Potion(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index edf1f473b8..7a77ba4213 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Apparatus::sRecordId = REC_APPA; - Apparatus::Apparatus() - : mIsDeleted(false) - {} - - void Apparatus::load(ESMReader &esm) + void Apparatus::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing AADT subrecord"); } - void Apparatus::save(ESMWriter &esm) const + void Apparatus::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -87,6 +82,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mName.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 2dac379952..0590d33edf 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -38,12 +38,8 @@ struct Apparatus AADTstruct mData; std::string mId, mModel, mIcon, mScript, mName; - bool mIsDeleted; - - Apparatus(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index d5b9fdd446..600c417be3 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -38,31 +38,23 @@ namespace ESM unsigned int Armor::sRecordId = REC_ARMO; - Armor::Armor() - : mIsDeleted(false) - {} - - void Armor::load(ESMReader &esm) + void Armor::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mParts.mParts.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -85,6 +77,10 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -93,15 +89,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CTDT subrecord"); } - void Armor::save(ESMWriter &esm) const + void Armor::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -130,6 +126,5 @@ namespace ESM mIcon.clear(); mScript.clear(); mEnchant.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 4ebe181a72..ef3bb734c0 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -96,12 +96,8 @@ struct Armor std::string mId, mName, mModel, mIcon, mScript, mEnchant; - bool mIsDeleted; - - Armor(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index e2c6ad7b2e..20d6b35cff 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int BodyPart::sRecordId = REC_BODY; - BodyPart::BodyPart() - : mIsDeleted(false) - {} - - void BodyPart::load(ESMReader &esm) + void BodyPart::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -42,6 +33,10 @@ namespace ESM esm.getHT(mData, 4); hasData = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -50,15 +45,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing BYDT subrecord"); } - void BodyPart::save(ESMWriter &esm) const + void BodyPart::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -78,7 +73,5 @@ namespace ESM mModel.clear(); mRace.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index f32d2fb58d..bf320330ff 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -60,12 +60,8 @@ struct BodyPart BYDTstruct mData; std::string mId, mModel, mRace; - bool mIsDeleted; - - BodyPart(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 2d0d3ce755..b08b12f501 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; - Book::Book() - : mIsDeleted(false) - {} - - void Book::load(ESMReader &esm) + void Book::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -54,6 +45,10 @@ namespace ESM case ESM::FourCC<'T','E','X','T'>::value: mText = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -62,14 +57,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing BKDT subrecord"); } - void Book::save(ESMWriter &esm) const + void Book::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -97,6 +92,5 @@ namespace ESM mScript.clear(); mEnchant.clear(); mText.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 931f813c0e..3d50356aea 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -28,12 +28,8 @@ struct Book std::string mName, mModel, mIcon, mScript, mEnchant, mText; std::string mId; - bool mIsDeleted; - - Book(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 54de009aad..56dc1897cf 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -8,30 +8,22 @@ namespace ESM { unsigned int BirthSign::sRecordId = REC_BSGN; - BirthSign::BirthSign() - : mIsDeleted(false) - {} - - void BirthSign::load(ESMReader &esm) + void BirthSign::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPowers.mList.clear(); - mIsDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -44,6 +36,10 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -54,9 +50,9 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void BirthSign::save(ESMWriter &esm) const + void BirthSign::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -75,7 +71,6 @@ namespace ESM mDescription.clear(); mTexture.clear(); mPowers.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 685ade82ff..24d27a7f85 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -22,12 +22,8 @@ struct BirthSign // List of powers and abilities that come with this birth sign. SpellList mPowers; - bool mIsDeleted; - - BirthSign(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 7e02f0f85f..2d8daa584f 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -52,75 +52,98 @@ namespace ESM return ref.mRefNum == refNum; } - void Cell::load(ESMReader &esm, bool saveContext) + void Cell::load(ESMReader &esm, bool &isDeleted, bool saveContext) { - loadName(esm); - loadData(esm); + loadNameAndData(esm, isDeleted); loadCell(esm, saveContext); } - void Cell::loadName(ESMReader &esm) + void Cell::loadNameAndData(ESMReader &esm, bool &isDeleted) { - mName = esm.getHNString("NAME"); + isDeleted = false; - mIsDeleted = false; - if (esm.isNextSub("DELE")) + bool hasName = false; + bool hasData = false; + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - esm.skipHSub(); - mIsDeleted = true; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'N','A','M','E'>::value: + mName = esm.getHString(); + hasName = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } + + if (!hasName) + esm.fail("Missing NAME subrecord"); + if (!hasData) + esm.fail("Missing DATA subrecord"); } void Cell::loadCell(ESMReader &esm, bool saveContext) { + mWater = 0.0f; + mWaterInt = false; + mMapColor = 0; + mRegion.clear(); mRefNumCounter = 0; - if (mData.mFlags & Interior) + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - // Interior cells - if (esm.isNextSub("INTV")) + esm.getSubName(); + switch (esm.retSubName().val) { - int waterl; - esm.getHT(waterl); - mWater = (float) waterl; - mWaterInt = true; + case ESM::FourCC<'I','N','T','V'>::value: + int waterl; + esm.getHT(waterl); + mWater = static_cast(waterl); + mWaterInt = true; + break; + case ESM::FourCC<'W','H','G','T'>::value: + esm.getHT(mWater); + break; + case ESM::FourCC<'A','M','B','I'>::value: + esm.getHT(mAmbi); + break; + case ESM::FourCC<'R','G','N','N'>::value: + mRegion = esm.getHString(); + break; + case ESM::FourCC<'N','A','M','5'>::value: + esm.getHT(mMapColor); + break; + case ESM::FourCC<'N','A','M','0'>::value: + esm.getHT(mRefNumCounter); + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; } - else if (esm.isNextSub("WHGT")) - { - esm.getHT(mWater); - } - - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if (mData.mFlags & QuasiEx) - mRegion = esm.getHNOString("RGNN"); - else if (esm.isNextSub("AMBI")) - esm.getHT(mAmbi); } - else + + if (saveContext) { - // Exterior cells - mRegion = esm.getHNOString("RGNN"); - - mMapColor = 0; - esm.getHNOT(mMapColor, "NAM5"); - } - if (esm.isNextSub("NAM0")) { - esm.getHT(mRefNumCounter); - } - - if (saveContext) { mContextList.push_back(esm.getContext()); esm.skipRecord(); } } - void Cell::loadData(ESMReader &esm) - { - esm.getHNT(mData, "DATA", 12); - } - void Cell::postLoad(ESMReader &esm) { // Save position of the cell references and move on @@ -128,11 +151,11 @@ namespace ESM esm.skipRecord(); } - void Cell::save(ESMWriter &esm) const + void Cell::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mName); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -183,8 +206,10 @@ namespace ESM } } - bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves, MovedCellRef *mref) + bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref) { + isDeleted = false; + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; @@ -207,12 +232,15 @@ namespace ESM } } - ref.load (esm); + if (esm.peekNextSub("FRMR")) + { + ref.load (esm, isDeleted); - // Identify references belonging to a parent file and adapt the ID accordingly. - adjustRefNum (ref.mRefNum, esm); - - return true; + // Identify references belonging to a parent file and adapt the ID accordingly. + adjustRefNum (ref.mRefNum, esm); + return true; + } + return false; } bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) @@ -242,8 +270,6 @@ namespace ESM mAmbi.mSunlight = 0; mAmbi.mFog = 0; mAmbi.mFogDensity = 0; - - mIsDeleted = false; } CellId Cell::getCellId() const diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index a1a758e3bd..2a7a78a54a 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -85,8 +85,7 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(0), - mIsDeleted(false) + mRefNumCounter(0) {} // Interior cells are indexed by this (it's the 'id'), for exterior @@ -113,18 +112,15 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - bool mIsDeleted; - void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. - void load(ESMReader &esm, bool saveContext = true); // Load everything (except references) - void loadName(ESMReader &esm); // Load NAME and checks for DELE - void loadData(ESMReader &esm); // Load DATAstruct only - void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except DATAstruct and references + void load(ESMReader &esm, bool &isDeleted, bool saveContext = true); // Load everything (except references) + void loadNameAndData(ESMReader &esm, bool &isDeleted); // Load NAME and DATAstruct + void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; bool isExterior() const { @@ -163,7 +159,11 @@ struct Cell reuse one memory location without blanking it between calls. */ /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, CellRef &ref, bool ignoreMoves = false, MovedCellRef *mref = 0); + static bool getNextRef(ESMReader &esm, + CellRef &ref, + bool &isDeleted, + bool ignoreMoves = false, + MovedCellRef *mref = 0); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index b58c35d90a..2ad14b9f26 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -22,10 +22,6 @@ namespace ESM "sSpecializationStealth" }; - Class::Class() - : mIsDeleted(false) - {} - int& Class::CLDTstruct::getSkill (int index, bool major) { if (index<0 || index>=5) @@ -42,26 +38,21 @@ namespace ESM return mSkills[index][major ? 1 : 0]; } - void Class::load(ESMReader &esm) + void Class::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -74,6 +65,10 @@ namespace ESM case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -82,14 +77,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CLDT subrecord"); } - void Class::save(ESMWriter &esm) const + void Class::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -113,7 +108,5 @@ namespace ESM for (int i=0; i<5; ++i) for (int i2=0; i2<2; ++i2) mData.mSkills[i][i2] = 0; - - mIsDeleted = false; } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 399e93c241..833dd6757d 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -73,12 +73,8 @@ struct Class std::string mId, mName, mDescription; CLDTstruct mData; - bool mIsDeleted; - - Class(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 18f7cd44fb..8a88e6d7a8 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -8,31 +8,23 @@ namespace ESM { unsigned int Clothing::sRecordId = REC_CLOT; - Clothing::Clothing() - : mIsDeleted(false) - {} - - void Clothing::load(ESMReader &esm) + void Clothing::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mParts.mParts.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -55,6 +47,10 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -63,15 +59,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing CTDT subrecord"); } - void Clothing::save(ESMWriter &esm) const + void Clothing::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -101,6 +97,5 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 202c1ec459..39e5ea6729 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -48,12 +48,8 @@ struct Clothing std::string mId, mName, mModel, mIcon, mEnchant, mScript; - bool mIsDeleted; - - Clothing(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index fadfe5f0fe..3726837509 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -24,16 +24,11 @@ namespace ESM unsigned int Container::sRecordId = REC_CONT; - Container::Container() - : mWeight(0), - mFlags(0x8), - mIsDeleted(false) - {} - - void Container::load(ESMReader &esm) + void Container::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mInventory.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasWeight = false; @@ -41,17 +36,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -76,6 +66,10 @@ namespace ESM case ESM::FourCC<'N','P','C','O'>::value: mInventory.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -84,17 +78,17 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasWeight && !mIsDeleted) + if (!hasWeight && !isDeleted) esm.fail("Missing CNDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void Container::save(ESMWriter &esm) const + void Container::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -118,6 +112,5 @@ namespace ESM mWeight = 0; mFlags = 0x8; // set default flag value mInventory.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 31c7e1815b..4c847f4e2e 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -52,12 +52,8 @@ struct Container int mFlags; InventoryList mInventory; - bool mIsDeleted; - - Container(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f360c87489..67c0ba31d6 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,14 +8,10 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; - Creature::Creature() - : mFlags(0), - mScale(0.0f), - mIsDeleted(false) - {} - - void Creature::load(ESMReader &esm) + void Creature::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mAiPackage.mList.clear(); @@ -25,7 +21,6 @@ namespace ESM { mScale = 1.f; mHasAI = false; - mIsDeleted = false; bool hasName = false; bool hasNpdt = false; @@ -33,17 +28,12 @@ namespace ESM { while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -89,6 +79,10 @@ namespace ESM { case AI_CNDT: mAiPackage.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -97,17 +91,17 @@ namespace ESM { if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasNpdt && !mIsDeleted) + if (!hasNpdt && !isDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void Creature::save(ESMWriter &esm) const + void Creature::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -156,7 +150,6 @@ namespace ESM { mAiData.mServices = 0; mAiPackage.mList.clear(); mTransport.mList.clear(); - mIsDeleted = false; } const std::vector& Creature::getTransport() const diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 22e834e45b..a5147619cf 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -96,14 +96,10 @@ struct Creature AIPackageList mAiPackage; Transport mTransport; - bool mIsDeleted; - - Creature(); - const std::vector& getTransport() const; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 74a708805c..30fa3cfef7 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -10,29 +10,25 @@ namespace ESM { unsigned int Dialogue::sRecordId = REC_DIAL; - Dialogue::Dialogue() - : mIsDeleted(false) - {} - - void Dialogue::load(ESMReader &esm) + void Dialogue::load(ESMReader &esm, bool &isDeleted) { loadId(esm); - loadData(esm); + loadData(esm, isDeleted); } void Dialogue::loadId(ESMReader &esm) { - mIsDeleted = false; mId = esm.getHNString("NAME"); } - void Dialogue::loadData(ESMReader &esm) + void Dialogue::loadData(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: { @@ -51,7 +47,7 @@ namespace ESM case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); mType = Unknown; - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -60,10 +56,10 @@ namespace ESM } } - void Dialogue::save(ESMWriter &esm) const + void Dialogue::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -76,7 +72,6 @@ namespace ESM void Dialogue::blank() { mInfo.clear(); - mIsDeleted = false; } void Dialogue::readInfo(ESMReader &esm, bool merge) @@ -84,25 +79,27 @@ namespace ESM ESM::DialInfo info; info.loadId(esm); + bool isDeleted = false; if (!merge || mInfo.empty()) { - info.loadInfo(esm); - mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + info.loadData(esm, isDeleted); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); + return; } - ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); + InfoContainer::iterator it = mInfo.end(); - std::map::iterator lookup; + LookupMap::iterator lookup; lookup = mLookup.find(info.mId); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; // Merge with existing record. Only the subrecords that are present in // the new record will be overwritten. - it->loadInfo(esm); + it->loadData(esm, isDeleted); info = *it; // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record @@ -111,35 +108,35 @@ namespace ESM } else { - info.loadInfo(esm); + info.loadData(esm, isDeleted); } if (info.mNext.empty()) { - mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); return; } if (info.mPrev.empty()) { - mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); + mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.begin(), info), isDeleted); return; } lookup = mLookup.find(info.mPrev); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; - mLookup[info.mId] = mInfo.insert(++it, info); + mLookup[info.mId] = std::make_pair(mInfo.insert(++it, info), isDeleted); return; } lookup = mLookup.find(info.mNext); if (lookup != mLookup.end()) { - it = lookup->second; + it = lookup->second.first; - mLookup[info.mId] = mInfo.insert(it, info); + mLookup[info.mId] = std::make_pair(mInfo.insert(it, info), isDeleted); return; } @@ -148,12 +145,15 @@ namespace ESM void Dialogue::clearDeletedInfos() { - for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) + LookupMap::const_iterator current = mLookup.begin(); + LookupMap::const_iterator end = mLookup.end(); + for (; current != end; ++current) { - if (it->mIsDeleted) - it = mInfo.erase(it); - else - ++it; + if (current->second.second) + { + mInfo.erase(current->second.first); + } } + mLookup.clear(); } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 73bf169741..e517fc86f4 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "loadinfo.hpp" @@ -39,27 +40,24 @@ struct Dialogue typedef std::list InfoContainer; - typedef std::map LookupMap; + // Parameters: Info ID, (Info iterator, Deleted flag) + typedef std::map > LookupMap; InfoContainer mInfo; // This is only used during the loading phase to speed up DialInfo merging. LookupMap mLookup; - bool mIsDeleted; - - Dialogue(); - - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Dialogue record void loadId(ESMReader &esm); ///< Loads NAME sub-record of Dialogue record - void loadData(ESMReader &esm); + void loadData(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Dialogue record, except NAME sub-record - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; - /// Remove all INFOs that are deleted or marked as QS_Deleted from mInfos. + /// Remove all INFOs that are deleted void clearDeletedInfos(); /// Read the next info record diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 4f58a42611..706e938e89 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; - Door::Door() - : mIsDeleted(false) - {} - - void Door::load(ESMReader &esm) + void Door::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -46,6 +37,10 @@ namespace ESM case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,11 +51,11 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Door::save(ESMWriter &esm) const + void Door::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -80,6 +75,5 @@ namespace ESM mScript.clear(); mOpenSound.clear(); mCloseSound.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 546471ed3d..3afe5d5e4b 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -17,12 +17,8 @@ struct Door std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; - bool mIsDeleted; - - Door(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 0e480c379d..5580ef222a 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -8,31 +8,22 @@ namespace ESM { unsigned int Enchantment::sRecordId = REC_ENCH; - Enchantment::Enchantment() - : mIsDeleted(false) - {} - - void Enchantment::load(ESMReader &esm) + void Enchantment::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'E','N','D','T'>::value: esm.getHT(mData, 16); hasData = true; @@ -40,6 +31,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -48,15 +43,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing ENDT subrecord"); } - void Enchantment::save(ESMWriter &esm) const + void Enchantment::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -74,7 +69,5 @@ namespace ESM mData.mAutocalc = 0; mEffects.mList.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 6ebe8e9405..7b93b519c3 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -42,12 +42,8 @@ struct Enchantment ENDTstruct mData; EffectList mEffects; - bool mIsDeleted; - - Enchantment(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 8538b0b95d..f550a55380 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -10,10 +10,6 @@ namespace ESM { unsigned int Faction::sRecordId = REC_FACT; - Faction::Faction() - : mIsDeleted(false) - {} - int& Faction::FADTstruct::getSkill (int index, bool ignored) { if (index<0 || index>=7) @@ -30,9 +26,10 @@ namespace ESM return mSkills[index]; } - void Faction::load(ESMReader &esm) + void Faction::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); @@ -43,17 +40,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -76,6 +68,10 @@ namespace ESM mReactions[faction] = reaction; break; } + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -84,15 +80,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing FADT subrecord"); } - void Faction::save(ESMWriter &esm) const + void Faction::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -136,7 +132,5 @@ namespace ESM mData.mSkills[i] = 0; mReactions.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 96c02028ba..cc715d2660 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -62,12 +62,8 @@ struct Faction // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; - bool mIsDeleted; - - Faction(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 5f96aff1f3..72ecce503c 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -8,19 +8,16 @@ namespace ESM { unsigned int Global::sRecordId = REC_GLOB; - Global::Global() - : mIsDeleted(false) - {} - - void Global::load (ESMReader &esm) + void Global::load (ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mId = esm.getHNString ("NAME"); if (esm.isNextSub ("DELE")) { esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; } else { @@ -28,11 +25,11 @@ namespace ESM } } - void Global::save (ESMWriter &esm) const + void Global::save (ESMWriter &esm, bool isDeleted) const { esm.writeHNCString ("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString ("DELE", ""); } @@ -45,7 +42,6 @@ namespace ESM void Global::blank() { mValue.setType (ESM::VT_None); - mIsDeleted = false; } bool operator== (const Global& left, const Global& right) diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index c0219c0bac..0533cc95ea 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -24,12 +24,8 @@ struct Global std::string mId; Variant mValue; - bool mIsDeleted; - - Global(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 9e2a80270d..1ebb002e68 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -8,13 +8,15 @@ namespace ESM { unsigned int GameSetting::sRecordId = REC_GMST; - void GameSetting::load (ESMReader &esm) + void GameSetting::load (ESMReader &esm, bool &isDeleted) { + isDeleted = false; // GameSetting record can't be deleted now (may be changed in the future) + mId = esm.getHNString("NAME"); mValue.read (esm, ESM::Variant::Format_Gmst); } - void GameSetting::save (ESMWriter &esm) const + void GameSetting::save (ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNCString("NAME", mId); mValue.write (esm, ESM::Variant::Format_Gmst); diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index d9d9048b61..73a723e810 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -26,7 +26,7 @@ struct GameSetting Variant mValue; - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); /// \todo remove the get* functions (redundant, since mValue has equivalent functions now). @@ -39,7 +39,7 @@ struct GameSetting std::string getString() const; ///< Throwns an exception if GMST is not of type string. - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 89fd4e0cd6..d1f20a3d45 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -8,29 +8,23 @@ namespace ESM { unsigned int DialInfo::sRecordId = REC_INFO; - DialInfo::DialInfo() - : mFactionLess(false), - mQuestStatus(QS_None), - mIsDeleted(false) - {} - - void DialInfo::load(ESMReader &esm) + void DialInfo::load(ESMReader &esm, bool &isDeleted) { loadId(esm); - loadInfo(esm); + loadData(esm, isDeleted); } void DialInfo::loadId(ESMReader &esm) { - mIsDeleted = false; mId = esm.getHNString("INAM"); } - void DialInfo::loadInfo(ESMReader &esm) + void DialInfo::loadData(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mQuestStatus = QS_None; mFactionLess = false; - mIsDeleted = false; mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); @@ -41,13 +35,8 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); break; @@ -104,6 +93,10 @@ namespace ESM mQuestStatus = QS_Restart; esm.skipRecord(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -111,13 +104,13 @@ namespace ESM } } - void DialInfo::save(ESMWriter &esm) const + void DialInfo::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("INAM", mId); esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -173,6 +166,5 @@ namespace ESM mResultScript.clear(); mFactionLess = false; mQuestStatus = QS_None; - mIsDeleted = false; } } diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 65363d1be8..8123a9ace8 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -105,18 +105,14 @@ struct DialInfo REC_DELE = 0x454c4544 }; - bool mIsDeleted; - - DialInfo(); - - void load(ESMReader &esm); + void load(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Info record void loadId(ESMReader &esm); ///< Loads only Id of Info record (INAM sub-record) - void loadInfo(ESMReader &esm); + void loadData(ESMReader &esm, bool &isDeleted); ///< Loads all sub-records of Info record, except INAM sub-record - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 51a1f48059..a481d5b79a 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; - Ingredient::Ingredient() - : mIsDeleted(false) - {} - - void Ingredient::load(ESMReader &esm) + void Ingredient::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,7 +51,7 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing IRDT subrecord"); // horrible hack to fix broken data in records @@ -83,11 +78,11 @@ namespace ESM } } - void Ingredient::save(ESMWriter &esm) const + void Ingredient::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -115,7 +110,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index c92f28f183..c0f4450238 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -31,12 +31,8 @@ struct Ingredient IRDTstruct mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Ingredient(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 6acaa6e6a3..2ffd2a21b0 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -72,7 +72,6 @@ namespace ESM , mDataTypes(0) , mDataLoaded(false) , mLandData(NULL) - , mIsDeleted(false) { } @@ -81,61 +80,82 @@ namespace ESM delete mLandData; } - void Land::load(ESMReader &esm) + void Land::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEsm = &esm; mPlugin = mEsm->getIndex(); - mIsDeleted = false; - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(mX); - esm.getT(mY); - - esm.getHNT(mFlags, "DATA"); - - if (esm.isNextSub("DELE")) + bool hasLocation = false; + bool isLoaded = false; + while (!isLoaded && esm.hasMoreSubs()) { - esm.skipHSub(); - mIsDeleted = true; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'I','N','T','V'>::value: + esm.getSubHeaderIs(8); + esm.getT(mX); + esm.getT(mY); + hasLocation = true; + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mFlags); + break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; + default: + esm.cacheSubName(); + isLoaded = true; + break; + } } - // Store the file position + if (!hasLocation) + esm.fail("Missing INTV subrecord"); + mContext = esm.getContext(); - // Skip these here. Load the actual data when the cell is loaded. - if (esm.isNextSub("VNML")) + // Skip the land data here. Load it when the cell is loaded. + while (esm.hasMoreSubs()) { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VNML; - } - if (esm.isNextSub("VHGT")) - { - esm.skipHSubSize(4232); - mDataTypes |= DATA_VHGT; - } - if (esm.isNextSub("WNAM")) - { - esm.skipHSubSize(81); - mDataTypes |= DATA_WNAM; - } - if (esm.isNextSub("VCLR")) - { - esm.skipHSubSize(12675); - mDataTypes |= DATA_VCLR; - } - if (esm.isNextSub("VTEX")) - { - esm.skipHSubSize(512); - mDataTypes |= DATA_VTEX; + esm.getSubName(); + switch (esm.retSubName().val) + { + case ESM::FourCC<'V','N','M','L'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VNML; + break; + case ESM::FourCC<'V','H','G','T'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VHGT; + break; + case ESM::FourCC<'W','N','A','M'>::value: + esm.skipHSub(); + mDataTypes |= DATA_WNAM; + break; + case ESM::FourCC<'V','C','L','R'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VCLR; + break; + case ESM::FourCC<'V','T','E','X'>::value: + esm.skipHSub(); + mDataTypes |= DATA_VTEX; + break; + default: + esm.fail("Unknown subrecord"); + break; + } } mDataLoaded = 0; mLandData = NULL; } - void Land::save(ESMWriter &esm) const + void Land::save(ESMWriter &esm, bool isDeleted) const { esm.startSubRecord("INTV"); esm.writeT(mX); @@ -144,22 +164,17 @@ namespace ESM esm.writeHNT("DATA", mFlags); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } - if (mLandData != NULL) + if (mLandData) { mLandData->save(esm); } } - void Land::blank() - { - mIsDeleted = false; - } - void Land::loadData(int flags) { // Try to load only available data diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d9ee0015a4..ddb00f3947 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -97,12 +97,10 @@ struct Land LandData *mLandData; - bool mIsDeleted; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; - - void blank(); + void blank() {} /** * Actually loads data diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 9c34ef6578..6245ec856a 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -6,29 +6,21 @@ namespace ESM { - LevelledListBase::LevelledListBase() - : mIsDeleted(false) - {} - - void LevelledListBase::load(ESMReader &esm) + void LevelledListBase::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; + bool hasList = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mFlags); break; @@ -53,12 +45,28 @@ namespace ESM li.mId = esm.getHNString(mRecName); esm.getHNT(li.mLevel, "INTV"); } + + hasList = true; break; } - default: - mList.clear(); - esm.skipRecord(); + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; break; + default: + { + if (!hasList) + { + // Original engine ignores rest of the record, even if there are items following + mList.clear(); + esm.skipRecord(); + } + else + { + esm.fail("Unknown subrecord"); + } + break; + } } } @@ -66,11 +74,11 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void LevelledListBase::save(ESMWriter &esm) const + void LevelledListBase::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -92,7 +100,6 @@ namespace ESM mFlags = 0; mChanceNone = 0; mList.clear(); - mIsDeleted = false; } unsigned int CreatureLevList::sRecordId = REC_LEVC; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 14ebc99370..ed4131c165 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -36,12 +36,8 @@ struct LevelledListBase std::vector mList; - bool mIsDeleted; - - LevelledListBase(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 441e96d0ac..a0fedc3ad8 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; - Light::Light() - : mIsDeleted(false) - {} - - void Light::load(ESMReader &esm) + void Light::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,6 +42,10 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -59,14 +54,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing LHDT subrecord"); } - void Light::save(ESMWriter &esm) const + void Light::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -93,6 +88,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mName.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index d4d3418d87..8509c64b6d 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -47,12 +47,8 @@ struct Light std::string mSound, mScript, mModel, mIcon, mName, mId; - bool mIsDeleted; - - Light(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 2cfe43743b..be93eaa0e7 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; - Lockpick::Lockpick() - : mIsDeleted(false) - {} - - void Lockpick::load(ESMReader &esm) + void Lockpick::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing LKDT subrecord"); } - void Lockpick::save(ESMWriter &esm) const + void Lockpick::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index ce7de2c06d..9db41af978 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -27,12 +27,8 @@ struct Lockpick Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Lockpick(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 6bd48d8011..cf026dbf1d 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int LandTexture::sRecordId = REC_LTEX; - LandTexture::LandTexture() - : mIsDeleted(false) - {} - - void LandTexture::load(ESMReader &esm) + void LandTexture::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasIndex = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'I','N','T','V'>::value: esm.getHT(mIndex); hasIndex = true; @@ -39,6 +30,10 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: mTexture = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -50,9 +45,9 @@ namespace ESM if (!hasIndex) esm.fail("Missing INTV subrecord"); } - void LandTexture::save(ESMWriter &esm) const + void LandTexture::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -66,6 +61,5 @@ namespace ESM { mTexture.clear(); mIndex = -1; - mIsDeleted = false; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 33af776120..2cb5abf0c8 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -34,12 +34,8 @@ struct LandTexture std::string mId, mTexture; int mIndex; - bool mIsDeleted; - - LandTexture(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 6f859ab3cd..eef58aa2f1 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -189,8 +189,10 @@ namespace ESM { unsigned int MagicEffect::sRecordId = REC_MGEF; -void MagicEffect::load(ESMReader &esm) +void MagicEffect::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; // MagicEffect record can't be deleted now (may be changed in the future) + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); @@ -209,8 +211,7 @@ void MagicEffect::load(ESMReader &esm) while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); @@ -250,7 +251,7 @@ void MagicEffect::load(ESMReader &esm) } } } -void MagicEffect::save(ESMWriter &esm) const +void MagicEffect::save(ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNT("INDX", mIndex); diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 32b8a85a6d..24d4c9e2be 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -96,8 +96,8 @@ struct MagicEffect // sMagicCreature04ID/05ID. int mIndex; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; /// Set record to default state (does not touch the ID/index). void blank(); diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index de9ccdd6aa..f03cb9a852 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; - Miscellaneous::Miscellaneous() - : mIsDeleted(false) - {} - - void Miscellaneous::load(ESMReader &esm) + void Miscellaneous::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing MCDT subrecord"); } - void Miscellaneous::save(ESMWriter &esm) const + void Miscellaneous::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -86,6 +81,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 82018cd72d..e7a3239042 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -32,12 +32,8 @@ struct Miscellaneous std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Miscellaneous(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index ff3213ee93..939801e742 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -8,15 +8,10 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; - NPC::NPC() - : mFlags(0), - mHasAI(false), - mIsDeleted(false) - {} - - void NPC::load(ESMReader &esm) + void NPC::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); @@ -31,17 +26,12 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -108,6 +98,10 @@ namespace ESM case AI_CNDT: mAiPackage.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -116,16 +110,16 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasNpdt && !mIsDeleted) + if (!hasNpdt && !isDeleted) esm.fail("Missing NPDT subrecord"); - if (!hasFlags && !mIsDeleted) + if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); } - void NPC::save(ESMWriter &esm) const + void NPC::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -206,7 +200,6 @@ namespace ESM mScript.clear(); mHair.clear(); mHead.clear(); - mIsDeleted = false; } int NPC::getFactionRank() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 2637527522..5b89f40554 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -130,12 +130,8 @@ struct NPC // body parts std::string mHair, mHead; - bool mIsDeleted; - - NPC(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; bool isMale() const; diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 5e8de9d573..8027be91ca 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -32,12 +32,10 @@ namespace ESM { } - Pathgrid::Pathgrid() - : mIsDeleted(false) - {} - - void Pathgrid::load(ESMReader &esm) + void Pathgrid::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPoints.clear(); mEdges.clear(); @@ -49,8 +47,7 @@ namespace ESM while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); @@ -118,7 +115,7 @@ namespace ESM } case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -132,12 +129,12 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Pathgrid::save(ESMWriter &esm) const + void Pathgrid::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNT("DATA", mData, 12); esm.writeHNCString("NAME", mCell); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -173,6 +170,5 @@ namespace ESM mData.mS2 = 0; mPoints.clear(); mEdges.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index 4b82d95711..d1003eb865 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -53,12 +53,8 @@ struct Pathgrid typedef std::vector EdgeList; EdgeList mEdges; - bool mIsDeleted; - - Pathgrid(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 4ce9b9d9c7..31caeff414 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; - Probe::Probe() - : mIsDeleted(false) - {} - - void Probe::load(ESMReader &esm) + void Probe::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing PBDT subrecord"); } - void Probe::save(ESMWriter &esm) const + void Probe::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index 748d498fc6..da203b456b 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -27,12 +27,8 @@ struct Probe Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Probe(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 12762bda3b..d5172a133e 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -8,10 +8,6 @@ namespace ESM { unsigned int Race::sRecordId = REC_RACE; - Race::Race() - : mIsDeleted(false) - {} - int Race::MaleFemale::getValue (bool male) const { return male ? mMale : mFemale; @@ -22,27 +18,23 @@ namespace ESM return static_cast(male ? mMale : mFemale); } - void Race::load(ESMReader &esm) + void Race::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mPowers.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -56,6 +48,10 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); } @@ -63,14 +59,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing RADT subrecord"); } - void Race::save(ESMWriter &esm) const + void Race::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index e8e9a442bb..bf0573075c 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -68,12 +68,8 @@ struct Race std::string mId, mName, mDescription; SpellList mPowers; - bool mIsDeleted; - - Race(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b48ffa4b7b..b04e6ee3b0 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -8,29 +8,20 @@ namespace ESM { unsigned int Region::sRecordId = REC_REGN; - Region::Region() - : mMapColor(0), - mIsDeleted(false) - {} - - void Region::load(ESMReader &esm) + void Region::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); @@ -75,6 +66,9 @@ namespace ESM esm.getHT(sr, 33); mSoundList.push_back(sr); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; default: esm.fail("Unknown subrecord"); break; @@ -85,9 +79,9 @@ namespace ESM esm.fail("Missing NAME subrecord"); } - void Region::save(ESMWriter &esm) const + void Region::save(ESMWriter &esm, bool isDeleted) const { - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -121,7 +115,5 @@ namespace ESM mName.clear(); mSleepList.clear(); mSoundList.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 9082437fed..3d914bd17b 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -51,12 +51,8 @@ struct Region std::vector mSoundList; - bool mIsDeleted; - - Region(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 74e682d63e..00d2ebf085 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Repair::sRecordId = REC_REPA; - Repair::Repair() - : mIsDeleted(false) - {} - - void Repair::load(ESMReader &esm) + void Repair::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -48,6 +39,10 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -56,15 +51,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing RIDT subrecord"); } - void Repair::save(ESMWriter &esm) const + void Repair::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -88,6 +83,5 @@ namespace ESM mModel.clear(); mIcon.clear(); mScript.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index 1448f9c772..2537c53cb6 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -27,12 +27,8 @@ struct Repair Data mData; std::string mId, mName, mModel, mIcon, mScript; - bool mIsDeleted; - - Repair(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 333389ba41..e433ddede8 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -10,10 +10,6 @@ namespace ESM { unsigned int Script::sRecordId = REC_SCPT; - Script::Script() - : mIsDeleted(false) - {} - void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -61,17 +57,17 @@ namespace ESM } } - void Script::load(ESMReader &esm) + void Script::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mVarNames.clear(); - mIsDeleted = false; bool hasHeader = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'S','C','H','D'>::value: SCHD data; @@ -80,10 +76,6 @@ namespace ESM mId = data.mName.toString(); hasHeader = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'S','C','V','R'>::value: // list of local variables loadSCVR(esm); @@ -96,6 +88,10 @@ namespace ESM case ESM::FourCC<'S','C','T','X'>::value: mScriptText = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -106,7 +102,7 @@ namespace ESM esm.fail("Missing SCHD subrecord"); } - void Script::save(ESMWriter &esm) const + void Script::save(ESMWriter &esm, bool isDeleted) const { std::string varNameString; if (!mVarNames.empty()) @@ -121,7 +117,7 @@ namespace ESM esm.writeHNT("SCHD", data, 52); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -156,8 +152,6 @@ namespace ESM mScriptText = "Begin \"" + mId + "\"\n\nEnd " + mId + "\n"; else mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; - - mIsDeleted = false; } } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 58b5842e83..b8a06406dd 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -50,12 +50,8 @@ public: /// Script source code std::string mScriptText; - bool mIsDeleted; - - Script(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 7883b8a1a9..c520897910 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,15 +129,16 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; - void Skill::load(ESMReader &esm) + void Skill::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; // Skill record can't be deleted now (may be changed in the future) + bool hasIndex = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'I','N','D','X'>::value: esm.getHT(mIndex); @@ -164,7 +165,7 @@ namespace ESM mId = indexToId (mIndex); } - void Skill::save(ESMWriter &esm) const + void Skill::save(ESMWriter &esm, bool /*isDeleted*/) const { esm.writeHNT("INDX", mIndex); esm.writeHNT("SKDT", mData, 24); diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index e001842970..5430b422d1 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -78,8 +78,8 @@ struct Skill static const std::string sIconNames[Length]; static const boost::array sSkillIds; - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index a20e6ee519..400b1072b6 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,31 +8,21 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; - SoundGenerator::SoundGenerator() - : mType(LeftFoot), - mIsDeleted(false) - {} - - void SoundGenerator::load(ESMReader &esm) + void SoundGenerator::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mType, 4); hasData = true; @@ -43,6 +33,10 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -51,17 +45,17 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing DATA subrecord"); } - void SoundGenerator::save(ESMWriter &esm) const + void SoundGenerator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -72,6 +66,5 @@ namespace ESM mType = LeftFoot; mCreature.clear(); mSound.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 13eb180723..70b221e98c 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -36,12 +36,8 @@ struct SoundGenerator std::string mId, mCreature, mSound; - bool mIsDeleted; - - SoundGenerator(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 55fe692929..d3a82e1984 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; - Sound::Sound() - : mIsDeleted(false) - {} - - void Sound::load(ESMReader &esm) + void Sound::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mSound = esm.getHString(); break; @@ -39,6 +30,10 @@ namespace ESM esm.getHT(mData, 3); hasData = true; break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -47,15 +42,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing DATA subrecord"); } - void Sound::save(ESMWriter &esm) const + void Sound::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -72,7 +67,5 @@ namespace ESM mData.mVolume = 128; mData.mMinRange = 0; mData.mMaxRange = 255; - - mIsDeleted = false; } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 0b40ae7514..937e22be88 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -23,12 +23,8 @@ struct Sound SOUNstruct mData; std::string mId, mSound; - bool mIsDeleted; - - Sound(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 28feffd209..16ffb63ff7 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,32 +8,23 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; - Spell::Spell() - : mIsDeleted(false) - {} - - void Spell::load(ESMReader &esm) + void Spell::load(ESMReader &esm, bool &isDeleted) { + isDeleted = false; + mEffects.mList.clear(); - mIsDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -46,6 +37,10 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -54,15 +49,15 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing SPDT subrecord"); } - void Spell::save(ESMWriter &esm) const + void Spell::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -81,6 +76,5 @@ namespace ESM mName.clear(); mEffects.mList.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 327e94d8f8..1763d0991c 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -45,12 +45,8 @@ struct Spell std::string mId, mName; EffectList mEffects; - bool mIsDeleted; - - Spell(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID/index). diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 076f73742b..6af6c96dc0 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,21 +8,16 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; - StartScript::StartScript() - : mIsDeleted(false) - {} - - void StartScript::load(ESMReader &esm) + void StartScript::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasData = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'D','A','T','A'>::value: mData = esm.getHString(); @@ -34,7 +29,7 @@ namespace ESM break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); - mIsDeleted = true; + isDeleted = true; break; default: esm.fail("Unknown subrecord"); @@ -47,12 +42,12 @@ namespace ESM if (!hasName) esm.fail("Missing NAME"); } - void StartScript::save(ESMWriter &esm) const + void StartScript::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNString("DATA", mData); esm.writeHNString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -61,6 +56,5 @@ namespace ESM void StartScript::blank() { mData.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index e475abd866..ce2ff49e77 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -26,13 +26,9 @@ struct StartScript std::string mData; std::string mId; - bool mIsDeleted; - - StartScript(); - // Load a record and add it to the list - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); }; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 9a146a3705..eee7a50f50 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,32 +8,27 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; - Static::Static() - : mIsDeleted(false) - {} - - void Static::load(ESMReader &esm) + void Static::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; @@ -43,10 +38,10 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); } - void Static::save(ESMWriter &esm) const + void Static::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); } @@ -59,6 +54,5 @@ namespace ESM void Static::blank() { mModel.clear(); - mIsDeleted = false; } } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index f88ad671bd..930cdb8491 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -28,12 +28,8 @@ struct Static std::string mId, mModel; - bool mIsDeleted; - - Static(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 98302c13d5..b0bc1dad67 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -8,30 +8,21 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; - Weapon::Weapon() - : mIsDeleted(false) - {} - - void Weapon::load(ESMReader &esm) + void Weapon::load(ESMReader &esm, bool &isDeleted) { - mIsDeleted = false; + isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - uint32_t name = esm.retSubName().val; - switch (name) + switch (esm.retSubName().val) { case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; - case ESM::FourCC<'D','E','L','E'>::value: - esm.skipHSub(); - mIsDeleted = true; - break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; @@ -51,6 +42,10 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; + case ESM::FourCC<'D','E','L','E'>::value: + esm.skipHSub(); + isDeleted = true; + break; default: esm.fail("Unknown subrecord"); } @@ -58,14 +53,14 @@ namespace ESM if (!hasName) esm.fail("Missing NAME subrecord"); - if (!hasData && !mIsDeleted) + if (!hasData && !isDeleted) esm.fail("Missing WPDT subrecord"); } - void Weapon::save(ESMWriter &esm) const + void Weapon::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); - if (mIsDeleted) + if (isDeleted) { esm.writeHNCString("DELE", ""); return; @@ -98,7 +93,5 @@ namespace ESM mIcon.clear(); mEnchant.clear(); mScript.clear(); - - mIsDeleted = false; } } diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index ce61eeb727..eddcaee4f1 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -69,12 +69,8 @@ struct Weapon std::string mId, mName, mModel, mIcon, mEnchant, mScript; - bool mIsDeleted; - - Weapon(); - - void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 0ae690ee8a..575826ef31 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -8,7 +8,8 @@ void ESM::ObjectState::load (ESMReader &esm) { mVersion = esm.getFormat(); - mRef.loadData(esm); + bool isDeleted; + mRef.loadData(esm, isDeleted); mHasLocals = 0; esm.getHNOT (mHasLocals, "HLOC"); From 67c8f95c4e85466a7c802f4cced117ade2378184 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 13:17:03 +0300 Subject: [PATCH 0796/1812] Load/read methods (for ESM records) accept a deleted flag in OpenMW --- apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 58 +++++++++--------- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 6 +- apps/openmw/mwworld/store.cpp | 94 +++++++++++++---------------- 5 files changed, 79 insertions(+), 83 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 0ce6032243..49197d1671 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// and the build will fail with an ugly three-way cyclic header dependence /// so we need to pass the instantiation of the method to the linker, when /// all methods are known. - void load (ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); + void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a516725811..e9f9c5cd1b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -147,7 +147,7 @@ namespace MWWorld { template - void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + void CellRefList::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore) { const MWWorld::Store &store = esmStore.get(); @@ -158,7 +158,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); - if (ref.mIsDeleted) + if (deleted) liveCellRef.mData.setDeleted(true); if (iter != mList.end()) @@ -374,9 +374,10 @@ namespace MWWorld ESM::CellRef ref; // Get each reference in turn - while (mCell->getNextRef (esm[index], ref)) + bool deleted = false; + while (mCell->getNextRef (esm[index], ref, deleted)) { - if (ref.mIsDeleted) + if (deleted) continue; // Don't list reference if it was moved to a different cell. @@ -419,7 +420,8 @@ namespace MWWorld ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn - while(mCell->getNextRef(esm[index], ref)) + bool deleted = false; + while(mCell->getNextRef(esm[index], ref, deleted)) { // Don't load reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = @@ -428,7 +430,7 @@ namespace MWWorld continue; } - loadRef (ref, store); + loadRef (ref, deleted, store); } } @@ -437,7 +439,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, store); + loadRef (ref, false, store); } } @@ -466,32 +468,32 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) { Misc::StringUtils::toLower (ref.mRefID); switch (store.find (ref.mRefID)) { - case ESM::REC_ACTI: mActivators.load(ref, store); break; - case ESM::REC_ALCH: mPotions.load(ref,store); break; - case ESM::REC_APPA: mAppas.load(ref, store); break; - case ESM::REC_ARMO: mArmors.load(ref, store); break; - case ESM::REC_BOOK: mBooks.load(ref, store); break; - case ESM::REC_CLOT: mClothes.load(ref, store); break; - case ESM::REC_CONT: mContainers.load(ref, store); break; - case ESM::REC_CREA: mCreatures.load(ref, store); break; - case ESM::REC_DOOR: mDoors.load(ref, store); break; - case ESM::REC_INGR: mIngreds.load(ref, store); break; - case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; - case ESM::REC_LEVI: mItemLists.load(ref, store); break; - case ESM::REC_LIGH: mLights.load(ref, store); break; - case ESM::REC_LOCK: mLockpicks.load(ref, store); break; - case ESM::REC_MISC: mMiscItems.load(ref, store); break; - case ESM::REC_NPC_: mNpcs.load(ref, store); break; - case ESM::REC_PROB: mProbes.load(ref, store); break; - case ESM::REC_REPA: mRepairs.load(ref, store); break; - case ESM::REC_STAT: mStatics.load(ref, store); break; - case ESM::REC_WEAP: mWeapons.load(ref, store); break; + case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; + case ESM::REC_ALCH: mPotions.load(ref, deleted,store); break; + case ESM::REC_APPA: mAppas.load(ref, deleted, store); break; + case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break; + case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break; + case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break; + case ESM::REC_CONT: mContainers.load(ref, deleted, store); break; + case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break; + case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break; + case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break; + case ESM::REC_LIGH: mLights.load(ref, deleted, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break; + case ESM::REC_PROB: mProbes.load(ref, deleted, store); break; + case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break; + case ESM::REC_STAT: mStatics.load(ref, deleted, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 5caa4eeea2..f879343d9d 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); - void loadRef (ESM::CellRef& ref, const ESMStore& store); + void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 668a33f091..87070a7122 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -92,7 +92,11 @@ namespace MWWorld if (type==ESM::REC_GLOB) { ESM::Global global; - global.load(reader); + bool isDeleted = false; + + // This readRecord() method is used when reading a saved game. + // Deleted globals can't appear there, so isDeleted will be ignored here. + global.load(reader, isDeleted); Misc::StringUtils::toLower(global.mId); Collection::iterator iter = mVariables.find (global.mId); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 55fb43e000..cd9290bfc8 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -66,7 +66,9 @@ namespace MWWorld void IndexedStore::load(ESM::ESMReader &esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); // Try to overwrite existing record std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); @@ -187,14 +189,16 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); Misc::StringUtils::toLower(record.mId); std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); - return RecordId(record.mId, record.mIsDeleted); + return RecordId(record.mId, isDeleted); } template void Store::setUp() @@ -324,10 +328,12 @@ namespace MWWorld RecordId Store::read(ESM::ESMReader& reader) { T record; - record.load (reader); + bool isDeleted = false; + + record.load (reader, isDeleted); insert (record); - return RecordId(record.mId, record.mIsDeleted); + return RecordId(record.mId, isDeleted); } // LandTexture @@ -370,7 +376,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm, size_t plugin) { ESM::LandTexture lt; - lt.load(esm); + bool isDeleted = false; + + lt.load(esm, isDeleted); // Make sure we have room for the structure if (plugin >= mStatic.size()) { @@ -383,7 +391,7 @@ namespace MWWorld // Store it ltexl[lt.mIndex] = lt; - return RecordId(lt.mId, lt.mIsDeleted); + return RecordId(lt.mId, isDeleted); } RecordId Store::load(ESM::ESMReader &esm) { @@ -449,7 +457,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { ESM::Land *ptr = new ESM::Land(); - ptr->load(esm); + bool isDeleted = false; + + ptr->load(esm, isDeleted); // Same area defined in multiple plugins? -> last plugin wins // Can't use search() because we aren't sorted yet - is there any other way to speed this up? @@ -465,7 +475,7 @@ namespace MWWorld mStatic.push_back(ptr); - return RecordId(); // No ID and can't be deleted (for now) + return RecordId("", isDeleted); } void Store::setUp() { @@ -617,12 +627,12 @@ namespace MWWorld // All cells have a name record, even nameless exterior cells. ESM::Cell cell; - cell.loadName(esm); - std::string idLower = Misc::StringUtils::lowerCase(cell.mName); + bool isDeleted = false; - // Load the (x,y) coordinates of the cell, if it is an exterior cell, + // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with - cell.loadData(esm); + cell.loadNameAndData(esm, isDeleted); + std::string idLower = Misc::StringUtils::lowerCase(cell.mName); if(cell.mData.mFlags & ESM::Cell::Interior) { @@ -690,7 +700,8 @@ namespace MWWorld mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; } } - return RecordId("", cell.mIsDeleted); + + return RecordId(cell.mName, isDeleted); } Store::iterator Store::intBegin() const { @@ -849,7 +860,9 @@ namespace MWWorld RecordId Store::load(ESM::ESMReader &esm) { ESM::Pathgrid pathgrid; - pathgrid.load(esm); + bool isDeleted = false; + + pathgrid.load(esm, isDeleted); // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. @@ -872,7 +885,7 @@ namespace MWWorld ret.first->second = pathgrid; } - return RecordId(); // No ID and can't be deleted (for now) + return RecordId("", isDeleted); } size_t Store::getSize() const { @@ -1027,22 +1040,24 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; + bool isDeleted = false; + dialogue.loadId(esm); std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId); std::map::iterator found = mStatic.find(idLower); if (found == mStatic.end()) { - dialogue.loadData(esm); + dialogue.loadData(esm, isDeleted); mStatic.insert(std::make_pair(idLower, dialogue)); } else { - found->second.loadData(esm); + found->second.loadData(esm, isDeleted); dialogue = found->second; } - return RecordId(dialogue.mId, dialogue.mIsDeleted); + return RecordId(dialogue.mId, isDeleted); } @@ -1052,7 +1067,9 @@ namespace MWWorld template <> inline RecordId Store::load(ESM::ESMReader &esm) { ESM::Script script; - script.load(esm); + bool isDeleted = false; + + script.load(esm, isDeleted); Misc::StringUtils::toLower(script.mId); std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); @@ -1061,7 +1078,7 @@ namespace MWWorld else inserted.first->second = script; - return RecordId(script.mId, script.mIsDeleted); + return RecordId(script.mId, isDeleted); } @@ -1072,7 +1089,9 @@ namespace MWWorld inline RecordId Store::load(ESM::ESMReader &esm) { ESM::StartScript script; - script.load(esm); + bool isDeleted = false; + + script.load(esm, isDeleted); Misc::StringUtils::toLower(script.mId); std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); @@ -1081,36 +1100,7 @@ namespace MWWorld else inserted.first->second = script; - return RecordId(script.mId); - } - - // GameSetting - // Need to specialize load() and read() methods, because GameSetting can't - // be deleted (has no mIsDeleted flag) - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &reader) - { - ESM::GameSetting setting; - setting.load(reader); - Misc::StringUtils::toLower(setting.mId); - - std::pair inserted = mStatic.insert(std::make_pair(setting.mId, setting)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - - return RecordId(setting.mId); - } - - template <> - inline RecordId Store::read(ESM::ESMReader &reader) - { - ESM::GameSetting setting; - setting.load(reader); - insert(setting); - - return RecordId(setting.mId); + return RecordId(script.mId, isDeleted); } } From 13bb6be2383c808084eabed0cb1bfb3b9749e55a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 20:25:43 +0300 Subject: [PATCH 0797/1812] Load methods (for ESM records) accept a deleted flag in OpenCS --- apps/opencs/model/doc/savingstages.cpp | 31 ++++-------- apps/opencs/model/doc/savingstages.hpp | 3 +- apps/opencs/model/world/cell.cpp | 6 +-- apps/opencs/model/world/cell.hpp | 2 +- apps/opencs/model/world/data.cpp | 6 ++- apps/opencs/model/world/idcollection.cpp | 3 -- apps/opencs/model/world/idcollection.hpp | 13 +++-- apps/opencs/model/world/infocollection.cpp | 6 ++- apps/opencs/model/world/land.cpp | 5 +- apps/opencs/model/world/land.hpp | 2 +- apps/opencs/model/world/landtexture.cpp | 8 +--- apps/opencs/model/world/landtexture.hpp | 2 +- apps/opencs/model/world/pathgrid.cpp | 15 ++---- apps/opencs/model/world/pathgrid.hpp | 5 +- apps/opencs/model/world/record.cpp | 48 ------------------- apps/opencs/model/world/record.hpp | 39 --------------- apps/opencs/model/world/refcollection.cpp | 5 +- apps/opencs/model/world/refiddata.hpp | 11 +++-- apps/opencs/model/world/subcellcollection.hpp | 7 +-- 19 files changed, 56 insertions(+), 161 deletions(-) delete mode 100644 apps/opencs/model/world/idcollection.cpp diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index dbfa4651b7..87f7ea16a1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -107,10 +107,8 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message { // if the topic is deleted, we do not need to bother with INFO records. ESM::Dialogue dialogue = topic.get(); - dialogue.mIsDeleted = true; - writer.startRecord(dialogue.sRecordId); - dialogue.save(writer); + dialogue.save(writer, true); writer.endRecord(dialogue.sRecordId); return; } @@ -121,7 +119,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - if (topic.isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) + if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted) { infoModified = true; break; @@ -131,7 +129,6 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message if (topic.isModified() || infoModified) { ESM::Dialogue dialogue = topic.get(); - writer.startRecord (dialogue.sRecordId); dialogue.save (writer); writer.endRecord (dialogue.sRecordId); @@ -143,7 +140,6 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); - info.mIsDeleted = (iter->mState == CSMWorld::RecordBase::State_Deleted); info.mPrev = ""; if (iter!=range.first) @@ -164,7 +160,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message } writer.startRecord (info.sRecordId); - info.save (writer); + info.save (writer, iter->mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (info.sRecordId); } } @@ -213,9 +209,7 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) const CSMWorld::Record& record = mDocument.getData().getReferences().getRecord (i); - if (record.mState==CSMWorld::RecordBase::State_Deleted || - record.mState==CSMWorld::RecordBase::State_Modified || - record.mState==CSMWorld::RecordBase::State_ModifiedOnly) + if (record.isModified() || record.mState == CSMWorld::RecordBase::State_Deleted) { std::string cellId = record.get().mOriginalCell.empty() ? record.get().mCell : record.get().mOriginalCell; @@ -284,8 +278,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY; } - cellRecord.mIsDeleted = (cell.mState == CSMWorld::RecordBase::State_Deleted); - cellRecord.save (writer); + cellRecord.save (writer, cell.mState == CSMWorld::RecordBase::State_Deleted); // write references if (references!=mState.getSubRecords().end()) @@ -326,8 +319,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) writer.writeHNT ("CNDT", moved.mTarget, 8); } - refRecord.mIsDeleted = (ref.mState == CSMWorld::RecordBase::State_Deleted); - refRecord.save (writer); + refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted); } } } @@ -366,9 +358,8 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message else record.mCell = record.mId; - record.mIsDeleted = (pathgrid.mState == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, pathgrid.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } @@ -393,10 +384,8 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::Land record = land.get(); - - record.mLand->mIsDeleted = (land.mState == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.mLand->sRecordId); - record.mLand->save (writer); + record.mLand->save (writer, land.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.mLand->sRecordId); } } @@ -421,10 +410,8 @@ void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& mess if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) { CSMWorld::LandTexture record = landTexture.get(); - record.mIsDeleted = (landTexture.mState == CSMWorld::RecordBase::State_Deleted); - writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, landTexture.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index a7d9704b02..64afd0dd8e 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -108,9 +108,8 @@ namespace CSMDoc state == CSMWorld::RecordBase::State_ModifiedOnly || state == CSMWorld::RecordBase::State_Deleted) { - CSMWorld::setRecordDeleted (record, state == CSMWorld::RecordBase::State_Deleted); writer.startRecord (record.sRecordId); - record.save (writer); + record.save (writer, state == CSMWorld::RecordBase::State_Deleted); writer.endRecord (record.sRecordId); } } diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 8816cd35ee..be64061bee 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -3,12 +3,12 @@ #include -void CSMWorld::Cell::load (ESM::ESMReader &esm) +void CSMWorld::Cell::load (ESM::ESMReader &esm, bool &isDeleted) { - ESM::Cell::load (esm, false); + ESM::Cell::load (esm, isDeleted, false); mId = mName; - if (!(mData.mFlags & Interior)) + if (isExterior()) { std::ostringstream stream; stream << "#" << mData.mX << " " << mData.mY; diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index f393e2cf97..160610874c 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 91ccda73cd..32255cb1a0 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -989,9 +989,11 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_DIAL: { ESM::Dialogue record; - record.load (*mReader); + bool isDeleted = false; - if (record.mIsDeleted) + record.load (*mReader, isDeleted); + + if (isDeleted) { // record vector can be shuffled around which would make pointer to record invalid mDialogue = 0; diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp deleted file mode 100644 index 9571ed7734..0000000000 --- a/apps/opencs/model/world/idcollection.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "idcollection.hpp" - - diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 9d3ec990ef..c79b4e020d 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -12,7 +12,7 @@ namespace CSMWorld template > class IdCollection : public Collection { - virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); public: @@ -34,21 +34,24 @@ namespace CSMWorld template void IdCollection::loadRecord (ESXRecordT& record, - ESM::ESMReader& reader) + ESM::ESMReader& reader, + bool& isDeleted) { - record.load (reader); + record.load (reader, isDeleted); } template int IdCollection::load (ESM::ESMReader& reader, bool base) { ESXRecordT record; - loadRecord (record, reader); + bool isDeleted = false; + + loadRecord (record, reader, isDeleted); std::string id = IdAccessorT().getId (record); int index = this->searchId (id); - if (isRecordDeleted(record)) + if (isDeleted) { if (index==-1) { diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 665b497d00..81f3ac143f 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -108,10 +108,12 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vectorload(esm); + mLand->load(esm, isDeleted); std::ostringstream stream; stream << "#" << mLand->mX << " " << mLand->mY; - mId = stream.str(); } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd8..c006f2a4d0 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -20,7 +20,7 @@ namespace CSMWorld std::string mId; /// Loads the metadata and ID - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); void blank(); }; diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4725866a56..9e8dcff9ff 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -4,17 +4,13 @@ namespace CSMWorld { - - void LandTexture::load(ESM::ESMReader &esm) + void LandTexture::load(ESM::ESMReader &esm, bool &isDeleted) { - ESM::LandTexture::load(esm); - + ESM::LandTexture::load(esm, isDeleted); int plugin = esm.getIndex(); std::ostringstream stream; - stream << mIndex << "_" << plugin; - mId = stream.str(); } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index b13903186b..e18f0277c2 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -15,7 +15,7 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/pathgrid.cpp b/apps/opencs/model/world/pathgrid.cpp index 5c66e7d8ea..c995bd8f09 100644 --- a/apps/opencs/model/world/pathgrid.cpp +++ b/apps/opencs/model/world/pathgrid.cpp @@ -4,33 +4,28 @@ #include -void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, const IdCollection& cells) +void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection& cells) { - load (esm); + load (esm, isDeleted); // correct ID if (!mId.empty() && mId[0]!='#' && cells.searchId (mId)==-1) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } } -void CSMWorld::Pathgrid::load (ESM::ESMReader &esm) +void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, bool &isDeleted) { - ESM::Pathgrid::load (esm); + ESM::Pathgrid::load (esm, isDeleted); + mId = mCell; if (mCell.empty()) { std::ostringstream stream; - stream << "#" << mData.mX << " " << mData.mY; - mId = stream.str(); } - else - mId = mCell; } diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7e7b7c3bb6..22d01b0710 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -20,9 +20,8 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm, const IdCollection& cells); - - void load (ESM::ESMReader &esm); + void load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection& cells); + void load (ESM::ESMReader &esm, bool &isDeleted); }; } diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 7563c4cfd9..ef2f4d3202 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -19,51 +19,3 @@ bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } - -template<> -bool CSMWorld::isRecordDeleted(const CSMWorld::Land &land) -{ - return land.mLand->mIsDeleted; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::GameSetting &setting) -{ - return false; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::MagicEffect &effect) -{ - return false; -} - -template<> -bool CSMWorld::isRecordDeleted(const ESM::Skill &skill) -{ - return false; -} - -template<> -void CSMWorld::setRecordDeleted(CSMWorld::Land &land, bool isDeleted) -{ - land.mLand->mIsDeleted = isDeleted; -} - -template<> -void CSMWorld::setRecordDeleted(ESM::GameSetting &setting, bool isDeleted) -{ - // GameSetting doesn't have a Deleted flag -} - -template<> -void CSMWorld::setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted) -{ - // MagicEffect doesn't have a Deleted flag -} - -template<> -void CSMWorld::setRecordDeleted(ESM::Skill &skill, bool isDeleted) -{ - // Skill doesn't have a Deleted flag -} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 8e39cd705e..3362f9f963 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -3,12 +3,6 @@ #include -#include -#include -#include - -#include "land.hpp" - namespace CSMWorld { struct RecordBase @@ -160,39 +154,6 @@ namespace CSMWorld mState = State_Erased; } } - - // Not all records can be deleted (may be changed in the future), - // so we need to use a separate method to check whether a record is deleted or not. - template - bool isRecordDeleted(const ESXRecordT &record) - { - return record.mIsDeleted; - } - - template<> - bool isRecordDeleted(const Land &land); - template<> - bool isRecordDeleted(const ESM::GameSetting &setting); - template<> - bool isRecordDeleted(const ESM::MagicEffect &effect); - template<> - bool isRecordDeleted(const ESM::Skill &skill); - - // ... and also a separate method for setting the deleted flag of a record - template - void setRecordDeleted(ESXRecordT &record, bool isDeleted = false) - { - record.mIsDeleted = isDeleted; - } - - template<> - void setRecordDeleted(Land &land, bool isDeleted); - template<> - void setRecordDeleted(ESM::GameSetting &setting, bool isDeleted); - template<> - void setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted); - template<> - void setRecordDeleted(ESM::Skill &skill, bool isDeleted); } #endif diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index d32f21d0a1..39af9b4087 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -21,9 +21,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CellRef ref; ESM::MovedCellRef mref; + bool isDeleted = false; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, isDeleted, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -79,7 +80,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool break; } - if (ref.mIsDeleted) + if (isDeleted) { if (iter==cache.end()) { diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 195244ba89..0c9239d59c 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -129,7 +129,9 @@ namespace CSMWorld int RefIdDataContainer::load (ESM::ESMReader& reader, bool base) { RecordT record; - record.load(reader); + bool isDeleted = false; + + record.load(reader, isDeleted); int index = 0; int numRecords = static_cast(mContainer.size()); @@ -141,7 +143,7 @@ namespace CSMWorld } } - if (record.mIsDeleted) + if (isDeleted) { if (index == numRecords) { @@ -197,13 +199,12 @@ namespace CSMWorld void RefIdDataContainer::save (int index, ESM::ESMWriter& writer) const { Record record = mContainer.at(index); - RecordT esmRecord = record.get(); if (record.isModified() || record.mState == RecordBase::State_Deleted) { - esmRecord.mIsDeleted = (record.mState == RecordBase::State_Deleted); + RecordT esmRecord = record.get(); writer.startRecord(esmRecord.sRecordId); - esmRecord.save(writer); + esmRecord.save(writer, record.mState == RecordBase::State_Deleted); writer.endRecord(esmRecord.sRecordId); } } diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index df1f8a12ea..496cb06430 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { const IdCollection& mCells; - virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); public: @@ -29,9 +29,10 @@ namespace CSMWorld template void SubCellCollection::loadRecord (ESXRecordT& record, - ESM::ESMReader& reader) + ESM::ESMReader& reader, + bool& isDeleted) { - record.load (reader, mCells); + record.load (reader, isDeleted, mCells); } template From 8243fb2479a18cd47e03e9ffcff87020a9c1446f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 20:47:02 +0300 Subject: [PATCH 0798/1812] Load methods (for ESM records) accept a deleted flag in ESMTool --- apps/esmtool/esmtool.cpp | 14 ++++---- apps/esmtool/record.cpp | 74 ++++++++++++++++++++-------------------- apps/esmtool/record.hpp | 9 +++-- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index c2507ccdc4..be90afec38 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -27,7 +27,8 @@ struct ESMData std::vector masters; std::deque mRecords; - std::map > mCellRefs; + // Value: (Reference, Deleted flag) + std::map > > mCellRefs; std::map mRecordStats; static const std::set sLabeledRec; @@ -251,10 +252,11 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) ESM::CellRef ref; if(!quiet) std::cout << " References:\n"; - while(cell.getNextRef(esm, ref)) + bool deleted = false; + while(cell.getNextRef(esm, ref, deleted)) { if (save) { - info.data.mCellRefs[&cell].push_back(ref); + info.data.mCellRefs[&cell].push_back(std::make_pair(ref, deleted)); } if(quiet) continue; @@ -269,7 +271,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; - std::cout << " Deleted: " << ref.mIsDeleted << std::endl; + std::cout << " Deleted: " << deleted << std::endl; if (!ref.mKey.empty()) std::cout << " Key: '" << ref.mKey << "'" << std::endl; } @@ -497,11 +499,11 @@ int clone(Arguments& info) if (name.val == ESM::REC_CELL) { ESM::Cell *ptr = &record->cast()->get(); if (!info.data.mCellRefs[ptr].empty()) { - typedef std::deque RefList; + typedef std::deque > RefList; RefList &refs = info.data.mCellRefs[ptr]; for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) { - refIt->save(esm); + refIt->first.save(esm, refIt->second); } } } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a033182626..728c5dc91a 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -405,7 +405,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -420,7 +420,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -449,7 +449,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -464,7 +464,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -478,7 +478,7 @@ void Record::print() std::cout << " Part: " << meshPartLabel(mData.mData.mPart) << " (" << (int)mData.mData.mPart << ")" << std::endl; std::cout << " Vampire: " << (int)mData.mData.mVampire << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -507,7 +507,7 @@ void Record::print() { std::cout << " Text: [skipped]" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -519,7 +519,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit) std::cout << " Power: " << *pit << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -548,7 +548,7 @@ void Record::print() std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -571,7 +571,7 @@ void Record::print() for (int i = 0; i != 5; i++) std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -598,7 +598,7 @@ void Record::print() if (pit->mFemale != "") std::cout << " Female Name: " << pit->mFemale << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -614,7 +614,7 @@ void Record::print() for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -681,7 +681,7 @@ void Record::print() std::vector::iterator pit; for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -689,7 +689,7 @@ void Record::print() { std::cout << " Type: " << dialogTypeLabel(mData.mType) << " (" << (int)mData.mType << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? @@ -706,7 +706,7 @@ void Record::print() std::cout << " Script: " << mData.mScript << std::endl; std::cout << " OpenSound: " << mData.mOpenSound << std::endl; std::cout << " CloseSound: " << mData.mCloseSound << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -718,7 +718,7 @@ void Record::print() std::cout << " Charge: " << mData.mData.mCharge << std::endl; std::cout << " AutoCalc: " << mData.mData.mAutocalc << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -752,14 +752,14 @@ void Record::print() std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit) std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> void Record::print() { std::cout << " " << mData.mValue << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -826,7 +826,7 @@ void Record::print() std::cout << " Result Script: [skipped]" << std::endl; } } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -850,7 +850,7 @@ void Record::print() std::cout << " Attribute: " << attributeLabel(mData.mData.mAttributes[i]) << " (" << mData.mData.mAttributes[i] << ")" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -873,7 +873,7 @@ void Record::print() std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; } if (!wasLoaded) mData.unloadData(); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -886,7 +886,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -899,7 +899,7 @@ void Record::print() for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -920,7 +920,7 @@ void Record::print() std::cout << " Duration: " << mData.mData.mTime << std::endl; std::cout << " Radius: " << mData.mData.mRadius << std::endl; std::cout << " Color: " << mData.mData.mColor << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -935,7 +935,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -950,7 +950,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -965,7 +965,7 @@ void Record::print() std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; std::cout << " Uses: " << mData.mData.mUses << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -974,7 +974,7 @@ void Record::print() std::cout << " Id: " << mData.mId << std::endl; std::cout << " Index: " << mData.mIndex << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1025,7 +1025,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Is Key: " << mData.mData.mIsKey << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1112,7 +1112,7 @@ void Record::print() for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) printAIPackage(*pit); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1148,7 +1148,7 @@ void Record::print() i++; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1190,7 +1190,7 @@ void Record::print() for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit) std::cout << " Power: " << *sit << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1251,7 +1251,7 @@ void Record::print() std::cout << " Script: [skipped]" << std::endl; } - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1275,7 +1275,7 @@ void Record::print() std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Type: " << soundTypeLabel(mData.mType) << " (" << mData.mType << ")" << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1286,7 +1286,7 @@ void Record::print() if (mData.mData.mMinRange != 0 && mData.mData.mMaxRange != 0) std::cout << " Range: " << (int)mData.mData.mMinRange << " - " << (int)mData.mData.mMaxRange << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1298,7 +1298,7 @@ void Record::print() std::cout << " Flags: " << spellFlags(mData.mData.mFlags) << std::endl; std::cout << " Cost: " << mData.mData.mCost << std::endl; printEffectList(mData.mEffects); - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1306,7 +1306,7 @@ void Record::print() { std::cout << " Start Script: " << mData.mId << std::endl; std::cout << " Start Data: " << mData.mData << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> @@ -1347,7 +1347,7 @@ void Record::print() if (mData.mData.mThrust[0] != 0 && mData.mData.mThrust[1] != 0) std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" << (int)mData.mData.mThrust[1] << std::endl; - std::cout << " Deleted: " << mData.mIsDeleted << std::endl; + std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index a10fda40b0..d0c113279c 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -67,8 +67,13 @@ namespace EsmTool class Record : public RecordBase { T mData; + bool mIsDeleted; public: + Record() + : mIsDeleted(false) + {} + std::string getId() const { return mData.mId; } @@ -78,11 +83,11 @@ namespace EsmTool } void save(ESM::ESMWriter &esm) { - mData.save(esm); + mData.save(esm, mIsDeleted); } void load(ESM::ESMReader &esm) { - mData.load(esm); + mData.load(esm, mIsDeleted); } void print(); From 0c6ab6cc9449e14fe30d1f9baa3424b92eee9ba8 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 21 Jul 2015 21:49:36 +0300 Subject: [PATCH 0799/1812] Load methods (for ESM records) accept a deleted flag in ESSImporter --- apps/essimporter/converter.cpp | 4 +++- apps/essimporter/converter.hpp | 29 +++++++++++++++++++++------- apps/essimporter/importacdt.cpp | 3 ++- apps/essimporter/importinventory.cpp | 3 ++- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 9827531345..1d1942a3ec 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -158,7 +158,9 @@ namespace ESSImport void ConvertCell::read(ESM::ESMReader &esm) { ESM::Cell cell; - cell.load(esm, false); + bool isDeleted = false; + + cell.load(esm, isDeleted, false); // I wonder what 0x40 does? if (cell.isExterior() && cell.mData.mFlags & 0x20) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 3bb5d2eaed..1c6783539d 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -54,6 +54,8 @@ public: void setContext(Context& context) { mContext = &context; } + /// @note The load method of ESM records accept the deleted flag as a parameter. + /// I don't know can the DELE sub-record appear in saved games, so the deleted flag will be ignored. virtual void read(ESM::ESMReader& esm) { } @@ -79,7 +81,9 @@ public: virtual void read(ESM::ESMReader& esm) { T record; - record.load(esm); + bool isDeleted = false; + + record.load(esm, isDeleted); mRecords[record.mId] = record; } @@ -103,7 +107,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::NPC npc; - npc.load(esm); + bool isDeleted = false; + + npc.load(esm, isDeleted); if (npc.mId != "player") { // Handles changes to the NPC struct, but since there is no index here @@ -139,7 +145,9 @@ public: { // See comment in ConvertNPC ESM::Creature creature; - creature.load(esm); + bool isDeleted = false; + + creature.load(esm, isDeleted); mContext->mCreatures[Misc::StringUtils::lowerCase(creature.mId)] = creature; } }; @@ -154,7 +162,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Global global; - global.load(esm); + bool isDeleted = false; + + global.load(esm, isDeleted); if (Misc::StringUtils::ciEqual(global.mId, "gamehour")) mContext->mHour = global.mValue.getFloat(); if (Misc::StringUtils::ciEqual(global.mId, "day")) @@ -173,8 +183,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Class class_; - class_.load(esm); + bool isDeleted = false; + class_.load(esm, isDeleted); if (class_.mId == "NEWCLASSID_CHARGEN") mContext->mCustomPlayerClassName = class_.mName; @@ -188,7 +199,9 @@ public: virtual void read(ESM::ESMReader &esm) { ESM::Book book; - book.load(esm); + bool isDeleted = false; + + book.load(esm, isDeleted); if (book.mData.mSkillID == -1) mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId)); @@ -365,7 +378,9 @@ public: virtual void read(ESM::ESMReader& esm) { ESM::Faction faction; - faction.load(esm); + bool isDeleted = false; + + faction.load(esm, isDeleted); std::string id = Misc::StringUtils::toLower(faction.mId); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9d881515dd..1602aa784b 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -18,7 +18,8 @@ namespace ESSImport if (esm.isNextSub("MNAM")) esm.skipHSub(); - ESM::CellRef::loadData(esm); + bool isDeleted = false; + ESM::CellRef::loadData(esm, isDeleted); mHasACDT = false; if (esm.isNextSub("ACDT")) diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index d27cd5c8ca..3ec640d3d5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -32,7 +32,8 @@ namespace ESSImport item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too - item.ESM::CellRef::loadData(esm); + bool isDeleted = false; + item.ESM::CellRef::loadData(esm, isDeleted); int charge=-1; esm.getHNOT(charge, "XHLT"); From daaff1284e26d13358b130d7b44721ced210066d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 22 Jul 2015 22:02:01 +0300 Subject: [PATCH 0800/1812] Remove unused includes --- apps/opencs/model/world/idcollection.hpp | 1 - apps/openmw/mwworld/store.cpp | 1 - components/esm/loaddial.hpp | 1 - components/esm/util.hpp | 5 ----- 4 files changed, 8 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index c79b4e020d..ea6eefb882 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,7 +4,6 @@ #include #include "collection.hpp" -#include "record.hpp" namespace CSMWorld { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cd9290bfc8..a8b0af88aa 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index e517fc86f4..b80cbd74c3 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "loadinfo.hpp" diff --git a/components/esm/util.hpp b/components/esm/util.hpp index e16603b84f..a80df2456f 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,14 +1,9 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H -#include - #include #include -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { From 8286dc6c5aaa2f9f5c6c5aff4644f93d9bbdcdb0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:37:19 +0200 Subject: [PATCH 0801/1812] Player followers don't report crimes (Fixes #2457) --- .../mwmechanics/mechanicsmanagerimp.cpp | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e9ef99454c..07fa6d5922 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1049,6 +1049,19 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } + + void getFollowers (const MWWorld::Ptr& actor, std::set& out) + { + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + for(std::list::iterator it = followers.begin();it != followers.end();++it) + { + if (out.insert(*it).second) + { + getFollowers(*it, out); + } + } + } + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware) { // NOTE: victim may be empty @@ -1070,6 +1083,10 @@ namespace MWMechanics if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); + // get the player's followers / allies (works recursively) that will not report crimes + std::set playerFollowers; + getFollowers(player, playerFollowers); + // Did anyone see it? bool crimeSeen = false; for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) @@ -1085,11 +1102,6 @@ namespace MWMechanics // TODO: Add mod support for stealth executions! || (type == OT_Murder && *it != victim)) { - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) - MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); - // Crime reporting only applies to NPCs if (!it->getClass().isNpc()) continue; @@ -1097,6 +1109,14 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); + crimeSeen = true; } } From 7900631d51be62726598bd70177b182b0992783c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:39:22 +0200 Subject: [PATCH 0802/1812] Print the missing player cell to error output --- apps/openmw/mwworld/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b17b8e1f0c..d3c0110ac3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,7 +1,7 @@ - #include "player.hpp" #include +#include #include #include @@ -19,7 +19,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/actors.hpp" #include "class.hpp" #include "ptr.hpp" @@ -327,6 +326,7 @@ namespace MWWorld } catch (...) { + std::cerr << "Player cell '" << player.mCellId.mWorldspace << "' no longer exists" << std::endl; // Cell no longer exists. Place the player in a default cell. ESM::Position pos = mPlayer.mData.getPosition(); MWBase::Environment::get().getWorld()->indexToPosition(0, 0, pos.pos[0], pos.pos[1], true); From 7e4e59efb9640135d2ea265f458cfd1cbb6425d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Jul 2015 02:28:38 +0200 Subject: [PATCH 0803/1812] Fix excessive auto-equipping in InventoryStore::removeItem (Fixes #2792) --- apps/openmw/mwworld/inventorystore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6c283bb3ea..2fe914a4e1 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -490,6 +490,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor { int retCount = ContainerStore::remove(item, count, actor); + bool wasEquipped = false; if (!item.getRefData().getCount()) { for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) @@ -500,6 +501,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor if (*mSlots[slot] == item) { unequipSlot(slot, actor); + wasEquipped = true; break; } } @@ -507,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); From a7b3248ee7a042d4c481c8215ab850cfb9891dc1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 20:35:16 +0300 Subject: [PATCH 0804/1812] Proper sorting of columns with enum values --- apps/opencs/model/world/idtableproxymodel.cpp | 14 ++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 5166447138..1f8f2e4b4e 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -60,6 +60,20 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr(left.data(ColumnBase::Role_ColumnId).toInt()); + EnumColumnCache::const_iterator valuesIt = mEnumColumnCache.find(id); + if (valuesIt == mEnumColumnCache.end()) + { + if (Columns::hasEnums(id)) + { + valuesIt = mEnumColumnCache.insert(std::make_pair(id, Columns::getEnums(id))).first; + } + } + + if (valuesIt != mEnumColumnCache.end()) + { + return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + } return QSortFilterProxyModel::lessThan(left, right); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index d2a2405291..decad157c4 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -11,6 +11,8 @@ #include "../filter/node.hpp" +#include "columns.hpp" + namespace CSMWorld { class IdTableProxyModel : public QSortFilterProxyModel @@ -20,6 +22,11 @@ namespace CSMWorld boost::shared_ptr mFilter; std::map mColumnMap; // column ID, column index in this model (or -1) + // Cache of enum values for enum columns (e.g. Modified, Record Type). + // Used to speed up comparisons during the sort by such columns. + typedef std::map > EnumColumnCache; + mutable EnumColumnCache mEnumColumnCache; + private: void updateColumnMap(); From f5b1447c9226adb89db38ea52b7435d4e2072cc6 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 21:05:00 +0300 Subject: [PATCH 0805/1812] IdTableProxyModel refreshes the filter when the source model data or rows changed --- apps/opencs/model/world/idtableproxymodel.cpp | 28 +++++++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 8 ++++++ apps/opencs/view/world/table.cpp | 4 --- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 1f8f2e4b4e..ce9d44ed67 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -50,6 +50,24 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); } +void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) +{ + QSortFilterProxyModel::setSourceModel(model); + + connect(sourceModel(), + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, + SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); +} + void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) { beginResetModel(); @@ -82,3 +100,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() updateColumnMap(); invalidateFilter(); } + +void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +{ + refreshFilter(); +} + +void CSMWorld::IdTableProxyModel::sourceDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +{ + refreshFilter(); +} diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index decad157c4..17c30361a5 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -37,6 +37,8 @@ namespace CSMWorld virtual QModelIndex getModelIndex (const std::string& id, int column) const; + virtual void setSourceModel(QAbstractItemModel *model); + void setFilter (const boost::shared_ptr& filter); void refreshFilter(); @@ -46,6 +48,12 @@ namespace CSMWorld bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + + private slots: + + void sourceRowsChanged(const QModelIndex &parent, int start, int end); + + void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 74343a5f63..5a2a572e2f 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -653,10 +653,6 @@ void CSVWorld::Table::tableSizeUpdate() } emit tableSizeChanged (size, deleted, modified); - - // not really related to tableSizeUpdate() but placed here for convenience rather than - // creating a bunch of extra connections & slot - mProxyModel->refreshFilter(); } void CSVWorld::Table::selectionSizeUpdate() From 6d2d32485fa051260dfe3643786891d070f21480 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 23 Jul 2015 22:22:22 -0500 Subject: [PATCH 0806/1812] Fix building OpenCS with Qt 5. --- apps/opencs/view/world/scripterrortable.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 3e80c5bd47..415e6c9dca 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -76,8 +76,13 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); +#else horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); +#endif horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setColumnHidden (3, true); From 71bc22401f103532e8ad4eec3b0a8140f60226f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 18:23:23 +0200 Subject: [PATCH 0807/1812] Include cleanup --- apps/openmw/mwworld/actioneat.cpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 6609155236..8bb80b564b 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,8 +1,6 @@ #include "actioneat.hpp" -#include - #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8011f81ce2..15c8cbeb2e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,13 +14,11 @@ #include #include +#include #include #include -#include -#include -#include #include #include From 7f66339790a8f25aedeb610cb792ad043af8caf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 20:23:27 +0200 Subject: [PATCH 0808/1812] Remove a redundant function --- apps/openmw/mwclass/creature.cpp | 26 ++++---------------------- apps/openmw/mwclass/creature.hpp | 2 -- apps/openmw/mwclass/npc.cpp | 25 +++---------------------- apps/openmw/mwclass/npc.hpp | 2 -- apps/openmw/mwmechanics/actors.cpp | 4 +++- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 6 ------ 7 files changed, 10 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index f312a41c7a..8b7bcf6b92 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -394,8 +394,10 @@ namespace MWClass damage = scaleDamage(damage, attacker, ptr); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -430,26 +432,6 @@ namespace MWClass } } - void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 740552a60f..b2a333beb3 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -72,8 +72,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d0dd9f994c..75b612dade 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -733,8 +733,9 @@ namespace MWClass if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -779,26 +780,6 @@ namespace MWClass } } - void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f032ae77cd..b12b7b13fb 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -87,8 +87,6 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 14561b4bb1..c135811dd6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -699,7 +699,9 @@ namespace MWMechanics { // If drowning, apply 3 points of damage per second static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->getFloat(); - ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - fSuffocationDamage*duration); + DynamicStat health = stats.getHealth(); + health.setCurrent(health.getCurrent() - fSuffocationDamage*duration); + stats.setHealth(health); // Play a drowning sound MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5ec2d4e165..180cba3327 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -109,11 +109,6 @@ namespace MWWorld throw std::runtime_error("class cannot be hit"); } - void Class::setActorHealth(const Ptr& ptr, float health, const Ptr& attacker) const - { - throw std::runtime_error("class does not have actor health"); - } - boost::shared_ptr Class::activate (const Ptr& ptr, const Ptr& actor) const { return boost::shared_ptr (new NullAction); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f091380f2..cd05b471b3 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -136,12 +136,6 @@ namespace MWWorld ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield /// (default implementation: throw an exception) - virtual void setActorHealth(const Ptr& ptr, float health, const Ptr& attacker=Ptr()) const; - ///< Sets a new current health value for the actor, optionally specifying the object causing - /// the change. Use this instead of using CreatureStats directly as this will make sure the - /// correct dialog and actor states are properly handled when being hurt or healed. - /// (default implementation: throw an exception) - virtual boost::shared_ptr activate (const Ptr& ptr, const Ptr& actor) const; ///< Generate action for activation (default implementation: return a null action). From 47922f6c35a9f88374ff0f6301b5706f43e3e9af Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Fri, 24 Jul 2015 21:54:58 +0200 Subject: [PATCH 0809/1812] Changed a settings variable responsible for number of loaded exterior cells. --- apps/openmw/mwworld/scene.cpp | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb7733..13e6593e50 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -327,7 +327,7 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); - const int halfGridSize = Settings::Manager::getInt("exterior grid size", "Cells")/2; + const int halfGridSize = Settings::Manager::getInt("exterior cell load distance", "Cells"); CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index dcb9b8893e..0f7349eb9f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -101,7 +101,7 @@ local map widget size = 512 local map hud widget size = 256 [Cells] -exterior grid size = 3 +exterior cell load distance = 1 [Camera] near clip = 5 From 4f6e5345ccd831169bfec8432cebce6f125942a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:36 +0200 Subject: [PATCH 0810/1812] Include cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/manualref.cpp | 1 - apps/openmw/mwworld/player.cpp | 1 - apps/openmw/mwworld/scene.cpp | 5 +---- apps/openmw/mwworld/store.cpp | 1 - 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f879343d9d..fd3f364e94 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -10,7 +10,6 @@ #include "livecellref.hpp" #include "cellreflist.hpp" -#include #include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index b926c57992..d6e40ad09e 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -1,7 +1,6 @@ #include "manualref.hpp" #include "esmstore.hpp" -#include "cellstore.hpp" namespace { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d3c0110ac3..6bfdd29860 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -22,7 +22,6 @@ #include "class.hpp" #include "ptr.hpp" -#include "inventorystore.hpp" #include "cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb7733..1c51d45704 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,15 +1,12 @@ #include "scene.hpp" #include +#include -#include #include #include #include #include -#include - -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index d873ab4686..29187f950d 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,5 +1,4 @@ #include "store.hpp" -#include "esmstore.hpp" #include #include From 3f3c3d0ad354b12309a6f023d8885fee61a3cd50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:43 +0200 Subject: [PATCH 0811/1812] Remove an already resolved todo comment --- apps/openmw/mwworld/inventorystore.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index a60d1f464f..95c16c115e 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -87,7 +87,6 @@ namespace MWWorld float mMultiplier; }; - // TODO: store in savegame typedef std::map > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From e6b28d84f0b58317a73ec6b20964da8bb9f76dfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 00:28:47 +0200 Subject: [PATCH 0812/1812] Outdated comment fix --- apps/openmw/mwmechanics/aicombat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce0..f0bb198a0e 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -20,7 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -#include "character.hpp" // fixme: for getActiveWeapon +#include "character.hpp" #include "aicombataction.hpp" #include "combat.hpp" @@ -291,7 +291,7 @@ namespace MWMechanics // Get weapon characteristics if (actorClass.hasInventoryStore(actor)) { - //Get weapon speed and range + //Get weapon range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); From b3f5ac5dbb227233bb88cd1cc9b7d996abecfc20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 01:48:34 +0200 Subject: [PATCH 0813/1812] Include cleanup --- apps/opencs/model/world/refidadapterimp.hpp | 1 - apps/openmw/mwmechanics/aiactivate.cpp | 1 - apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +-- apps/openmw/mwmechanics/aicombat.cpp | 5 ----- apps/openmw/mwmechanics/aiescort.cpp | 1 - apps/openmw/mwmechanics/aifollow.cpp | 2 -- components/compiler/fileparser.cpp | 2 -- components/esmterrain/storage.cpp | 2 -- components/files/constrainedfilestream.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/nifbullet/bulletnifloader.cpp | 1 - components/sceneutil/attach.cpp | 1 - components/sceneutil/lightmanager.cpp | 5 ++--- components/terrain/material.cpp | 2 -- 14 files changed, 3 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 869996da5b..4066b5646f 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -2,7 +2,6 @@ #define CSM_WOLRD_REFIDADAPTERIMP_H #include -#include #include diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index b0621c8052..8761ca37fa 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -8,7 +8,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 457c9a95ca..b3aa346cee 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -1,10 +1,9 @@ #include "aiavoiddoor.hpp" -#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f0bb198a0e..b2f938b9e3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -5,18 +5,13 @@ #include #include "../mwworld/class.hpp" -#include "../mwworld/timestamp.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwrender/animation.hpp" - #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 593f9f173e..f75fc22ad1 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index a92e9eedc8..8e111be61f 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,7 +1,5 @@ #include "aifollow.hpp" -#include - #include #include "../mwbase/world.hpp" diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 423841ac3e..c8a512340f 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -1,7 +1,5 @@ #include "fileparser.hpp" -#include - #include "tokenloc.hpp" #include "scanner.hpp" diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 1811f58e60..10b75bb741 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 3e5d0c245e..cd9a3c8f57 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,7 +1,6 @@ #include "constrainedfilestream.hpp" #include -#include #include "lowlevelfile.hpp" diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index ea1e9fc912..f5dee0dba3 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -2,7 +2,6 @@ #include "interpreter.hpp" #include -#include #include #include diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index adf961dc25..2496c68cde 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 2432b5eb29..d8cfa428a2 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -1,7 +1,6 @@ #include "attach.hpp" #include -#include #include #include diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 039d556d11..07ec0aff6c 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -1,5 +1,7 @@ #include "lightmanager.hpp" +#include + #include #include @@ -9,9 +11,6 @@ #include -#include -#include - namespace SceneUtil { diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 2034883edd..df45b6ec2a 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,7 +1,5 @@ #include "material.hpp" -#include - #include #include #include From 3bca3e73d439b3202ce86853ad061c68d25c7fbf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 02:11:59 +0200 Subject: [PATCH 0814/1812] Fix GetWeaponDrawn and GetSpellReadied script functions for creatures --- apps/openmw/mwscript/miscextensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8409351aa0..9a9127977a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -567,7 +567,8 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + runtime.push((ptr.getClass().hasInventoryStore(ptr) || ptr.getClass().isBipedal(ptr)) && + ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); } }; @@ -580,7 +581,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); + runtime.push(ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); } }; From 278076e609573ac4c0367a5f4f9d6693c01a2a73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 04:14:22 +0200 Subject: [PATCH 0815/1812] Include cleanup --- apps/openmw/mwmechanics/aifollow.cpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 ++++- apps/openmw/mwmechanics/aipursue.cpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 6 ++---- apps/openmw/mwmechanics/aitravel.cpp | 1 + apps/openmw/mwmechanics/obstacle.cpp | 2 ++ apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwworld/cellstore.hpp | 22 +++++++++++++++++++++- 9 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 8e111be61f..cd67c60582 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,6 +1,7 @@ #include "aifollow.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 0e68d9d79b..77efe62a88 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -1,7 +1,10 @@ - #include "aipackage.hpp" #include + +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index ac6b23ef6b..e936505c93 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -1,12 +1,12 @@ #include "aipursue.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index fb6450d16a..a750860ca9 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -1,6 +1,7 @@ - #include "aisequence.hpp" +#include + #include "aipackage.hpp" #include "aistate.hpp" @@ -14,9 +15,6 @@ #include -#include "../mwworld/class.hpp" -#include "creaturestats.hpp" -#include "npcstats.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index f192bed63f..1585a3007f 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,6 +1,7 @@ #include "aitravel.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d2ab7d3d7..25bd06301f 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,5 +1,7 @@ #include "obstacle.hpp" +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 6ce54a4baa..d307e990a1 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7cad745dd8..b5f141963a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "vismask.hpp" #include "ripplesimulation.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index fd3f364e94..f88bf09587 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -5,12 +5,32 @@ #include #include #include +#include + #include #include "livecellref.hpp" #include "cellreflist.hpp" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld From c088cd4fa9d0286124bf3ad7c553150cdb842bbe Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 25 Jul 2015 17:57:40 +0300 Subject: [PATCH 0816/1812] Proper index creation for nested data --- apps/opencs/model/world/idtree.cpp | 4 ++-- apps/opencs/model/world/nestedtableproxymodel.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 9dbe7e002f..5a7d10c6ec 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -171,10 +171,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par encodedId = this->foldIndexAddress(parent); } - if (row<0 || row>=idCollection()->getSize()) + if (row < 0 || row >= rowCount(parent)) return QModelIndex(); - if (column<0 || column>=idCollection()->getColumns()) + if (column < 0 || column >= columnCount(parent)) return QModelIndex(); return createIndex(row, column, encodedId); // store internal id diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 052e629aac..edcc7a0706 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -75,10 +75,10 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM { assert (!parent.isValid()); - int rows = mMainModel->rowCount(parent); - int columns = mMainModel->columnCount(parent); + int numRows = rowCount(parent); + int numColumns = columnCount(parent); - if (row < 0 || row >= rows || column < 0 || column >= columns) + if (row < 0 || row >= numRows || column < 0 || column >= numColumns) return QModelIndex(); return createIndex(row, column); From e0ee2fc01b3fb8db478bb88e6211065cc775c8e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:22:48 +0200 Subject: [PATCH 0817/1812] Adjust the movement animation speed every frame (Fixes #1921) --- apps/openmw/mwmechanics/character.cpp | 43 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 3 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 50faaa91ba..066489e8ef 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -408,14 +408,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { - float vel, speedmult = 1.0f; - bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !MWBase::Environment::get().getWorld()->isFlying(mPtr); // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // even if we are running. This must be replicated, otherwise the observed speed would differ drastically. std::string anim = mCurrentMovement; + mAdjustMovementAnimSpeed = true; if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() && !(mPtr.get()->mBase->mFlags & ESM::Creature::Flies)) { @@ -423,30 +422,28 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState)); anim = stateinfo->groupname; - if (mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - speedmult = mMovementSpeed / vel; - else + mMovementAnimSpeed = mAnimation->getVelocity(anim); + if (mMovementAnimSpeed <= 1.0f) + { // Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward), // then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist // we will play without any scaling. // Makes the speed attribute of most water creatures totally useless. // And again, this can not be fixed without patching game data. - speedmult = 1.f; + mAdjustMovementAnimSpeed = false; + mMovementAnimSpeed = 1.f; + } } else { - if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - { - speedmult = mMovementSpeed / vel; - } - else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) - speedmult = 1.f; // adjusted each frame - else if (mMovementSpeed > 0.0f) + mMovementAnimSpeed = mAnimation->getVelocity(anim); + + if (mMovementAnimSpeed <= 1.0f) { // The first person anims don't have any velocity to calculate a speed multiplier from. // We use the third person velocities instead. // FIXME: should be pulled from the actual animation, but it is not presently loaded. - speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f); + mMovementAnimSpeed = (isrunning ? 222.857f : 154.064f); mMovementAnimationControlled = false; } } @@ -462,7 +459,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, - speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -655,7 +652,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) - , mMovementSpeed(0.0f) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) @@ -1487,6 +1483,7 @@ void CharacterController::update(float duration) MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = mPtr.getClass(); osg::Vec3f movement(0.f, 0.f, 0.f); + float speed = 0.f; updateMagicEffects(); @@ -1550,10 +1547,10 @@ void CharacterController::update(float duration) vec = osg::Vec3f(0.f, 0.f, 0.f); osg::Vec3f rot = cls.getRotationVector(mPtr); - mMovementSpeed = cls.getSpeed(mPtr); + speed = cls.getSpeed(mPtr); - vec.x() *= mMovementSpeed; - vec.y() *= mMovementSpeed; + vec.x() *= speed; + vec.y() *= speed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -1807,6 +1804,11 @@ void CharacterController::update(float duration) if (duration > 0) mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); } + else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed) + { + float speedmult = speed / mMovementAnimSpeed; + mAnimation->adjustSpeedMult(mCurrentMovement, speedmult); + } if (!mSkipAnim) { @@ -1845,7 +1847,7 @@ void CharacterController::update(float duration) moved = osg::Vec3f(0.f, 0.f, 0.f); // Ensure we're moving in generally the right direction... - if(mMovementSpeed > 0.f) + if(speed > 0.f) { float l = moved.length(); @@ -1927,7 +1929,6 @@ void CharacterController::clearAnimQueue() mAnimQueue.clear(); } - void CharacterController::forceStateUpdate() { if(!mAnimation) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f37afd996a..1f9b524e51 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -150,7 +150,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener CharacterState mMovementState; std::string mCurrentMovement; - float mMovementSpeed; + float mMovementAnimSpeed; + bool mAdjustMovementAnimSpeed; bool mHasMovedInXY; bool mMovementAnimationControlled; From 41996b0aad06bd402b69f40b1855bec927c87ba4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:59:16 +0200 Subject: [PATCH 0818/1812] Don't play turning animations in first person mode --- apps/openmw/mwmechanics/character.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 066489e8ef..cf8b0284e5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -448,17 +448,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); - if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) - && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() - && MWBase::Environment::get().getWorld()->isFirstPerson()) - { - priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; - } - - mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -1741,10 +1731,7 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot. - // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon, - // but I don't think we need to go as far as that. - else if(rot.z() != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) + else if(rot.z() != 0.0f && !inwater && !sneak && !MWBase::Environment::get().getWorld()->isFirstPerson()) { if(rot.z() > 0.0f) movestate = CharState_TurnRight; From aba72258173db213bdccc82682ca1938a88d7559 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 11:15:21 +1200 Subject: [PATCH 0819/1812] Removed some duplicated operations. --- apps/openmw/mwmechanics/aicombat.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce0..bdd09a1a8f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,13 +181,15 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); + const MWWorld::Class& actorClass = actor.getClass(); //General description - if(actor.getClass().getCreatureStats(actor).isDead()) + if (actorClass.getCreatureStats(actor).isDead()) return true; - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -196,9 +198,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - //Update every frame bool& combatMove = storage.mCombatMove; From dff84adf7e254c819943104d870d59a8e55d924d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Jul 2015 01:35:36 +0200 Subject: [PATCH 0820/1812] Fix weapon animation priority --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf8b0284e5..9d5f7137f9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1052,7 +1052,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1f9b524e51..d647cae229 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -28,6 +28,7 @@ class CreatureStats; enum Priority { Priority_Default, + Priority_WeaponLowerBody, Priority_Jump, Priority_Movement, Priority_Hit, From b3d5b47fea3b949d632f9168dd8cd5f273dc8b00 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:23:45 +1200 Subject: [PATCH 0821/1812] extracted function UpdateActorsMovement(). --- apps/openmw/mwmechanics/aicombat.cpp | 37 ++++++++++++++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bdd09a1a8f..1beb0024cd 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -214,20 +214,8 @@ namespace MWMechanics } } - actorClass.getMovementSettings(actor) = movement; - actorClass.getMovementSettings(actor).mRotation[0] = 0; - actorClass.getMovementSettings(actor).mRotation[2] = 0; + UpdateActorsMovement(actor, movement); - if(movement.mRotation[2] != 0) - { - if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; - } - - if(movement.mRotation[0] != 0) - { - if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; - } - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; @@ -579,6 +567,29 @@ namespace MWMechanics return false; } + void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + { + MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } + + void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) + { + actorMovementSettings.mRotation[axis] = 0; + float& targetAngleRadians = desiredMovement.mRotation[axis]; + if (targetAngleRadians != 0) + { + if (smoothTurn(actor, targetAngleRadians, axis)) + { + // actor now facing desired direction, no need to turn any more + targetAngleRadians = 0; + } + } + } + bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { if (!mPathFinder.getPath().empty()) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 083f233849..c81ad0544a 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -60,6 +60,11 @@ namespace MWMechanics void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Transfer desired movement (from AiCombatStorage) to Actor + void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 5ec310dfbab45a6952cb8fcb94b64f6f8b364a7f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:24:33 +1200 Subject: [PATCH 0822/1812] extract function onIdleStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 68 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 5c9949a5a3..8b05299a44 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -195,18 +195,10 @@ namespace MWMechanics WanderState& wanderState = storage.mState; - // Check if an idle actor is too close to a door - if so start walking - mDoorCheckDuration += duration; - if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + + if (wanderState == Wander_IdleNow) { - mDoorCheckDuration = 0; // restart timer - if(mDistance && // actor is not intended to be stationary - (wanderState == Wander_IdleNow) && // but is in idle - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only - { - wanderState = Wander_MoveNow; - mTrimCurrentNode = false; // just in case - } + onIdleStatePerFrameActions(actor, duration, storage); } // Are we there yet? @@ -229,29 +221,11 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; - if (rotate) - { - // Reduce the turning animation glitch by using a *HUGE* value of - // epsilon... TODO: a proper fix might be in either the physics or the - // animation subsystem - if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) - rotate = false; - } - - // Check if idle animation finished - short unsigned& idleAnimation = storage.mIdleAnimation; - GreetingState& greetingState = storage.mSaidGreeting; - if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) - { - wanderState = Wander_ChooseAction; - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) { + short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); if(!idleAnimation && mDistance) @@ -355,6 +329,40 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) + { + // Check if an idle actor is too close to a door - if so start walking + mDoorCheckDuration += duration; + if (mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + { + mDoorCheckDuration = 0; // restart timer + if (mDistance && // actor is not intended to be stationary + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + { + storage.mState = Wander_MoveNow; + mTrimCurrentNode = false; // just in case + return; + } + } + + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; + if (rotate) + { + // Reduce the turning animation glitch by using a *HUGE* value of + // epsilon... TODO: a proper fix might be in either the physics or the + // animation subsystem + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) + rotate = false; + } + + // Check if idle animation finished + GreetingState& greetingState = storage.mSaidGreeting; + if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) + { + storage.mState = Wander_ChooseAction; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d1dab3f50e..92af5b7178 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,6 +83,7 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 76f95eafe7c4db0ecb7a223465c5d010d2be0742 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:00 +1200 Subject: [PATCH 0823/1812] extract function onWalkingStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8b05299a44..77cd9e1375 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,26 +201,11 @@ namespace MWMechanics onIdleStatePerFrameActions(actor, duration, storage); } - // Are we there yet? - if ((wanderState == Wander_Walking) && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + if (wanderState == Wander_Walking) { - stopWalking(actor, storage); - wanderState = Wander_ChooseAction; - mHasReturnPosition = false; + onWalkingStatePerFrameActions(actor, duration, storage, pos); } - - - if (wanderState == Wander_Walking) // have not yet reached the destination - { - // turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) @@ -363,6 +348,27 @@ namespace MWMechanics } } + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + float duration, AiWanderStorage& storage, ESM::Position& pos) + { + // Are we there yet? + if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + { + stopWalking(actor, storage); + storage.mState = Wander_ChooseAction; + mHasReturnPosition = false; + } + else + { + // have not yet reached the destination + //... turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + + evadeObstacles(actor, storage, duration); + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 92af5b7178..4750df1dc5 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -84,6 +84,7 @@ namespace MWMechanics void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); + void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 9c0e3d6c28bd66717d8cd385e5e9099a1a01ad56 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:44 +1200 Subject: [PATCH 0824/1812] extracted functions doPerFrameActionsForState() and onChooseActionStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 85 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 + 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 77cd9e1375..e6d7d44225 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -193,39 +193,7 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - - WanderState& wanderState = storage.mState; - - if (wanderState == Wander_IdleNow) - { - onIdleStatePerFrameActions(actor, duration, storage); - } - - if (wanderState == Wander_Walking) - { - onWalkingStatePerFrameActions(actor, duration, storage, pos); - } - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - if (wanderState == Wander_ChooseAction) - { - short unsigned& idleAnimation = storage.mIdleAnimation; - idleAnimation = getRandomIdle(); - - if(!idleAnimation && mDistance) - { - wanderState = Wander_MoveNow; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, idleAnimation); - wanderState = Wander_IdleNow; - } - } + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -243,7 +211,7 @@ namespace MWMechanics if(mDuration) { // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { @@ -288,12 +256,13 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - wanderState = Wander_Walking; + storage.mState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting + WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); @@ -314,6 +283,32 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) + { + switch (storage.mState) + { + case Wander_IdleNow: + onIdleStatePerFrameActions(actor, duration, storage); + break; + + case Wander_Walking: + onWalkingStatePerFrameActions(actor, duration, storage, pos); + break; + + case Wander_ChooseAction: + onChooseActionStatePerFrameActions(actor, storage); + break; + + case Wander_MoveNow: + break; // nothing to do + + default: + // should never get here + assert(false); + break; + } + } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) { // Check if an idle actor is too close to a door - if so start walking @@ -369,6 +364,26 @@ namespace MWMechanics } } + void AiWander::onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + + short unsigned& idleAnimation = storage.mIdleAnimation; + idleAnimation = getRandomIdle(); + + if (!idleAnimation && mDistance) + { + storage.mState = Wander_MoveNow; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, idleAnimation); + storage.mState = Wander_IdleNow; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4750df1dc5..9b21415c4e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,8 +83,10 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); + void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ad0d8071037d4fda4e8b5151f5e6c9ec561d9af3 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:28:32 +1200 Subject: [PATCH 0825/1812] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e6d7d44225..228f4b32d1 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -199,15 +199,18 @@ namespace MWMechanics float& lastReaction = storage.mReaction; lastReaction += duration; - if(lastReaction < REACTION_INTERVAL) + if (REACTION_INTERVAL <= lastReaction) { - return false; + lastReaction = 0; + return reactionTimeActions(actor, storage, currentCell, cellChange, pos); } else - lastReaction = 0; - - // NOTE: everything below get updated every REACTION_INTERVAL seconds + return false; + } + bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) + { if(mDuration) { // End package if duration is complete or mid-night hits: diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b21415c4e..3468c212d4 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -87,6 +87,8 @@ namespace MWMechanics void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); + bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 5e519ef550abbceda13d501cccb83d07d1f1dba8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:01 +1200 Subject: [PATCH 0826/1812] extract function isPackageFinished(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 228f4b32d1..ff26bc116c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -211,21 +211,9 @@ namespace MWMechanics bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) { - if(mDuration) + if (isPackageCompleted(actor, storage)) { - // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || - (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } + return true; } // Initialization to discover & store allowed node points for this actor. @@ -286,6 +274,30 @@ namespace MWMechanics return false; // AiWander package not yet completed } + bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + if (mDuration) + { + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if ((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) + { + if (!mRepeat) + { + stopWalking(actor, storage); + return true; + } + else + { + mStartTime = currentTime; + } + } + } + // if get here, not yet completed + return false; + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3468c212d4..2364ac5430 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -89,6 +89,7 @@ namespace MWMechanics void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); + bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From c7aacaee706a9226ff947a038cdbae519920e708 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:32 +1200 Subject: [PATCH 0827/1812] extracted function returnToStartLocation(). --- apps/openmw/mwmechanics/aiwander.cpp | 38 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ff26bc116c..e230998eb5 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -233,23 +233,10 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) + if (mDistance == 0 && mHasReturnPosition + && (pos.asVec3() - mReturnPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) { - if (!storage.mPathFinder.isPathConstructed()) - { - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) - { - storage.mState = Wander_Walking; - } - } + returnToStartLocation(actor, storage, pos); } // Allow interrupting a walking actor to trigger a greeting @@ -298,6 +285,25 @@ namespace MWMechanics return false; } + void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) + { + if (!storage.mPathFinder.isPathConstructed()) + { + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + storage.mState = Wander_Walking; + } + } + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 2364ac5430..8a489c783c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -90,6 +90,7 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 04aee1fe20a1d742292ac09d0c162dc9a30c3de2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:32:29 +1200 Subject: [PATCH 0828/1812] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1beb0024cd..fc1c31c26d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -45,6 +45,7 @@ namespace return -std::asin(dir.z() / len); } + const float REACTION_INTERVAL = 0.25f; const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid @@ -181,15 +182,11 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); - const MWWorld::Class& actorClass = actor.getClass(); - - //General description - if (actorClass.getCreatureStats(actor).isDead()) + if (actor.getClass().getCreatureStats(actor).isDead()) return true; - MWBase::World* world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -217,8 +214,6 @@ namespace MWMechanics UpdateActorsMovement(actor, movement); bool& attack = storage.mAttack; - bool& readyToAttack = storage.mReadyToAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; @@ -228,14 +223,22 @@ namespace MWMechanics actionCooldown -= duration; float& timerReact = storage.mTimerReact; - float tReaction = 0.25f; - if(timerReact < tReaction) + if(timerReact < REACTION_INTERVAL) { timerReact += duration; return false; } + else + { + timerReact = 0; + return reactionTimeActions(actor, characterController, storage, target); + } + } - //Update with period = tReaction + bool AiCombat::reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target) + { + MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 @@ -245,7 +248,6 @@ namespace MWMechanics return false; // TODO: run away instead of doing nothing } - timerReact = 0; const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); if(!currentCell || cellChange) @@ -253,8 +255,10 @@ namespace MWMechanics currentCell = actor.getCell(); } + const MWWorld::Class& actorClass = actor.getClass(); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + float& actionCooldown = storage.mActionCooldown; if (actionCooldown > 0) return false; @@ -276,6 +280,7 @@ namespace MWMechanics float weapRange = 1.0f; // Get weapon characteristics + MWBase::World* world = MWBase::Environment::get().getWorld(); if (actorClass.hasInventoryStore(actor)) { //Get weapon speed and range @@ -326,13 +331,14 @@ namespace MWMechanics float& strength = storage.mStrength; + bool& readyToAttack = storage.mReadyToAttack; // start new attack if(readyToAttack && characterController.readyToStartAttack()) { if (storage.mAttackCooldown <= 0) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); + storage.mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); if (!distantCombat) chooseBestAttack(weapon, movement); @@ -356,7 +362,7 @@ namespace MWMechanics storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } else - storage.mAttackCooldown -= tReaction; + storage.mAttackCooldown -= REACTION_INTERVAL; } @@ -400,7 +406,7 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * tReaction / 2) + if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * REACTION_INTERVAL / 2) isStuck = true; lastActorPos = vActorPos; @@ -437,7 +443,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -458,8 +464,8 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) @@ -468,8 +474,8 @@ namespace MWMechanics if (Misc::Rng::rollClosedProbability() < 0.25) { movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } } @@ -497,7 +503,7 @@ namespace MWMechanics { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } @@ -558,8 +564,8 @@ namespace MWMechanics if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - combatMove = true; - timerCombatMove = 0; + storage.mCombatMove = true; + storage.mTimerCombatMove = 0; } readyToAttack = false; } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index c81ad0544a..4e40608196 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -26,6 +26,8 @@ namespace MWMechanics { class Action; + struct AiCombatStorage; + /// \brief Causes the actor to fight another actor class AiCombat : public AiPackage { @@ -58,8 +60,9 @@ namespace MWMechanics int mTargetActorId; - void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + bool reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); From 6a1e1a07cbb52250cdd6b0c73c574e3f98b55862 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Jul 2015 11:02:22 +0200 Subject: [PATCH 0829/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index def0b2b896..291b0d56c7 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) + pkubik Radu-Marius Popovici (rpopovici) rdimesio riothamus From 9a8ca819073e54406daafd04319299429c089c4e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 13:54:36 +0300 Subject: [PATCH 0830/1812] Fix missing break in switch statement --- components/esm/loadregn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index b04e6ee3b0..add821c3e8 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -22,7 +22,6 @@ namespace ESM mId = esm.getHString(); hasName = true; break; - break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; @@ -69,6 +68,7 @@ namespace ESM case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); isDeleted = true; + break; default: esm.fail("Unknown subrecord"); break; From 37fd733debc8c8d98220a6a920b14328ec5ab038 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:06:30 +0300 Subject: [PATCH 0831/1812] Create a custom signal to inform about a row addition in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 53 ++++++++++++------- apps/opencs/model/world/idtableproxymodel.hpp | 20 +++++-- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index ce9d44ed67..8beccd4973 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -7,23 +7,23 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() { - mColumnMap.clear(); + Q_ASSERT(mSourceModel != NULL); + mColumnMap.clear(); if (mFilter) { std::vector columns = mFilter->getReferencedColumns(); - - const IdTableBase& table = dynamic_cast (*sourceModel()); - for (std::vector::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) - mColumnMap.insert (std::make_pair (*iter, - table.searchColumnIndex (static_cast (*iter)))); + mColumnMap.insert (std::make_pair (*iter, + mSourceModel->searchColumnIndex (static_cast (*iter)))); } } bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { + Q_ASSERT(mSourceModel != NULL); + // It is not possible to use filterAcceptsColumn() and check for // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) // because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can @@ -35,34 +35,37 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI if (!mFilter) return true; - return mFilter->test ( - dynamic_cast (*sourceModel()), sourceRow, mColumnMap); + return mFilter->test (*mSourceModel, sourceRow, mColumnMap); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) -: QSortFilterProxyModel (parent) + : QSortFilterProxyModel (parent), + mSourceModel(NULL) { setSortCaseSensitivity (Qt::CaseInsensitive); } QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { - return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); + Q_ASSERT(mSourceModel != NULL); + + return mapFromSource(mSourceModel->getModelIndex (id, column)); } void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) { QSortFilterProxyModel::setSourceModel(model); - connect(sourceModel(), - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + mSourceModel = dynamic_cast(sourceModel()); + connect(mSourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + SLOT(sourceRowsInserted(const QModelIndex &, int, int))); + connect(mSourceModel, + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); + connect(mSourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); @@ -95,13 +98,27 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel return QSortFilterProxyModel::lessThan(left, right); } +QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const +{ + Q_ASSERT(mSourceModel != NULL); + + int idColumn = mSourceModel->findColumnIndex(Columns::ColumnId_Id); + return mSourceModel->data(mSourceModel->index(sourceRow, idColumn)).toString(); +} + void CSMWorld::IdTableProxyModel::refreshFilter() { updateColumnMap(); invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +{ + refreshFilter(); + emit rowAdded(getRecordId(end).toUtf8().constData()); +} + +void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { refreshFilter(); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 17c30361a5..cf31b5c11b 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -27,6 +27,10 @@ namespace CSMWorld typedef std::map > EnumColumnCache; mutable EnumColumnCache mEnumColumnCache; + protected: + + IdTableBase *mSourceModel; + private: void updateColumnMap(); @@ -45,15 +49,23 @@ namespace CSMWorld protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - private slots: + QString getRecordId(int sourceRow) const; - void sourceRowsChanged(const QModelIndex &parent, int start, int end); + protected slots: - void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + + signals: + + void rowAdded(const std::string &id); }; } From 86b7d2a43d2842eaab0938afbab699dcce4684e0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:07:36 +0300 Subject: [PATCH 0832/1812] Inform about a row addition after re-sorting in InfoTableProxyModel --- .../model/world/infotableproxymodel.cpp | 56 ++++++++++++++----- .../model/world/infotableproxymodel.hpp | 12 ++-- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 6216291d07..c6216ba5d8 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,16 +9,17 @@ namespace { QString toLower(const QString &str) { - return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toUtf8().constData()).c_str()); } } CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mSourceModel(NULL), mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : - Columns::ColumnId_Journal) + Columns::ColumnId_Journal), + mInfoColumnIndex(-1), + mLastAddedSourceRow(-1) { Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); } @@ -26,23 +27,18 @@ CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type t void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { IdTableProxyModel::setSourceModel(sourceModel); - mSourceModel = dynamic_cast(sourceModel); + if (mSourceModel != NULL) { - connect(mSourceModel, - SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); - connect(mSourceModel, - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); + mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId); mFirstRowCache.clear(); } } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { + Q_ASSERT(mSourceModel != NULL); + QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); @@ -56,8 +52,10 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { + Q_ASSERT(mSourceModel != NULL); + int row = currentRow; - int column = mSourceModel->findColumnIndex(mInfoColumnId); + int column = mInfoColumnIndex; QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); if (mFirstRowCache.contains(info)) @@ -73,7 +71,37 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const return row; } -void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { + refreshFilter(); mFirstRowCache.clear(); } + +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +{ + refreshFilter(); + mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; +} + +void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + refreshFilter(); + + if (mLastAddedSourceRow != -1 && + topLeft.row() <= mLastAddedSourceRow && bottomRight.row() >= mLastAddedSourceRow) + { + // Now the topic of the last added row is set, + // so we can re-sort the model to ensure the corrent position of this row + int column = sortColumn(); + Qt::SortOrder order = sortOrder(); + sort(mInfoColumnIndex); // Restore the correct position of an added row + sort(column, order); // Restore the original sort order + emit rowAdded(getRecordId(mLastAddedSourceRow).toUtf8().constData()); + + // Make sure that we perform a re-sorting only in the first dataChanged() after a row insertion + mLastAddedSourceRow = -1; + } +} diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 28d6017b31..51d93f9a16 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -16,25 +16,29 @@ namespace CSMWorld Q_OBJECT UniversalId::Type mType; - IdTableBase *mSourceModel; Columns::ColumnId mInfoColumnId; ///< Contains ID for Topic or Journal ID + int mInfoColumnIndex; + int mLastAddedSourceRow; mutable QHash mFirstRowCache; int getFirstInfoRow(int currentRow) const; ///< Finds the first row with the same topic (journal entry) as in \a currentRow + ///< \a currentRow is a row of the source model. public: InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0); - void setSourceModel(QAbstractItemModel *sourceModel); + virtual void setSourceModel(QAbstractItemModel *sourceModel); protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - private slots: - void modelRowsChanged(const QModelIndex &parent, int start, int end); + protected slots: + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } From 2471e4d67a343ef8f64eb324feb08c8629f9d673 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:09:31 +0300 Subject: [PATCH 0833/1812] Rework Table to use rowAdded() signal of a proxy model --- apps/opencs/view/world/table.cpp | 11 +++++++---- apps/opencs/view/world/table.hpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 5a2a572e2f..02a9bb07ff 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -371,8 +371,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); - connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), + this, SLOT (rowAdded (const std::string &))); /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) @@ -714,12 +716,13 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const return idToDrag; } -void CSVWorld::Table::rowsInsertedEvent(const QModelIndex& parent, int start, int end) +void CSVWorld::Table::rowAdded(const std::string &id) { tableSizeUpdate(); if(mJumpToAddedRecord) { - selectRow(end); + int idColumn = mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + selectRow(mProxyModel->getModelIndex(id, idColumn).row()); if(mUnselectAfterJump) clearSelection(); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index adacd3a9d7..7ddeff0a58 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -140,7 +140,7 @@ namespace CSVWorld void updateUserSetting (const QString &name, const QStringList &list); - void rowsInsertedEvent(const QModelIndex& parent, int start, int end); + void rowAdded(const std::string &id); }; } From 812fffbadcc4ef8c69cf7382ab0e4c8939a8ef9f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:25:46 +0300 Subject: [PATCH 0834/1812] Don't inform about a nested row addition in proxy models for top-level tables --- apps/opencs/model/world/idtableproxymodel.cpp | 7 +++++-- apps/opencs/model/world/infotableproxymodel.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 8beccd4973..10fd92b46a 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -112,10 +112,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - emit rowAdded(getRecordId(end).toUtf8().constData()); + if (!parent.isValid()) + { + emit rowAdded(getRecordId(end).toUtf8().constData()); + } } void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index c6216ba5d8..f55f775ab3 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -77,13 +77,17 @@ void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*paren mFirstRowCache.clear(); } -void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - mFirstRowCache.clear(); - // We can't re-sort the model here, because the topic of the added row isn't set yet. - // Store the row index for using in the first dataChanged() after this row insertion. - mLastAddedSourceRow = end; + + if (!parent.isValid()) + { + mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; + } } void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) From ac1f64b5593f742fe34017dd07077a6c0da71956 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 03:20:18 +0200 Subject: [PATCH 0835/1812] Fix StencilProperty front face mixup (Fixes #2802) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b5439afeed..6824c0afd0 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1159,11 +1159,11 @@ namespace NifOsg osg::FrontFace* frontFace = new osg::FrontFace; switch (stencilprop->data.drawMode) { - case 1: + case 2: frontFace->setMode(osg::FrontFace::CLOCKWISE); break; case 0: - case 2: + case 1: default: frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); break; From 26656707dd16a0ffd1be105ce3b34cdb0d55b8c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 22:59:20 +0200 Subject: [PATCH 0836/1812] Use marker_error.nif as replacement when a mesh fails to load --- components/resource/scenemanager.cpp | 15 ++++++++++++--- components/resource/scenemanager.hpp | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index efaccec133..08fa7bc9b3 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -100,11 +100,20 @@ namespace Resource Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - Files::IStreamPtr file = mVFS->get(normalized); - // TODO: add support for non-NIF formats + osg::ref_ptr loaded; + try + { + Files::IStreamPtr file = mVFS->get(normalized); - osg::ref_ptr loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } + catch (std::exception& e) + { + std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; + Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); // TODO: run SharedStateManager::prune on unload diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 1dabe45e00..168247a156 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -38,12 +38,16 @@ namespace Resource ~SceneManager(); /// Get a read-only copy of this scene "template" + /// @note If the given filename does not exist or fails to load, an error marker mesh will be used instead. + /// If even the error marker mesh can not be found, an exception is thrown. osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name); /// Create an instance of the given scene template and immediately attach it to a parent node + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); /// Attach the given scene instance to the given parent node From 7ba399fc92fd676a0c1f896fa9521c4d9acdea8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 23:19:35 +0200 Subject: [PATCH 0837/1812] Change a message to upper case spelling More consistent with other loading messages --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 9ffc4071d5..48e346c145 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -233,7 +233,7 @@ namespace MWWorld if(result.second) { - std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + std::cout << "Loading cell " << cell->getCell()->getDescription() << std::endl; float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; From 2a653e45fd443fa58702f3505115aad713a00018 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 21 Jul 2015 22:08:37 -0400 Subject: [PATCH 0838/1812] (Re) Wrote a tool to test NIF files in BSAs and on the filesystem. Just give it a set of files, one file per argument, and it will make sure openmw can read them. --- CMakeLists.txt | 8 ++++ apps/niftest/CMakeLists.txt | 19 ++++++++ apps/niftest/find_bad_nifs.sh | 28 +++++++++++ apps/niftest/niftest.cpp | 87 +++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 apps/niftest/CMakeLists.txt create mode 100755 apps/niftest/find_bad_nifs.sh create mode 100644 apps/niftest/niftest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 656602b9e3..a14beb4235 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment @@ -396,6 +397,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) + IF(BUILD_NIFTEST) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_NIFTEST) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-iniimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) @@ -581,6 +585,10 @@ if (BUILD_WIZARD) add_subdirectory(apps/wizard) endif() +if (BUILD_NIFTEST) + add_subdirectory(apps/niftest) +endif(BUILD_NIFTEST) + # UnitTests if (BUILD_UNITTESTS) add_subdirectory( apps/openmw_test_suite ) diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt new file mode 100644 index 0000000000..d7f0200d2a --- /dev/null +++ b/apps/niftest/CMakeLists.txt @@ -0,0 +1,19 @@ +set(NIFTEST + niftest.cpp +) +source_group(components\\nif\\tests FILES ${NIFTEST}) + +# Main executable +add_executable(niftest + ${NIFTEST} +) + +target_link_libraries(niftest + ${Boost_FILESYSTEM_LIBRARY} + components +) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(niftest gcov) +endif() diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh new file mode 100755 index 0000000000..4b599f4427 --- /dev/null +++ b/apps/niftest/find_bad_nifs.sh @@ -0,0 +1,28 @@ +#!/bin/bash +#Script to test all nif files (both loose, and in BSA archives) in data files directory + +#The user input as an absolute path +DATAFILESDIR="`readlink -m "$1"`" +#Program used to test +TEST_PROG="`pwd`/niftest" + +#Make sure our files don't bother anyone +NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" +mkdir "$NIFTEST_TMP_DIR" +cd "$NIFTEST_TMP_DIR" + +find "$DATAFILESDIR" -iname *bsa > nifs.txt +find "$DATAFILESDIR" -iname *nif >> nifs.txt + +sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt + +xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt +# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null + +echo "List of bad NIF Files:" +cat nif_out.txt|grep File:|cut -d ' ' -f 2- + +rm nifs.txt +rm quoted_nifs.txt +rm nif_out.txt +rmdir "$NIFTEST_TMP_DIR" diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp new file mode 100644 index 0000000000..20c8597f3d --- /dev/null +++ b/apps/niftest/niftest.cpp @@ -0,0 +1,87 @@ +///Program to test .nif files both on the FileSystem and in BSA archives. + +#include +#include + +#include +#include +#include +#include + + +///See if the file has the named extension +bool hasExtension(std::string filename, std::string extensionToFind) +{ + std::string extension = filename.substr(filename.find_last_of(".")+1); + + //Convert strings to lower case for comparison + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower); + + if(extension == extensionToFind) + return true; + else + return false; +} + +///See if the file has the "nif" extension. +bool isNIF(std::string filename) +{ + return hasExtension(filename,"nif"); +} +///See if the file has the "bsa" extension. +bool isBSA(std::string filename) +{ + return hasExtension(filename,"bsa"); +} + +///Check all the nif files in the given BSA archive +void readBSA(std::string filename) +{ + VFS::Manager myManager(false); + myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.buildIndex(); + + std::map files=myManager.getIndex(); + for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = it->first; + if(isNIF(name)) + { +// std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } +} + +int main(int argc, char **argv) +{ + + std::cout << "Reading Files" << std::endl; + for(int i = 1; i Date: Tue, 28 Jul 2015 15:04:22 +0300 Subject: [PATCH 0839/1812] Make saving of deleted ESM records more consistent --- components/esm/cellref.cpp | 67 +++++++++++++++++-------------------- components/esm/cellref.hpp | 3 -- components/esm/loadbsgn.cpp | 5 +-- components/esm/loadcell.cpp | 18 ++++------ components/esm/loadland.cpp | 1 + components/esm/loadltex.cpp | 8 ++--- components/esm/loadpgrd.cpp | 12 +++---- components/esm/loadregn.cpp | 4 ++- components/esm/loadscpt.cpp | 1 + components/esm/loadsndg.cpp | 11 +++--- components/esm/loadsscr.cpp | 20 ++++++----- 11 files changed, 71 insertions(+), 79 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 9a0c8f1cc6..7cd8186bde 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -25,33 +25,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const } -void ESM::CellRef::clearData() -{ - mScale = 1; - mOwner.clear(); - mGlobalVariable.clear(); - mSoul.clear(); - mFaction.clear(); - mFactionRank = -2; - mChargeInt = -1; - mEnchantmentCharge = -1; - mGoldValue = 0; - mDestCell.clear(); - mLockLevel = 0; - mKey.clear(); - mTrap.clear(); - mReferenceBlocked = -1; - mTeleport = false; - - for (int i=0; i<3; ++i) - { - mDoorDest.pos[i] = 0; - mDoorDest.rot[i] = 0; - mPos.pos[i] = 0; - mPos.rot[i] = 0; - } -} - void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, bool wideRefNum) { loadId(esm, wideRefNum); @@ -67,6 +40,8 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) if (esm.isNextSub ("NAM0")) esm.skipHSub(); + blank(); + mRefNum.load (esm, wideRefNum); mRefID = esm.getHNString ("NAME"); @@ -76,8 +51,6 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) { isDeleted = false; - clearData(); - bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { @@ -154,6 +127,11 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool esm.writeHNCString("NAME", mRefID); + if (isDeleted) { + esm.writeHNCString("DELE", ""); + return; + } + if (mScale != 1.0) { esm.writeHNT("XSCL", mScale); } @@ -198,18 +176,35 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool if (!inInventory) esm.writeHNT("DATA", mPos, 24); - - if (isDeleted) - { - esm.writeHNCString("DELE", ""); - } } void ESM::CellRef::blank() { mRefNum.unset(); - mRefID.clear(); - clearData(); + mRefID.clear(); + mScale = 1; + mOwner.clear(); + mGlobalVariable.clear(); + mSoul.clear(); + mFaction.clear(); + mFactionRank = -2; + mChargeInt = -1; + mEnchantmentCharge = -1; + mGoldValue = 0; + mDestCell.clear(); + mLockLevel = 0; + mKey.clear(); + mTrap.clear(); + mReferenceBlocked = -1; + mTeleport = false; + + for (int i=0; i<3; ++i) + { + mDoorDest.pos[i] = 0; + mDoorDest.rot[i] = 0; + mPos.pos[i] = 0; + mPos.rot[i] = 0; + } } bool ESM::operator== (const RefNum& left, const RefNum& right) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index a9edd291e0..c371a4f015 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -33,10 +33,7 @@ namespace ESM class CellRef { - void clearData(); - public: - // Reference number // Note: Currently unused for items in containers RefNum mRefNum; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 56dc1897cf..0413a86104 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -52,12 +52,13 @@ namespace ESM void BirthSign::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - - esm.writeHNCString("NAME", mId); esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("TNAM", mTexture); esm.writeHNOCString("DESC", mDescription); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 2d8daa584f..703a4f4cba 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -62,7 +62,8 @@ namespace ESM { isDeleted = false; - bool hasName = false; + blank(); + bool hasData = false; bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) @@ -72,7 +73,6 @@ namespace ESM { case ESM::FourCC<'N','A','M','E'>::value: mName = esm.getHString(); - hasName = true; break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); @@ -89,20 +89,12 @@ namespace ESM } } - if (!hasName) - esm.fail("Missing NAME subrecord"); if (!hasData) esm.fail("Missing DATA subrecord"); } void Cell::loadCell(ESMReader &esm, bool saveContext) { - mWater = 0.0f; - mWaterInt = false; - mMapColor = 0; - mRegion.clear(); - mRefNumCounter = 0; - bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { @@ -117,6 +109,7 @@ namespace ESM break; case ESM::FourCC<'W','H','G','T'>::value: esm.getHT(mWater); + mWaterInt = false; break; case ESM::FourCC<'A','M','B','I'>::value: esm.getHT(mAmbi); @@ -153,14 +146,15 @@ namespace ESM void Cell::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNCString("NAME", mName); + esm.writeHNOCString("NAME", mName); + esm.writeHNT("DATA", mData, 12); if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - esm.writeHNT("DATA", mData, 12); if (mData.mFlags & Interior) { if (mWaterInt) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 2ffd2a21b0..1317fc71cb 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -167,6 +167,7 @@ namespace ESM if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } if (mLandData) diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index cf026dbf1d..e9cd4578d1 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -47,14 +47,14 @@ namespace ESM } void LandTexture::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + esm.writeHNT("INTV", mIndex); + esm.writeHNCString("DATA", mTexture); + if (isDeleted) { esm.writeHNCString("DELE", ""); } - - esm.writeHNCString("NAME", mId); - esm.writeHNT("INTV", mIndex); - esm.writeHNCString("DATA", mTexture); } void LandTexture::blank() diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 8027be91ca..95e6a906fd 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -43,20 +43,18 @@ namespace ESM int edgeCount = 0; bool hasData = false; - bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { + case ESM::FourCC<'N','A','M','E'>::value: + mCell = esm.getHString(); + break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); hasData = true; break; - case ESM::FourCC<'N','A','M','E'>::value: - mCell = esm.getHString(); - hasName = true; - break; case ESM::FourCC<'P','G','R','P'>::value: { esm.getSubHeader(); @@ -125,14 +123,12 @@ namespace ESM if (!hasData) esm.fail("Missing DATA subrecord"); - if (!hasName) - esm.fail("Missing NAME subrecord"); } void Pathgrid::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNT("DATA", mData, 12); esm.writeHNCString("NAME", mCell); + esm.writeHNT("DATA", mData, 12); if (isDeleted) { diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index add821c3e8..9f3089763c 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -81,12 +81,14 @@ namespace ESM void Region::save(ESMWriter &esm, bool isDeleted) const { + esm.writeHNCString("NAME", mId); + if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } - esm.writeHNString("NAME", mId); esm.writeHNOCString("FNAM", mName); if (esm.getVersion() == VER_12) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index e433ddede8..2a0542138a 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -120,6 +120,7 @@ namespace ESM if (isDeleted) { esm.writeHNCString("DELE", ""); + return; } if (!mVarNames.empty()) diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 400b1072b6..189cc97df9 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -51,14 +51,17 @@ namespace ESM void SoundGenerator::save(ESMWriter &esm, bool isDeleted) const { esm.writeHNCString("NAME", mId); + + if (isDeleted) + { + esm.writeHNCString("DELE", ""); + return; + } + esm.writeHNT("DATA", mType, 4); esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("SNAM", mSound); - if (isDeleted) - { - esm.writeHNCString("DELE", ""); - } } void SoundGenerator::blank() diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 6af6c96dc0..a211a99bf5 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -19,14 +19,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'D','A','T','A'>::value: - mData = esm.getHString(); - hasData = true; - break; case ESM::FourCC<'N','A','M','E'>::value: mId = esm.getHString(); hasName = true; break; + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; case ESM::FourCC<'D','E','L','E'>::value: esm.skipHSub(); isDeleted = true; @@ -37,20 +37,22 @@ namespace ESM } } - if (!hasData) - esm.fail("Missing DATA"); if (!hasName) esm.fail("Missing NAME"); + if (!hasData && !isDeleted) + esm.fail("Missing DATA"); } void StartScript::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mId); - + esm.writeHNCString("NAME", mId); if (isDeleted) { esm.writeHNCString("DELE", ""); } + else + { + esm.writeHNString("DATA", mData); + } } void StartScript::blank() From 3a7d0d8dc8a6f2c5d066cbdd7775cc72dfdda0cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:34:36 +0200 Subject: [PATCH 0840/1812] Remove a file that isn't in use yet from build --- components/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cf0c83fbda..946c3af164 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,9 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller workqueue + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + # not used yet + #workqueue ) add_component_dir (nif From d7ad0ee14895c1aba8168fef40494bb0fb0ef61c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:35:10 +0200 Subject: [PATCH 0841/1812] Print a sensible error message when S3TC support is missing (Fixes #2800) --- components/resource/texturemanager.cpp | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 87431ffcda..4bd712ea5c 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,6 +1,7 @@ #include "texturemanager.hpp" #include +#include #include @@ -73,7 +74,7 @@ namespace Resource { osg::ref_ptr tex = it->second; - // Keep mip-mapping disabled if the texture creator explicitely requested it. + // Keep mip-mapping disabled if the texture creator explicitely requested no mipmapping. osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) { @@ -108,6 +109,32 @@ namespace Resource } */ + bool checkSupported(osg::Image* image, const std::string& filename) + { + switch(image->getPixelFormat()) + { + case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): + { + osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported() + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) + { + std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; + return false; + } + break; + } + // not bothering with checks for other compression formats right now, we are unlikely to ever use those anyway + default: + return true; + } + return true; + } + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) { std::string normalized = filename; @@ -152,6 +179,10 @@ namespace Resource } osg::Image* image = result.getImage(); + if (!checkSupported(image, filename)) + { + return mWarningTexture; + } // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), // but OpenGL uses bottom left as the image origin. From 2d93a6f6cb906dea5a4207cd65d786a5dcfc8fc0 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Jul 2015 18:46:11 -0400 Subject: [PATCH 0842/1812] Be more verbose when dealing with unhandled nif texture properties --- components/nifosg/nifloader.cpp | 35 ++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6824c0afd0..c980083943 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -903,7 +903,7 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << " in " << mFilename << std::endl; + std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; continue; } @@ -1264,13 +1264,34 @@ namespace NifOsg { if (texprop->textures[i].inUse) { - if (i != Nif::NiTexturingProperty::BaseTexture - && i != Nif::NiTexturingProperty::GlowTexture - && i != Nif::NiTexturingProperty::DarkTexture - && i != Nif::NiTexturingProperty::DetailTexture) + switch(i) { - std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; - continue; + //These are handled later on + case Nif::NiTexturingProperty::BaseTexture: + case Nif::NiTexturingProperty::GlowTexture: + case Nif::NiTexturingProperty::DarkTexture: + case Nif::NiTexturingProperty::DetailTexture: + break; + case Nif::NiTexturingProperty::GlossTexture: + { + std::cerr << "NiTexturingProperty::GlossTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::BumpTexture: + { + std::cerr << "NiTexturingProperty::BumpTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::DecalTexture: + { + std::cerr << "NiTexturingProperty::DecalTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + default: + { + std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; + continue; + } } const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; From 20106bb90f4c21ba47d28db0675ad5292107df7f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 29 Jul 2015 14:45:56 +0200 Subject: [PATCH 0843/1812] allow keywords in quotes (Fixes #2794) --- components/compiler/scanner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 83d4359621..de7f7e1e16 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -281,8 +281,10 @@ namespace Compiler if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') { name = name.substr (1, name.size()-2); - cont = parser.parseName (name, loc, *this); - return true; +// allow keywords enclosed in "" +/// \todo optionally disable +// cont = parser.parseName (name, loc, *this); +// return true; } int i = 0; From 24ba54f4feb65161e306cba91b3270aa6efcdbfb Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 29 Jul 2015 23:57:45 -0500 Subject: [PATCH 0844/1812] Implement accurate moon settings (fixes #672) --- apps/openmw/mwrender/sky.cpp | 162 ++++++++------------ apps/openmw/mwrender/sky.hpp | 37 +++-- apps/openmw/mwworld/weather.cpp | 264 ++++++++++++++++++++------------ apps/openmw/mwworld/weather.hpp | 35 ++++- 4 files changed, 290 insertions(+), 208 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d7..cf20bc4c6d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,5 +1,8 @@ #include "sky.hpp" +#define _USE_MATH_DEFINES +#include + #include #include #include @@ -383,26 +386,29 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) , mType(type) - , mPhase(Phase_Unspecified) + , mPhase(MoonState::Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); - setPhase(Phase_WaxingCrescent); + setPhase(MoonState::Phase_Full); + setVisible(true); } - enum Phase + void setState(const MoonState& state) { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent, - Phase_Unspecified - }; + float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; + float radsY = 0; + float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; + + osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), + radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), + radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + setPhase(state.mPhase); + setTransparency(state.mMoonAlpha); + setShadowBlend(state.mShadowBlend); + } void setTextures(const std::string& phaseTex, const std::string& circleTex) { @@ -415,7 +421,7 @@ public: mUpdater->setTextures(phaseTexPtr, circleTexPtr); } - void setPhase(const Phase& phase) + void setPhase(const MoonState::Phase& phase) { if (mPhase == phase) return; @@ -426,14 +432,14 @@ public: if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; @@ -452,7 +458,8 @@ public: { public: MoonUpdater() - : mFade(0.f) + : mTransparency(1.0f) + , mShadowBlend(1.0f) , mMoonColor(1,1,1,1) { } @@ -464,7 +471,7 @@ public: texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); @@ -475,7 +482,7 @@ public: texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -484,21 +491,20 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mFade); + texEnv->setConstantColor(mMoonColor * mShadowBlend); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - const float backdropFadeThreshold = 0.03; - if (mFade <= backdropFadeThreshold) - { - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); - } - else - texEnv2->setConstantColor(mAtmosphereColor); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); } - void setFade (const float fade) + void setTransparency(const float ratio) { - mFade = fade; + mTransparency = ratio; + } + + void setShadowBlend(const float blendFactor) + { + mShadowBlend = blendFactor; } void setAtmosphereColor(const osg::Vec4f& color) @@ -519,7 +525,8 @@ public: } private: - float mFade; + float mTransparency; + float mShadowBlend; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -537,27 +544,32 @@ public: mUpdater->setMoonColor(color); } - void setFade(const float fade) + void setTransparency(const float ratio) { - mUpdater->setFade(fade); + mUpdater->setTransparency(ratio); + } + + void setShadowBlend(const float blendFactor) + { + mUpdater->setShadowBlend(blendFactor); } unsigned int getPhaseInt() const { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; return 0; } private: Type mType; - Phase mPhase; + MoonState::Phase mPhase; osg::ref_ptr mUpdater; }; @@ -886,10 +898,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -1128,46 +1136,18 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const osg::Vec3f& direction) +void SkyManager::setMasserState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mMasser->setDirection(direction); + mMasser->setState(state); } -void SkyManager::setSecundaDirection(const osg::Vec3f& direction) +void SkyManager::setSecundaState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mSecunda->setDirection(direction); -} - -void SkyManager::masserEnable() -{ - if (!mCreated) return; - - mMasser->setVisible(true); -} - -void SkyManager::secundaEnable() -{ - if (!mCreated) return; - - mSecunda->setVisible(true); -} - -void SkyManager::masserDisable() -{ - if (!mCreated) return; - - mMasser->setVisible(false); -} - -void SkyManager::secundaDisable() -{ - if (!mCreated) return; - - mSecunda->setVisible(false); + mSecunda->setState(state); } void SkyManager::setLightningStrength(const float factor) @@ -1184,18 +1164,6 @@ void SkyManager::setLightningStrength(const float factor) */ } -void SkyManager::setMasserFade(const float fade) -{ - if (!mCreated) return; - mMasser->setFade(fade); -} - -void SkyManager::setSecundaFade(const float fade) -{ - if (!mCreated) return; - mSecunda->setFade(fade); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4d1c73e446..eb953d1285 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -33,6 +33,28 @@ namespace MWRender class RainFader; class AlphaFader; + struct MoonState + { + enum Phase + { + Phase_Full = 0, + Phase_WaningGibbous, + Phase_ThirdQuarter, + Phase_WaningCrescent, + Phase_New, + Phase_WaxingCrescent, + Phase_FirstQuarter, + Phase_WaxingGibbous, + Phase_Unspecified + }; + + float mRotationFromHorizon; + float mRotationFromNorth; + Phase mPhase; + float mShadowBlend; + float mMoonAlpha; + }; + class SkyManager { public: @@ -72,19 +94,8 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const osg::Vec3f& direction); - - void setSecundaDirection(const osg::Vec3f& direction); - - void setMasserFade(const float fade); - - void setSecundaFade(const float fade); - - void masserEnable(); - void masserDisable(); - - void secundaEnable(); - void secundaDisable(); + void setMasserState(const MoonState& state); + void setSecundaState(const MoonState& state); void setLightningStrength(const float factor); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 970e8b4553..f98aa24c13 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,170 @@ namespace } } +MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) + : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) + , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) + , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) + , mFadeOutFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Finish")) + , mAxisOffset(fallback.getFallbackFloat("Moons_" + name + "_Axis_Offset")) + , mSpeed(fallback.getFallbackFloat("Moons_" + name + "_Speed")) + , mDailyIncrement(fallback.getFallbackFloat("Moons_" + name + "_Daily_Increment")) + , mFadeStartAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_Start_Angle")) + , mFadeEndAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_End_Angle")) + , mMoonShadowEarlyFadeAngle(fallback.getFallbackFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) +{ + // Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably + // complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering. + mSpeed = std::min(mSpeed, 180.0f / 23.0f); +} + +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +{ + float rotationFromHorizon = angle(daysPassed, gameHour); + MWRender::MoonState state = + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(daysPassed)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) + }; + + return state; +} + +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +{ + // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the + // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. + + // When calculating the angle of the moon, several cases have to be taken into account: + // 1. Moon rises and then sets in one day. + // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). + // 3. Moon sets and then rises in one day. + float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseAngleToday = 0; + + if(gameHour < moonRiseHourToday) + { + float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + if(moonRiseHourYesterday < 24) + { + float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); + if(moonRiseAngleYesterday < 180) + { + // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + } + } + } + else + { + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + } + + if(moonRiseAngleToday >= 180) + { + // The moon set today, reset the angle to the horizon. + moonRiseAngleToday = 0; + } + + return moonRiseAngleToday; +} + +inline float MoonModel::moonRiseHour(unsigned int daysPassed) +{ + // This arises from the start date of 16 Last Seed, 427 + // TODO: Find an alternate formula that doesn't rely on this day being fixed. + static const unsigned int startDay = 16; + + // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning + // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. + // Note that we don't modulo after adding the latest daily increment because other calculations need to + // know if doing so would cause the moon rise to be postponed until the next day (which happens when + // the moon rise hour is >= 24 in Morrowind). + return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); +} + +inline float MoonModel::rotation(float hours) +{ + // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. + // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure + // of whole rotations that could be completed in a day. + return 15.0f * mSpeed * hours; +} + +inline unsigned int MoonModel::phase(unsigned int daysPassed) +{ + // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. + // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't + // forward declare it (C++11 strongly typed enums solve this). + return ((daysPassed + 1) / 3) % 8; +} + +inline float MoonModel::shadowBlend(float angle) +{ + // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk + // that is roughly the color of the sky, to a textured surface. + // Depending on the current angle, the following values describe the ratio between the textured moon + // and the solid disk: + // 1. From Fade End Angle 1 to Fade Start Angle 1 (during moon rise): 0..1 + // 2. From Fade Start Angle 1 to Fade Start Angle 2 (between moon rise and moon set): 1 (textured) + // 3. From Fade Start Angle 2 to Fade End Angle 2 (during moon set): 1..0 + // 4. From Fade End Angle 2 to Fade End Angle 1 (between moon set and moon rise): 0 (solid disk) + float fadeAngle = mFadeStartAngle - mFadeEndAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float fadeStartAngle2 = 180.0f - mFadeStartAngle; + if((angle >= mFadeEndAngle) && (angle < mFadeStartAngle)) + return (angle - mFadeEndAngle) / fadeAngle; + else if((angle >= mFadeStartAngle) && (angle < fadeStartAngle2)) + return 1.0f; + else if((angle >= fadeStartAngle2) && (angle < fadeEndAngle2)) + return (fadeEndAngle2 - angle) / fadeAngle; + else + return 0.0f; +} + +inline float MoonModel::hourlyAlpha(float gameHour) +{ + // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon + // appears and disappears. + // Depending on the current hour, the following values describe how transparent the moon is. + // 1. From Fade Out Start to Fade Out Finish: 1..0 + // 2. From Fade Out Finish to Fade In Start: 0 (transparent) + // 3. From Fade In Start to Fade In Finish: 0..1 + // 4. From Fade In Finish to Fade Out Start: 1 (solid) + if((gameHour >= mFadeOutStart) && (gameHour < mFadeOutFinish)) + return (mFadeOutFinish - gameHour) / (mFadeOutFinish - mFadeOutStart); + else if((gameHour >= mFadeOutFinish) && (gameHour < mFadeInStart)) + return 0.0f; + else if((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) + return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); + else + return 1.0f; +} + +inline float MoonModel::earlyMoonShadowAlpha(float angle) +{ + // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. + // Depending on the current angle, the following values describe how transparent the moon is. + // 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1 + // 2. From Fade End Angle 1 to Fade End Angle 2 (between moon rise and moon set): 1 (solid) + // 3. From Fade End Angle 2 to Moon Shadow Early Fade Angle 2 (during moon set): 1..0 + // 4. From Moon Shadow Early Fade Angle 2 to Moon Shadow Early Fade Angle 1: 0 (transparent) + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; + if((angle >= moonShadowEarlyFadeAngle1) && (angle < mFadeEndAngle)) + return (angle - moonShadowEarlyFadeAngle1) / mMoonShadowEarlyFadeAngle; + else if((angle >= mFadeEndAngle) && (angle < fadeEndAngle2)) + return 1.0f; + else if((angle >= fadeEndAngle2) && (angle < moonShadowEarlyFadeAngle2)) + return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle; + else + return 0.0f; +} + void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; @@ -88,39 +252,12 @@ Max Raindrops=650 ? mWeatherSettings[name] = weather; } - -float WeatherManager::calculateHourFade (const std::string& moonName) const -{ - float fadeOutStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Start"); - float fadeOutFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Start"); - float fadeInFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Finish"); - - if (mHour >= fadeOutStart && mHour <= fadeOutFinish) - return (1 - ((mHour - fadeOutStart) / (fadeOutFinish - fadeOutStart))); - if (mHour >= fadeInStart && mHour <= fadeInFinish) - return (1 - ((mHour - fadeInStart) / (fadeInFinish - fadeInStart))); - else - return 1; -} - -float WeatherManager::calculateAngleFade (const std::string& moonName, float angle) const -{ - float endAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_End_Angle"); - float startAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Start_Angle"); - if (angle <= startAngle && angle >= endAngle) - return (1 - ((angle - endAngle)/(startAngle-endAngle))); - else if (angle > startAngle) - return 0.f; - else - return 1.f; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) + mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), + mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -465,72 +602,9 @@ void WeatherManager::update(float duration, bool paused) mRendering->setSunDirection( final * -1 ); } - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - osg::Vec3f masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - osg::Vec3f secunda( - (moonHeight - 1) * facing * 1.25f, - (1 - moonHeight) * facing * 0.8f, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - if (masserAngleFade > 0) - { - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->masserEnable(); - } - else - mRendering->getSkyManager()->masserDisable(); - - if (secundaAngleFade > 0) - { - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - mRendering->getSkyManager()->secundaEnable(); - } - else - mRendering->getSkyManager()->secundaDisable(); - - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); + mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); if (!paused) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index efe69f17cb..93cfed68bf 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,6 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; + class MoonState; } namespace Loading @@ -150,6 +151,35 @@ namespace MWWorld // is broken in the vanilla game and was disabled. }; + class MoonModel + { + public: + MoonModel(const std::string& name, MWWorld::Fallback& fallback); + + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + + private: + float mSize; + float mFadeInStart; + float mFadeInFinish; + float mFadeOutStart; + float mFadeOutFinish; + float mAxisOffset; + float mSpeed; + float mDailyIncrement; + float mFadeStartAngle; + float mFadeEndAngle; + float mMoonShadowEarlyFadeAngle; + + float angle(unsigned int daysPassed, float gameHour); + float moonRiseHour(unsigned int daysPassed); + float rotation(float hours); + unsigned int phase(unsigned int daysPassed); + float shadowBlend(float angle); + float hourlyAlpha(float gameHour); + float earlyMoonShadowAlpha(float angle); + }; + /// /// Interface for weather settings /// @@ -237,9 +267,6 @@ namespace MWWorld void transition(const float factor); void setResult(const std::string& weatherType); - float calculateHourFade (const std::string& moonName) const; - float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; WeatherResult mResult; @@ -265,6 +292,8 @@ namespace MWWorld std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; + MoonModel mMasser; + MoonModel mSecunda; }; } From 8dc7e158c675832a9cc4a3948a470d8dbb96f4a4 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:18:56 -0500 Subject: [PATCH 0845/1812] Fix forward declaration of MoonState --- apps/openmw/mwworld/weather.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 93cfed68bf..4290b21aac 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,7 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; - class MoonState; + struct MoonState; } namespace Loading From a4e1630ec249ce15dbfa71f12cee801d38031bf7 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:41:30 -0500 Subject: [PATCH 0846/1812] Remove unreferenced member in MoonModel --- apps/openmw/mwworld/weather.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4290b21aac..faa6355cee 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -159,7 +159,6 @@ namespace MWWorld MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); private: - float mSize; float mFadeInStart; float mFadeInFinish; float mFadeOutStart; From e9ffbcc1b0aa771ca627a26acb6565b6b5e85555 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 11:45:10 +0200 Subject: [PATCH 0847/1812] OSG 3.3.3 moves GL extensions out of osg::Texture --- components/resource/texturemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 4bd712ea5c..252456fb19 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,10 +118,17 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { +#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) + osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#else osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); if (exts && !exts->isTextureCompressionS3TCSupported() // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#endif { std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; From 6a9218ee07a81c9ca56faf8661c9d38e84ba3028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 30 Jul 2015 11:49:24 +0200 Subject: [PATCH 0848/1812] replaced State_Compiling (not requried anymore) with State_Merging --- apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/view/doc/operation.cpp | 3 ++- apps/opencs/view/doc/view.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 78f4681010..7352b4b999 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -12,7 +12,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, - State_Compiling = 64, // not implemented yet + State_Merging = 64, State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 95cbf012d6..e5c1e7b89e 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -19,6 +19,7 @@ void CSVDoc::Operation::updateLabel (int threads) case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; case CSMDoc::State_Searching: name = "searching"; break; + case CSMDoc::State_Merging: name = "merging"; break; } std::ostringstream stream; @@ -122,7 +123,7 @@ void CSVDoc::Operation::setBarColor (int type) bottomColor = "#9ECB2D"; //green gloss break; - case CSMDoc::State_Compiling: + case CSMDoc::State_Merging: topColor = "#F3E2C7"; midTopColor = "#C19E67"; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c4abb26225..05c98b11f5 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -471,6 +471,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 // end marker }; From 77a3a52b4e5d154d55c50c728410c809aa137a8c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:16:15 +0200 Subject: [PATCH 0849/1812] What's wrong with this statement? --- components/resource/texturemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 252456fb19..750dfaab70 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,7 +118,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) +#if OSG_MIN_VERSION_REQUIRED(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. From 1f78ebd3c98bf9759f5573a76279e44eab8cec61 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:22:51 +0200 Subject: [PATCH 0850/1812] Oops? --- components/resource/texturemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 750dfaab70..d29aa28122 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include From 5e6fcc2aefbf2eccf5e16deeb2f064c66efcb497 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Wed, 29 Jul 2015 14:15:06 -0400 Subject: [PATCH 0851/1812] Alert the user if attempting to play an animation fails This is mostly propogating the error up the stack so the game can do something about it. Working on avoiding log spam from calling an animation that doesn't exist every frame. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 ++- apps/openmw/mwmechanics/actors.cpp | 12 ++++++++++-- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwmechanics/objects.cpp | 13 +++++++++++-- apps/openmw/mwmechanics/objects.hpp | 2 +- 9 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2c4a22c075..63ad1d32fc 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -160,12 +160,13 @@ namespace MWBase virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + virtual bool 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 scene should be ignored. /// /// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param count How many times the animation should be run + /// \return Success or error virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd6..dd2fe3cada 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,6 +1,7 @@ #include "actors.hpp" #include +#include #include @@ -1241,11 +1242,18 @@ namespace MWMechanics iter->second->getCharacterController()->forceStateUpdate(); } - void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->getCharacterController()->playGroup(groupName, mode, number); + { + return iter->second->getCharacterController()->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Actors::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4baaea28dd..a16b808846 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -105,7 +105,7 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr &ptr); - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f9..1bd12b53f7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1866,10 +1866,13 @@ void CharacterController::update(float duration) } -void CharacterController::playGroup(const std::string &groupname, int mode, int count) +bool CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) + { std::cerr<< "Animation "< + #include "movement.hpp" #include "../mwbase/environment.hpp" @@ -77,11 +79,18 @@ void Objects::update(float duration, bool paused) } } -void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrControllerMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) - iter->second->playGroup(groupName, mode, number); + { + return iter->second->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Objects::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6e22c0582b..07e00675c2 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,7 +38,7 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); From f69de1f2636f6627a25e1c026e7d176cf7e6108e Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:08:58 -0400 Subject: [PATCH 0852/1812] Alert the user if trying to play a non-idle animation Continue to propagate success/failure up the call stack. --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e230998eb5..e3ce4ae2a7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,6 +1,7 @@ #include "aiwander.hpp" #include +#include #include @@ -621,12 +622,17 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0; } - void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) { const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + return MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } + else + { + std::cerr<< "Attempted to play out of range idle animation \""< Date: Thu, 30 Jul 2015 08:15:45 -0400 Subject: [PATCH 0853/1812] Refactor onChooseActionStatePerFrameActions This prevents playIdle errors from tyring to play idleAnimation 0 --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e3ce4ae2a7..f05040b663 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -392,18 +392,24 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); + //If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; } else { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + //Recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, idleAnimation); storage.mState = Wander_IdleNow; } + + //If we aren't going to just stand + if(idleAnimation) + { + playIdle(actor, idleAnimation); + } } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From f15adb4e4f18e9f5509c95a065001f85a4e0dd82 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 30 Jul 2015 14:43:36 +0300 Subject: [PATCH 0854/1812] Store::load() overwrites loaded records with the same IDs --- apps/openmw/mwworld/store.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index a8b0af88aa..5c1b2c6e30 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -196,6 +196,8 @@ namespace MWWorld std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) mShared.push_back(&inserted.first->second); + else + inserted.first->second = record; return RecordId(record.mId, isDeleted); } From d13766cb3c185ecce9b95518d1367b2cf2d2812d Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 30 Jul 2015 15:36:17 +0300 Subject: [PATCH 0855/1812] Remove redundant template specializations --- apps/openmw/mwworld/store.cpp | 43 ----------------------------------- 1 file changed, 43 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 5c1b2c6e30..98138147db 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1060,49 +1060,6 @@ namespace MWWorld return RecordId(dialogue.mId, isDeleted); } - - - // Script - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &esm) { - ESM::Script script; - bool isDeleted = false; - - script.load(esm, isDeleted); - Misc::StringUtils::toLower(script.mId); - - std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = script; - - return RecordId(script.mId, isDeleted); - } - - - // StartScript - //========================================================================= - - template <> - inline RecordId Store::load(ESM::ESMReader &esm) - { - ESM::StartScript script; - bool isDeleted = false; - - script.load(esm, isDeleted); - Misc::StringUtils::toLower(script.mId); - - std::pair inserted = mStatic.insert(std::make_pair(script.mId, script)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = script; - - return RecordId(script.mId, isDeleted); - } } template class MWWorld::Store; From 67a63cc6622c5b2d2f24fc8fdc8dc5f40aa22222 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 14:00:08 -0500 Subject: [PATCH 0856/1812] Add some const correctness to MoonModel --- apps/openmw/mwworld/weather.cpp | 18 +++++++++--------- apps/openmw/mwworld/weather.hpp | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f98aa24c13..0e78edce7d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,7 +37,7 @@ namespace } } -MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) +MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) @@ -54,7 +54,7 @@ MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const { float rotationFromHorizon = angle(daysPassed, gameHour); MWRender::MoonState state = @@ -69,7 +69,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -108,7 +108,7 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) return moonRiseAngleToday; } -inline float MoonModel::moonRiseHour(unsigned int daysPassed) +inline float MoonModel::moonRiseHour(unsigned int daysPassed) const { // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. @@ -122,7 +122,7 @@ inline float MoonModel::moonRiseHour(unsigned int daysPassed) return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); } -inline float MoonModel::rotation(float hours) +inline float MoonModel::rotation(float hours) const { // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure @@ -130,7 +130,7 @@ inline float MoonModel::rotation(float hours) return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) +inline unsigned int MoonModel::phase(unsigned int daysPassed) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't @@ -138,7 +138,7 @@ inline unsigned int MoonModel::phase(unsigned int daysPassed) return ((daysPassed + 1) / 3) % 8; } -inline float MoonModel::shadowBlend(float angle) +inline float MoonModel::shadowBlend(float angle) const { // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk // that is roughly the color of the sky, to a textured surface. @@ -161,7 +161,7 @@ inline float MoonModel::shadowBlend(float angle) return 0.0f; } -inline float MoonModel::hourlyAlpha(float gameHour) +inline float MoonModel::hourlyAlpha(float gameHour) const { // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon // appears and disappears. @@ -180,7 +180,7 @@ inline float MoonModel::hourlyAlpha(float gameHour) return 1.0f; } -inline float MoonModel::earlyMoonShadowAlpha(float angle) +inline float MoonModel::earlyMoonShadowAlpha(float angle) const { // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. // Depending on the current angle, the following values describe how transparent the moon is. diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index faa6355cee..8f7634fbb0 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -154,9 +154,9 @@ namespace MWWorld class MoonModel { public: - MoonModel(const std::string& name, MWWorld::Fallback& fallback); + MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; private: float mFadeInStart; @@ -170,13 +170,13 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour); - float moonRiseHour(unsigned int daysPassed); - float rotation(float hours); - unsigned int phase(unsigned int daysPassed); - float shadowBlend(float angle); - float hourlyAlpha(float gameHour); - float earlyMoonShadowAlpha(float angle); + float angle(unsigned int daysPassed, float gameHour) const; + float moonRiseHour(unsigned int daysPassed) const; + float rotation(float hours) const; + unsigned int phase(unsigned int daysPassed) const; + float shadowBlend(float angle) const; + float hourlyAlpha(float gameHour) const; + float earlyMoonShadowAlpha(float angle) const; }; /// From de479e35c8e39f6097148d17b5631630333cd1b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Jul 2015 23:51:37 +0200 Subject: [PATCH 0857/1812] Fix AlphaController affecting all instances of the StateSet --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83ecc0fa97..e66713c171 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -353,6 +353,13 @@ AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp { } +void AlphaController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4877c83dbb..500a5cc172 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,6 +189,8 @@ namespace NifOsg AlphaController(); AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); META_Object(NifOsg, AlphaController) From 16b8ef3164c28f829bbe76b3ac1a21a3bb53715c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:01:55 +0200 Subject: [PATCH 0858/1812] Don't use a shared Material in MaterialColorController --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index e66713c171..bb698ed632 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -387,6 +387,13 @@ MaterialColorController::MaterialColorController(const MaterialColorController & { } +void MaterialColorController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 500a5cc172..58870317e9 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -208,6 +208,8 @@ namespace NifOsg META_Object(NifOsg, MaterialColorController) + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; From 1f755a2bc0d99f1ad5e3fe1a32e645a6a4d77694 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:03:01 +0200 Subject: [PATCH 0859/1812] Don't use a shared Material in AlphaFader --- apps/openmw/mwrender/sky.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d7..2009232c52 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -705,6 +705,13 @@ public: mAlpha = alpha; } + virtual void setDefaults(osg::StateSet* stateset) + { + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); + } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); From e8cbdcfb1e98956b86df8d80eb268882d951864b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:35:17 +0200 Subject: [PATCH 0860/1812] Play swimming animation fallback on the upper body when possible --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f9..ae4412dbf8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -390,7 +390,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movemask = MWRender::Animation::BlendMask_LowerBody; + if (weap != sWeaponTypeListEnd) + movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName.erase(swimpos, 4); if(!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); From f326b8e5d28e5a8a68098bdb60a96fc382d0a3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:52:34 +0200 Subject: [PATCH 0861/1812] Fix weapon animations playing on the lowerbody when swimming --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ae4412dbf8..44fcf1c57d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -468,10 +468,14 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mIdleState = idle; std::string idle; + MWRender::Animation::AnimPriority idlePriority (Priority_Default); // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to // "idle"+weapon or "idle". if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) + { idle = "idleswim"; + idlePriority = Priority_SwimIdle; + } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) idle = "idlesneak"; else if(mIdleState != CharState_None) @@ -488,7 +492,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, + mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d647cae229..3ada5e65e3 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SwimIdle, Priority_Jump, Priority_Movement, Priority_Hit, From 7644a46deddc25367dfa6d50f6c51a74a32566f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 01:26:26 +0200 Subject: [PATCH 0862/1812] Creatures with no movement should not attempt to start combat (Fixes #2786) --- apps/openmw/mwmechanics/actors.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd6..75d501ff12 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -291,6 +291,10 @@ namespace MWMechanics return; } + // no combat for totally static creatures (they have no movement or attack animations anyway) + if (!actor1.getClass().isMobile(actor1)) + return; + bool aggressive; if (againstPlayer) From 61c38356378fb4ab0de5bf4a23cd828b40ab7a29 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:20:16 -0400 Subject: [PATCH 0863/1812] Don't try to play animations we know are bad Prevents log spam --- apps/openmw/mwmechanics/aiwander.cpp | 34 +++++++++++++++++----------- apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f05040b663..331ec8b9d7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -58,7 +58,6 @@ namespace MWMechanics bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -68,6 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; + std::vector mBadIdles; //Idle animations that when called cause errors PathFinder mPathFinder; @@ -79,7 +79,8 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mIdleAnimation(0) + mIdleAnimation(0), + mBadIdles() {}; }; @@ -392,24 +393,31 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - //If we should be moving + // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; + return; } - else - { - //Recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartTime = currentTime; - storage.mState = Wander_IdleNow; - } - - //If we aren't going to just stand + // If we aren't going to just stand if(idleAnimation) { - playIdle(actor, idleAnimation); + // If the idle animation actually exists + if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) + { + if(!playIdle(actor, idleAnimation)) + { + std::cerr<< "Unable to play idle animation "<getTimeStamp(); + storage.mState = Wander_IdleNow; + return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c03cdfaa22..27e6fe9fb6 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -76,8 +76,8 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); - ///Have the given actor play an idle animation - ///@return Success or error + /// Have the given actor play an idle animation + /// @return Success or error bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); short unsigned getRandomIdle(); From 6fce49bfb5e6a32127852193dc9413bec59488c5 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 31 Jul 2015 18:00:17 -0400 Subject: [PATCH 0864/1812] Don't warn twice when unable to play an idle animation --- apps/openmw/mwmechanics/aiwander.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 331ec8b9d7..b356c6e7dc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -407,7 +407,6 @@ namespace MWMechanics { if(!playIdle(actor, idleAnimation)) { - std::cerr<< "Unable to play idle animation "< Date: Fri, 31 Jul 2015 18:23:07 -0400 Subject: [PATCH 0865/1812] Remove more comments --- apps/openmw/mwmechanics/aiwander.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b356c6e7dc..440814fb7c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -67,7 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; - std::vector mBadIdles; //Idle animations that when called cause errors + std::vector mBadIdles; // Idle animations that when called cause errors PathFinder mPathFinder; @@ -393,16 +393,13 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; return; } - // If we aren't going to just stand if(idleAnimation) { - // If the idle animation actually exists if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) { if(!playIdle(actor, idleAnimation)) @@ -416,7 +413,6 @@ namespace MWMechanics // Recreate vanilla (broken?) behavior of resetting start time of AIWander: mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); storage.mState = Wander_IdleNow; - return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From 0244a9b32950c8a2caa777a21f6ec73894146e80 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 1 Aug 2015 07:57:05 -0500 Subject: [PATCH 0866/1812] Correct moon texture with respect to trajectory --- apps/openmw/mwrender/sky.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cf20bc4c6d..ea3f8e8bfd 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -398,13 +398,19 @@ public: void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; - float radsY = 0; float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; - osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), - radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), - radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); - setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + osg::Quat rotX(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); + osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + + osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); + mTransform->setPosition(direction * 1000.0f); + + // The moon quad is initially oriented facing down, so we need to offset its X-axis + // rotation to rotate it to face the camera when sitting at the horizon. + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + mTransform->setAttitude(attX * rotZ); + setPhase(state.mPhase); setTransparency(state.mMoonAlpha); setShadowBlend(state.mShadowBlend); From afb36b73eb3edc81947a8b409197d8afc2cfa857 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:03:27 +0300 Subject: [PATCH 0867/1812] Proper index for Modified column in ModifyCommand --- apps/opencs/model/world/commands.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5e0cc8f880..019ffe7b25 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -33,7 +33,14 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI { mHasRecordState = true; int stateColumnIndex = table->findColumnIndex(Columns::ColumnId_Modification); - mRecordStateIndex = table->index(mIndex.row(), stateColumnIndex); + + int rowIndex = mIndex.row(); + if (mIndex.parent().isValid()) + { + rowIndex = mIndex.parent().row(); + } + + mRecordStateIndex = table->index(rowIndex, stateColumnIndex); mOldRecordState = static_cast(table->data(mRecordStateIndex).toInt()); } } From 25b653e316ddfe92754aa22cb6cf468edda44e66 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:06:56 +0300 Subject: [PATCH 0868/1812] Inform about Modified status change when modifying a value of a model --- apps/opencs/model/world/idtable.cpp | 6 +++++- apps/opencs/model/world/idtree.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 8ca19f7e96..bdbc5e0c45 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -77,7 +77,11 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (index, index); + // Modifying a value can also change the Modified status of a record. + // To track this, we inform about the change of a whole row. + QModelIndex rowStart = this->index(index.row(), 0); + QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); + emit dataChanged(rowStart, rowEnd); return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 5a7d10c6ec..0b027cdab6 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -96,7 +96,13 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (index, index); + emit dataChanged(index, index); + + // Modifying a value can also change the Modified status of a record (located in the parent row). + // To track this, we inform about the change of a whole parent row. + QModelIndex parentRowStart = this->index(index.parent().row(), 0); + QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); + emit dataChanged(parentRowStart, parentRowEnd); return true; } From 88c61ed2b6dabb11ae2760cf3095fd2004a4e031 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 17:57:50 +0200 Subject: [PATCH 0869/1812] Fix NotifyDrawCompletedCallback in single threaded mode --- apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c861119b53..54c6315fca 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -437,12 +437,31 @@ namespace MWRender class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback { public: + NotifyDrawCompletedCallback() + : mDone(false) + { + } + virtual void operator () (osg::RenderInfo& renderInfo) const { + mMutex.lock(); + mDone = true; + mMutex.unlock(); mCondition.signal(); } + void waitTillDone() + { + mMutex.lock(); + if (mDone) + return; + mCondition.wait(&mMutex); + mMutex.unlock(); + } + mutable OpenThreads::Condition mCondition; + mutable OpenThreads::Mutex mMutex; + mutable bool mDone; }; void RenderingManager::screenshot(osg::Image *image, int w, int h) @@ -476,15 +495,13 @@ namespace MWRender mRootNode->addChild(rttCamera); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); - // The draw needs to complete before we can copy back our image. osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - OpenThreads::Mutex m; - m.lock(); - callback->mCondition.wait(&m); - m.unlock(); + + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + + callback->waitTillDone(); rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); From 664ae079db5db64e91ed152c0d69651a03ca066d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 18:05:15 +0200 Subject: [PATCH 0870/1812] Improve setting of culling mask for the savegame screenshot camera --- apps/openmw/mwrender/renderingmanager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 54c6315fca..b01095f122 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -466,9 +466,6 @@ namespace MWRender void RenderingManager::screenshot(osg::Image *image, int w, int h) { - int oldCullMask = mViewer->getCamera()->getCullMask(); - mViewer->getCamera()->setCullMask(oldCullMask & (~Mask_GUI)); - osg::ref_ptr rttCamera (new osg::Camera); rttCamera->setNodeMask(Mask_RenderToTexture); rttCamera->attach(osg::Camera::COLOR_BUFFER, image); @@ -492,6 +489,7 @@ namespace MWRender image->setPixelFormat(texture->getInternalFormat()); rttCamera->addChild(mLightRoot); + rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); mRootNode->addChild(rttCamera); @@ -506,8 +504,6 @@ namespace MWRender rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); - - mViewer->getCamera()->setCullMask(oldCullMask); } osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) From 33042c14644532ae53f18fa2c60bd7aacd42357a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 17:16:06 +0300 Subject: [PATCH 0871/1812] Restore Modified status of a record when adding/removing nested rows --- apps/opencs/model/world/columnbase.hpp | 6 ++++++ apps/opencs/model/world/commands.cpp | 22 ++++++++++++++-------- apps/opencs/model/world/commands.hpp | 6 ++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 59f2836c21..c4789ed22b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -192,6 +192,12 @@ namespace CSMWorld ColumnBase::Display_NestedHeader, flags) {} + virtual void set (Record& record, const QVariant& data) + { + // There is nothing to do here. + // This prevents exceptions from parent's implementation + } + virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 019ffe7b25..7673e6bc96 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -289,21 +289,24 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Delete row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::DeleteNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.removeRows (mNestedRow, 1, parentIndex); + mModifyParentCommand->redo(); } void CSMWorld::DeleteNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -317,20 +320,23 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Add row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::AddNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.addNestedRow (parentIndex, mNewRow); + mModifyParentCommand->redo(); } void CSMWorld::AddNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 81c40d0abc..23ffccbd7e 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -200,6 +200,9 @@ namespace CSMWorld int mNestedRow; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); @@ -219,6 +222,9 @@ namespace CSMWorld int mParentColumn; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); From 1590a04d03a8385e7c4e496f32613e76ec339f7f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:39:41 +0300 Subject: [PATCH 0872/1812] Close EditWidget when a proper row removed --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5a44708c19..d537f2eb1d 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -811,8 +811,13 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + + if (!currentIndex.isValid()) + { + return; + } - if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) + if (currentIndex.parent() == parent && currentIndex.row() >= start && currentIndex.row() <= end) { if(mEditWidget) { From 6b3de5c72025140868e763f81204728e49156ed3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:53:40 +0300 Subject: [PATCH 0873/1812] Activate editing of nested table cells by a double click --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d537f2eb1d..5ad2f76e20 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -570,8 +570,6 @@ void CSVWorld::EditWidget::remake(int row) table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->setEnabled(false); } - else - table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); From 0ea4d1981a6c01cf780948dbad8e9f1840004efc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:08:01 +0300 Subject: [PATCH 0874/1812] Add magic effect verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/magiceffectcheck.cpp | 137 +++++++++++++++++++ apps/opencs/model/tools/magiceffectcheck.hpp | 50 +++++++ apps/opencs/model/tools/tools.cpp | 7 + 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/magiceffectcheck.cpp create mode 100644 apps/opencs/model/tools/magiceffectcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d4..e6dd045e1e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck ) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp new file mode 100644 index 0000000000..22620929c9 --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -0,0 +1,137 @@ +#include "magiceffectcheck.hpp" + +#include + +#include "../world/resources.hpp" +#include "../world/data.hpp" + +namespace +{ + void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string text) + { + if (!text.empty()) + { + messages.push_back(std::make_pair(id, text)); + } + } +} + +bool CSMTools::MagicEffectCheckStage::isTextureExists(const std::string &texture, bool isIcon) const +{ + const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; + bool exists = false; + + if (textures.searchId(texture) != -1) + { + exists = true; + } + else + { + std::string ddsTexture = texture; + if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) + { + exists = true; + } + } + + return exists; +} + +std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const +{ + std::string error; + if (!id.empty()) + { + CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id); + if (index.first == -1) + { + error = "No such " + column + " '" + id + "'"; + } + else if (index.second != type.getType()) + { + error = column + " is not of type " + type.getTypeName(); + } + } + return error; +} + +std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const +{ + std::string error; + if (!id.empty() && mSounds.searchId(id) == -1) + { + error = "No such " + column + " '" + id + "'"; + } + return error; +} + +CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures) + : mMagicEffects(effects), + mSounds(sounds), + mReferenceables(referenceables), + mIcons(icons), + mTextures(textures) +{} + +int CSMTools::MagicEffectCheckStage::setup() +{ + return mMagicEffects.getSize(); +} + +void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + ESM::MagicEffect effect = mMagicEffects.getRecord(stage).get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId); + + if (effect.mData.mBaseCost < 0.0f) + { + messages.push_back(std::make_pair(id, "Base Cost is negative")); + } + + if (effect.mIcon.empty()) + { + messages.push_back(std::make_pair(id, "Icon is not specified")); + } + else if (!isTextureExists(effect.mIcon, true)) + { + messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); + } + + if (effect.mParticle.empty()) + { + messages.push_back(std::make_pair(id, "Particle is not specified")); + } + else if (!isTextureExists(effect.mParticle, false)) + { + messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); + } + + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt Object")); + + addMessageIfNotEmpty(messages, id, checkSound(effect.mCastSound, "Casting Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mHitSound, "Hit Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mAreaSound, "Area Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mBoltSound, "Bolt Sound")); + + if (effect.mDescription.empty()) + { + messages.push_back(std::make_pair(id, "Description is empty")); + } +} diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp new file mode 100644 index 0000000000..0ad6760d3d --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -0,0 +1,50 @@ +#ifndef CSM_TOOLS_MAGICEFFECTCHECK_HPP +#define CSM_TOOLS_MAGICEFFECTCHECK_HPP + +#include +#include + +#include "../world/idcollection.hpp" +#include "../world/refidcollection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMWorld +{ + class Resources; +} + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that magic effect records are internally consistent + class MagicEffectCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection &mMagicEffects; + const CSMWorld::IdCollection &mSounds; + const CSMWorld::RefIdCollection &mReferenceables; + const CSMWorld::Resources &mIcons; + const CSMWorld::Resources &mTextures; + + private: + bool isTextureExists(const std::string &texture, bool isIcon) const; + + std::string checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const; + std::string checkSound(const std::string &id, const std::string &column) const; + + public: + MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures); + + virtual int setup(); + ///< \return number of steps + virtual void perform (int stage, CSMDoc::Messages &messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c1160918..97943b1fb7 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "magiceffectcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mData.getSounds(), mData.getReferenceables())); + mVerifierOperation->appendStage (new MagicEffectCheckStage (mData.getMagicEffects(), + mData.getSounds(), + mData.getReferenceables(), + mData.getResources (CSMWorld::UniversalId::Type_Icons), + mData.getResources (CSMWorld::UniversalId::Type_Textures))); + mVerifier.setOperation (mVerifierOperation); } From 8da9eecea755e19b8d1719e0183243a517a36591 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:24:00 +0300 Subject: [PATCH 0875/1812] Correct comparison of enum values in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 10fd92b46a..7572854121 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -5,6 +5,18 @@ #include "idtablebase.hpp" +namespace +{ + std::string getEnumValue(const std::vector &values, int index) + { + if (index < 0 || index >= static_cast(values.size())) + { + return ""; + } + return values[index]; + } +} + void CSMWorld::IdTableProxyModel::updateColumnMap() { Q_ASSERT(mSourceModel != NULL); @@ -93,7 +105,9 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel if (valuesIt != mEnumColumnCache.end()) { - return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + std::string first = getEnumValue(valuesIt->second, left.data().toInt()); + std::string second = getEnumValue(valuesIt->second, right.data().toInt()); + return first < second; } return QSortFilterProxyModel::lessThan(left, right); } From 21e249cb9234b6b40a9e5e15ceb92ab7e3d3c0b4 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:14:36 +1200 Subject: [PATCH 0876/1812] pass parameters as const & --- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 79cee9f326..c7d71e13e6 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -87,14 +87,14 @@ namespace namespace MWMechanics { - float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) + float sqrDistanceIgnoreZ(const ESM::Pathgrid::Point& point, float x, float y) { x -= point.mX; y -= point.mY; return (x * x + y * y); } - float distance(ESM::Pathgrid::Point point, float x, float y, float z) + float distance(const ESM::Pathgrid::Point& point, float x, float y, float z) { x -= point.mX; y -= point.mY; @@ -102,7 +102,7 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { float x = static_cast(a.mX - b.mX); float y = static_cast(a.mY - b.mY); @@ -272,7 +272,7 @@ namespace MWMechanics if(mPath.empty()) return true; - ESM::Pathgrid::Point nextPoint = *mPath.begin(); + const ESM::Pathgrid::Point& nextPoint = *mPath.begin(); if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 4000f5d800..1765a5cc56 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -12,8 +12,8 @@ namespace MWWorld namespace MWMechanics { - float distance(ESM::Pathgrid::Point point, float x, float y, float); - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b); + float distance(const ESM::Pathgrid::Point& point, float x, float y, float); + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b); class PathFinder { public: From 4256e151b131453ca045fae270565e6a71e656b9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:15:58 +1200 Subject: [PATCH 0877/1812] Fixed error in deciding type of attack --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index dd843b9a38..776641e601 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -689,16 +689,14 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = static_cast(slash + chop + thrust); - - float roll = Misc::Rng::rollClosedProbability(); - if(roll <= (slash/total)) + float roll = Misc::Rng::rollClosedProbability() * (slash + chop + thrust); + if(roll <= slash) { movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (slash + (thrust/total))) + else if(roll <= (slash + thrust)) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; From ad9bab0b68f91a59d93f4b538d7575481149c466 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:17:08 +1200 Subject: [PATCH 0878/1812] Removed redundant if. --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 776641e601..560be888ca 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -503,12 +503,14 @@ namespace MWMechanics } // don't use pathgrid when actor can move in 3 dimensions - if(canMoveByZ) preferShortcut = true; + if (canMoveByZ) + { + preferShortcut = true; + movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + } if(preferShortcut) { - if (canMoveByZ) - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); movement.mRotation[2] = getZAngleToDir(vDirToTarget); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; From 58f732ebc9f1cd88f04814caa8b7af66ce5a86fe Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:20:05 +1200 Subject: [PATCH 0879/1812] Update path following checks each frame in AiCombat. --- apps/openmw/mwmechanics/aicombat.cpp | 38 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 560be888ca..f386ec81be 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -429,6 +429,7 @@ namespace MWMechanics // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { + mPathFinder.clearPath(); //Melee and Close-up combat // getXAngleToDir determines vertical angle to target: @@ -528,9 +529,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use - //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); - + // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) { @@ -539,21 +538,16 @@ namespace MWMechanics --pntIter; osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); - preferShortcut = true; + mPathFinder.clearPath(); } } // if there is no new path, then go straight on target - if(!preferShortcut) + if (!mPathFinder.isPathConstructed()) { - if(!mPathFinder.getPath().empty()) - movement.mRotation[2] = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - else - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir(vDirToTarget); } } @@ -573,9 +567,25 @@ namespace MWMechanics void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); - actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + if (mPathFinder.isPathConstructed()) + { + const ESM::Position& pos = actor.getRefData().getPosition(); + if (mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + { + actorMovementSettings.mPosition[1] = 0; + } + else + { + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actorMovementSettings.mPosition[1] = 1; + } + } + else + { + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } } void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, From 581ea2660522dbefedd197753dac380298e001d2 Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 13:05:29 +0200 Subject: [PATCH 0880/1812] Add appdata file for openmw and install it --- CMakeLists.txt | 3 +++ files/openmw.appdata.xml | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 files/openmw.appdata.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb4235..99fb56fbe8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml + "${OpenMW_BINARY_DIR}/openmw.appdata.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -422,6 +424,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml new file mode 100644 index 0000000000..150eea9848 --- /dev/null +++ b/files/openmw.appdata.xml @@ -0,0 +1,39 @@ + + + + openmw.desktop + CC0-1.0 + GPL-3.0 and MIT and zlib + OpenMW + Unofficial open source engine re-implementation of the game Morrowind + +

    + OpenMW is a recreation of 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. +

    +

    + The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). +

    +

    + Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. +

    +
    + + + + http://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png + The OpenMW launcher + + + http://wiki.openmw.org/images/f/f1/Screenshot_mournhold_plaza_0.35.png + The Mournhold's plaza on OpenMW + + + http://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png + Vivec seen from Ebonheart on OpenMW + + +nobrakal@gmail.com + https://openmw.org + https://bugs.openmw.org/ + https://openmw.org/faq/ +
    From cbc8309289c9f4dc9fe4603cb04565e878b6addc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 4 Aug 2015 16:19:00 +0300 Subject: [PATCH 0881/1812] Don't allow empty value of School field in Magic Effects table --- apps/opencs/view/doc/viewmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf6..0db51dfd29 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, - { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, + { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false }, { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, From 8ae7c63c456985cea6198e9085023c5d7ce03c4b Mon Sep 17 00:00:00 2001 From: "taras.kudryavtsev" Date: Tue, 4 Aug 2015 16:56:05 +0300 Subject: [PATCH 0882/1812] #2730 and #2725 --- apps/opencs/model/world/columnbase.cpp | 1 - apps/opencs/model/world/columnbase.hpp | 1 - apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 24 ++++++++++++++------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f209e48c66..2143ec730e 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -82,7 +82,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c4789ed22b..400e31333f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -118,7 +118,6 @@ namespace CSMWorld Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b46..947454d771 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -198,7 +198,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_YesNo)); + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf6..cc91a5d726 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -103,7 +103,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, + { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e20..2bfde4b228 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -740,13 +740,15 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mMainLayout = new QVBoxLayout(mainWidget); setWidget (mainWidget); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false); + mTable->getModelIndex(getUniversalId().getId(), idColumn).row(), mTable, mCommandDispatcher, document, false); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); + dataChanged(mTable->getModelIndex (getUniversalId().getId(), idColumn)); connect(mEditWidget, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), @@ -759,8 +761,9 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid return; + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid()) { @@ -775,7 +778,8 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) @@ -808,7 +812,8 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (!currentIndex.isValid()) { @@ -906,7 +911,8 @@ void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QS void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && @@ -918,7 +924,8 @@ void CSVWorld::DialogueSubView::showPreview () void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && currentIndex.row() < getTable().rowCount()) @@ -953,7 +960,8 @@ void CSVWorld::DialogueSubView::switchToRow (int row) void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - QModelIndex index = getTable().getModelIndex (id, 0); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex index = getTable().getModelIndex (id, idColumn); if (index.isValid()) switchToRow (index.row()); From 8c8c5328dc8f8c96a70ebe0eb765fae573f1922a Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 22:50:53 +0200 Subject: [PATCH 0883/1812] Rewrite of the description --- files/openmw.appdata.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml index 150eea9848..1c16cb9a40 100644 --- a/files/openmw.appdata.xml +++ b/files/openmw.appdata.xml @@ -8,13 +8,13 @@ Unofficial open source engine re-implementation of the game Morrowind

    - OpenMW is a recreation of 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. + OpenMW is a new engine for 2002's Game of the Year, The Elder Scrolls 3: Morrowind.

    - The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). + It aims to be a fully playable (and improved!), open source implementation of the game's engine and functionality (including mods).

    - Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. + You will still need the original game data to play OpenMW.

    From ea2f88a355f7c1aeaad26fced87a70863f72ad6a Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 4 Aug 2015 21:07:42 -0500 Subject: [PATCH 0884/1812] Fix several sky rendering bugs, maybe also #639 Added code to hide the moons, sun, and stars for certain weather effects. Lightly refactored CelestialBody and derived classes. Fixed moons switching phase at 24:00. --- apps/openmw/mwrender/sky.cpp | 318 ++++++++++++++++---------------- apps/openmw/mwrender/sky.hpp | 58 +++++- apps/openmw/mwworld/weather.cpp | 37 +++- apps/openmw/mwworld/weather.hpp | 54 +----- 4 files changed, 248 insertions(+), 219 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8330835a6c..3a2da230f6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -322,11 +321,12 @@ private: int mMeshType; }; -class CelestialBody +// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being +// derived from osg::Referenced. +class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) - : mSceneManager(sceneManager) + CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -336,42 +336,85 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); + + mGeode->addUpdateCallback(this); } - void setDirection(const osg::Vec3f& direction) + virtual ~CelestialBody() { - osg::Vec3f normalizedDirection = direction / direction.length(); - mTransform->setPosition(normalizedDirection*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), normalizedDirection); - mTransform->setAttitude(quat); + mGeode->removeUpdateCallback(this); } + virtual void adjustTransparency(const float ratio) = 0; + void setVisible(bool visible) { mTransform->setNodeMask(visible ? ~0 : 0); } protected: + static const float mDistance; osg::ref_ptr mTransform; osg::ref_ptr mGeode; - Resource::SceneManager* mSceneManager; - }; +const float CelestialBody::mDistance = 1000.0f; + class Sun : public CelestialBody { public: - Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) - : CelestialBody(parentNode, sceneManager, 1.f, 1) + Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) + : CelestialBody(parentNode, 1.0f, 1) + , mColor(1.0f, 1.0f, 1.0f, 1.0f) + , mDummyTexture(textureManager.getWarningTexture()) { - osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP); + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr texEnv(new osg::TexEnvCombine); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + + stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mColor); + } + + virtual void adjustTransparency(const float ratio) + { + mColor.a() = ratio; + } + + void setDirection(const osg::Vec3f& direction) + { + osg::Vec3f normalizedDirection = direction / direction.length(); + mTransform->setPosition(normalizedDirection * mDistance); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normalizedDirection); + mTransform->setAttitude(quat); + } + +private: + + osg::Vec4f mColor; + osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -383,18 +426,57 @@ public: Type_Secunda }; - Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) - : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) + : CelestialBody(parentNode, scaleFactor, 2) + , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) { - mUpdater = new MoonUpdater; - mGeode->addUpdateCallback(mUpdater); - setPhase(MoonState::Phase_Full); setVisible(true); } + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + virtual void adjustTransparency(const float ratio) + { + mTransparency *= ratio; + } + void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; @@ -404,27 +486,59 @@ public: osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); - mTransform->setPosition(direction * 1000.0f); + mTransform->setPosition(direction * mDistance); // The moon quad is initially oriented facing down, so we need to offset its X-axis // rotation to rotate it to face the camera when sitting at the horizon. - osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - setTransparency(state.mMoonAlpha); - setShadowBlend(state.mShadowBlend); + mTransparency = state.mMoonAlpha; + mShadowBlend = state.mShadowBlend; } + void setAtmosphereColor(const osg::Vec4f& color) + { + mAtmosphereColor = color; + } + + void setColor(const osg::Vec4f& color) + { + mMoonColor = color; + } + + unsigned int getPhaseInt() const + { + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; + return 0; + } + +private: + + Resource::TextureManager& mTextureManager; + Type mType; + MoonState::Phase mPhase; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + void setTextures(const std::string& phaseTex, const std::string& circleTex) { - osg::ref_ptr phaseTexPtr = mSceneManager->getTextureManager()->getTexture2D(phaseTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - osg::ref_ptr circleTexPtr = mSceneManager->getTextureManager()->getTexture2D(circleTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); - - mUpdater->setTextures(phaseTexPtr, circleTexPtr); + reset(); } void setPhase(const MoonState::Phase& phase) @@ -454,129 +568,6 @@ public: else setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } - - void setType(const Type& type) - { - mType = type; - } - - class MoonUpdater : public SceneUtil::StateSetUpdater - { - public: - MoonUpdater() - : mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1,1,1,1) - { - } - - virtual void setDefaults(osg::StateSet *stateset) - { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) - { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); - } - - void setTransparency(const float ratio) - { - mTransparency = ratio; - } - - void setShadowBlend(const float blendFactor) - { - mShadowBlend = blendFactor; - } - - void setAtmosphereColor(const osg::Vec4f& color) - { - mAtmosphereColor = color; - } - - void setMoonColor(const osg::Vec4f& color) - { - mMoonColor = color; - } - - void setTextures(osg::ref_ptr phaseTex, osg::ref_ptr circleTex) - { - mPhaseTex = phaseTex; - mCircleTex = circleTex; - reset(); - } - - private: - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; - }; - - - void setAtmosphereColor(const osg::Vec4f& color) - { - mUpdater->setAtmosphereColor(color); - } - - void setColor(const osg::Vec4f& color) - { - mUpdater->setMoonColor(color); - } - - void setTransparency(const float ratio) - { - mUpdater->setTransparency(ratio); - } - - void setShadowBlend(const float blendFactor) - { - mUpdater->setShadowBlend(blendFactor); - } - - unsigned int getPhaseInt() const - { - if (mPhase == MoonState::Phase_New) return 0; - else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; - else if (mPhase == MoonState::Phase_WaningCrescent) return 1; - else if (mPhase == MoonState::Phase_FirstQuarter) return 2; - else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; - else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; - else if (mPhase == MoonState::Phase_WaningGibbous) return 3; - else if (mPhase == MoonState::Phase_Full) return 4; - return 0; - } - -private: - Type mType; - MoonState::Phase mPhase; - osg::ref_ptr mUpdater; }; SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) @@ -641,11 +632,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, mSceneManager)); + mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); + mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -970,7 +961,7 @@ void SkyManager::updateRainParameters() } } -void SkyManager::setWeather(const MWWorld::WeatherResult& weather) +void SkyManager::setWeather(const WeatherResult& weather) { if (!mCreated) return; @@ -1087,9 +1078,14 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - if (weather.mNight && mStarsOpacity != weather.mNightFade) + mMasser->adjustTransparency(weather.mCelestialBodyTransparency); + mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); + mSun->adjustTransparency(weather.mCelestialBodyTransparency); + + float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + if(weather.mNight && mStarsOpacity != nextStarsOpacity) { - mStarsOpacity = weather.mNightFade; + mStarsOpacity = nextStarsOpacity; mAtmosphereNightUpdater->setFade(mStarsOpacity); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index eb953d1285..16509ef32c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,9 +1,11 @@ #ifndef OPENMW_MWRENDER_SKY_H #define OPENMW_MWRENDER_SKY_H -#include +#include -#include "../mwworld/weather.hpp" +#include +#include +#include namespace osg { @@ -33,6 +35,50 @@ namespace MWRender class RainFader; class AlphaFader; + struct WeatherResult + { + std::string mCloudTexture; + std::string mNextCloudTexture; + float mCloudBlendFactor; + + osg::Vec4f mFogColor; + + osg::Vec4f mAmbientColor; + + osg::Vec4f mSkyColor; + + osg::Vec4f mSunColor; + + osg::Vec4f mSunDiscColor; + + float mFogDepth; + + float mWindSpeed; + + float mCloudSpeed; + + float mCloudOpacity; + + float mGlareView; + + bool mNight; // use night skybox + float mNightFade; // fading factor for night skybox + + bool mIsStorm; + + std::string mAmbientLoopSoundID; + float mAmbientSoundVolume; + + std::string mParticleEffect; + std::string mRainEffect; + float mEffectFade; + + float mRainSpeed; + float mRainFrequency; + + float mCelestialBodyTransparency; + }; + struct MoonState { enum Phase @@ -82,7 +128,7 @@ namespace MWRender void setMoonColour (bool red); ///< change Secunda colour to red - void setWeather(const MWWorld::WeatherResult& weather); + void setWeather(const WeatherResult& weather); void sunEnable(); @@ -133,9 +179,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - std::auto_ptr mSun; - std::auto_ptr mMasser; - std::auto_ptr mSecunda; + osg::ref_ptr mSun; + osg::ref_ptr mMasser; + osg::ref_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 0e78edce7d..679565e45f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -61,7 +61,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam { rotationFromHorizon, mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed)), + static_cast(phase(daysPassed, gameHour)), shadowBlend(rotationFromHorizon), earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) }; @@ -130,12 +130,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) const +inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). - return ((daysPassed + 1) / 3) % 8; + + // If the moon didn't rise yet today, use yesterday's moon phase. + if(gameHour < moonRiseHour(daysPassed)) + return (daysPassed / 3) % 8; + else + return ((daysPassed + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -289,44 +294,54 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; + clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; + cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; + foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; + thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; + rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; + overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; + ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; + blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; + snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; + blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -460,14 +475,16 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } + + mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) { setResult(mCurrentWeather); - const WeatherResult current = mResult; + const MWRender::WeatherResult current = mResult; setResult(mNextWeather); - const WeatherResult other = mResult; + const MWRender::WeatherResult other = mResult; mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; @@ -513,6 +530,16 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } + + const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; + const Weather& nextSettings = mWeatherSettings[mNextWeather]; + + if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = factor; + else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = 1 - factor; + else + mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 8f7634fbb0..1bc3bc3577 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwrender/sky.hpp" + namespace ESM { struct Region; @@ -19,7 +21,6 @@ namespace ESM namespace MWRender { class RenderingManager; - struct MoonState; } namespace Loading @@ -31,50 +32,6 @@ namespace MWWorld { class Fallback; - /// Defines the actual weather that results from weather setting (see below), time of day and weather transition - struct WeatherResult - { - std::string mCloudTexture; - std::string mNextCloudTexture; - float mCloudBlendFactor; - - osg::Vec4f mFogColor; - - osg::Vec4f mAmbientColor; - - osg::Vec4f mSkyColor; - - osg::Vec4f mSunColor; - - osg::Vec4f mSunDiscColor; - - float mFogDepth; - - float mWindSpeed; - - float mCloudSpeed; - - float mCloudOpacity; - - float mGlareView; - - bool mNight; // use night skybox - float mNightFade; // fading factor for night skybox - - bool mIsStorm; - - std::string mAmbientLoopSoundID; - float mAmbientSoundVolume; - - std::string mParticleEffect; - std::string mRainEffect; - float mEffectFade; - - float mRainSpeed; - float mRainFrequency; - }; - - /// Defines a single weather setting (according to INI) struct Weather { @@ -149,6 +106,9 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + // Some weather patterns will obstruct the moons, sun, and stars. + bool mObstructsCelestialBodies; }; class MoonModel @@ -173,7 +133,7 @@ namespace MWWorld float angle(unsigned int daysPassed, float gameHour) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed) const; + unsigned int phase(unsigned int daysPassed, float gameHour) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; @@ -268,7 +228,7 @@ namespace MWWorld void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; - WeatherResult mResult; + MWRender::WeatherResult mResult; typedef std::map > RegionModMap; RegionModMap mRegionMods; From 46ce04a65b00e4efe2f344e104373063a49f7742 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 5 Aug 2015 17:10:35 +0200 Subject: [PATCH 0885/1812] Don't package duplicate version for Windows The real version file is in the resources folder, and that's where it's read from. So the extra file is unused, and redundant. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99fb56fbe8..84fd16e338 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -449,7 +449,6 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") - INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES From cbf9f83b855e382375c17c2fc64eec582e31714a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 5 Aug 2015 17:20:01 +0200 Subject: [PATCH 0886/1812] allow use of IDs as function arguments, even if the ID matches a keyword (Fixes #2830) --- components/compiler/exprparser.cpp | 5 ++++- components/compiler/lineparser.cpp | 17 +++++++++++++++++ components/compiler/stringparser.cpp | 24 +++++++++++++++++++++++- components/compiler/stringparser.hpp | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index dc36b58d82..1818d04df2 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -353,7 +353,10 @@ namespace Compiler if (extensions->isInstruction (keyword, argumentType, hasExplicit)) { // pretend this is not a keyword - return parseName (loc.mLiteral, loc, scanner); + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index a71672916b..4d6e147fc4 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -222,6 +222,23 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==MessageState || mState==MessageCommaState) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + } + if (mState==SetMemberVarState) { mMemberName = loc.mLiteral; diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index a86c15794f..7a2098fb36 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -4,9 +4,12 @@ #include #include +#include + #include "scanner.hpp" #include "generator.hpp" -#include +#include "context.hpp" +#include "extensions.hpp" namespace Compiler { @@ -33,6 +36,25 @@ namespace Compiler return Parser::parseName (name, loc, scanner); } + bool StringParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + + return Parser::parseKeyword (keyword, loc, scanner); + } + bool StringParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { if (code==Scanner::S_comma && mState==StartState) diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index 3859a24965..52469128fd 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -32,6 +32,10 @@ namespace Compiler ///< Handle a name token. /// \return fetch another token? + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? From 5602cd9b7b6f954d953ed90ed1131aac8a3df32b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 02:54:47 +0200 Subject: [PATCH 0887/1812] Fix the launcher's version label for builds with no git commit info --- apps/launcher/maindialog.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c18c26cdda..9a6f91a0f5 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -175,20 +175,16 @@ void Launcher::MainDialog::setVersionLabel() QString tag(QString::fromUtf8(v.mTagHash.c_str())); versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } + if (!v.mVersion.empty() && (revision.isEmpty() || revision == tag)) + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + else + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); } bool Launcher::MainDialog::setup() From f2e51b0579fb44ea391ed439ca4c9010cd098953 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 21:03:21 -0500 Subject: [PATCH 0888/1812] Use diffuse alpha to fade Sun --- apps/openmw/mwrender/sky.cpp | 39 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3a2da230f6..38b6b9193f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -321,12 +321,12 @@ private: int mMeshType; }; -// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being -// derived from osg::Referenced. +/// A base class for the sun and moons. +/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) + CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -365,35 +365,26 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mColor(1.0f, 1.0f, 1.0f, 1.0f) - , mDummyTexture(textureManager.getWarningTexture()) + , mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) { - osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr texEnv(new osg::TexEnvCombine); - texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); - texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); - texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mColor); + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); } virtual void adjustTransparency(const float ratio) @@ -412,9 +403,8 @@ public: } private: - + Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -522,7 +512,6 @@ public: } private: - Resource::TextureManager& mTextureManager; Type mType; MoonState::Phase mPhase; From 238ae419a363ef263ffbba13307671a5d30e73f9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 22:02:54 -0500 Subject: [PATCH 0889/1812] Fix use of incorrect material for Sun --- apps/openmw/mwrender/sky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 38b6b9193f..f16f97bc21 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -377,7 +377,7 @@ public: osg::Texture::CLAMP); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From 469a896ca16cf59a29ea6cb33b9e9b7d42241871 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 08:45:38 +0200 Subject: [PATCH 0890/1812] make non-editable fields in dialogue sub view selectable (Fixes #2818) --- apps/opencs/view/world/dialoguesubview.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e20..b2f2355ef1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -104,7 +104,9 @@ QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return new QLabel(parent); + QLabel *label = new QLabel(parent); + label->setTextInteractionFlags (Qt::TextSelectableByMouse); + return label; } /* @@ -809,7 +811,7 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); - + if (!currentIndex.isValid()) { return; From b83f9445a96fda4dc14e43a2db363a748344227f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:52:10 +0200 Subject: [PATCH 0891/1812] added UI for merge tool (merge tool itself is still missing) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 16 +++ apps/opencs/editor.hpp | 12 +++ apps/opencs/model/doc/documentmanager.cpp | 2 + apps/opencs/model/doc/documentmanager.hpp | 2 + apps/opencs/view/doc/filewidget.cpp | 8 ++ apps/opencs/view/doc/filewidget.hpp | 4 + apps/opencs/view/doc/view.cpp | 11 ++ apps/opencs/view/doc/view.hpp | 5 + apps/opencs/view/doc/viewmanager.cpp | 1 + apps/opencs/view/doc/viewmanager.hpp | 2 + apps/opencs/view/tools/merge.cpp | 123 ++++++++++++++++++++++ apps/opencs/view/tools/merge.hpp | 60 +++++++++++ 13 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/tools/merge.cpp create mode 100644 apps/opencs/view/tools/merge.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d4..91c778c06b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -94,7 +94,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable searchsubview searchbox + reportsubview reporttable searchsubview searchbox merge ) opencs_units_noqt (view/tools diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf2..170e883201 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -40,9 +40,12 @@ CS::Editor::Editor () mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); + mMerge.setLocalData (mLocal); connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)), this, SLOT (documentAdded (CSMDoc::Document *))); + connect (&mDocumentManager, SIGNAL (documentAboutToBeRemoved (CSMDoc::Document *)), + this, SLOT (documentAboutToBeRemoved (CSMDoc::Document *))); connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()), this, SLOT (lastDocumentDeleted())); @@ -50,6 +53,7 @@ CS::Editor::Editor () connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ())); + connect (&mViewManager, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SLOT (mergeDocument (CSMDoc::Document *))); connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ())); connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ())); @@ -360,7 +364,19 @@ void CS::Editor::documentAdded (CSMDoc::Document *document) mViewManager.addView (document); } +void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document) +{ + if (mMerge.getDocument()==document) + mMerge.cancel(); +} + void CS::Editor::lastDocumentDeleted() { QApplication::quit(); } + +void CS::Editor::mergeDocument (CSMDoc::Document *document) +{ + mMerge.configure (document); + mMerge.show(); +} diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0464fb7eb4..ac403b1eee 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -27,11 +27,18 @@ #include "view/settings/dialog.hpp" +#include "view/tools/merge.hpp" + namespace VFS { class Manager; } +namespace CSMDoc +{ + class Document; +} + namespace CS { class Editor : public QObject @@ -55,6 +62,7 @@ namespace CS boost::interprocess::file_lock mLock; boost::filesystem::ofstream mPidFile; bool mFsStrict; + CSVTools::Merge mMerge; void setupDataFiles (const Files::PathContainer& dataDirs); @@ -94,8 +102,12 @@ namespace CS void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void lastDocumentDeleted(); + void mergeDocument (CSMDoc::Document *document); + private: QString mIpcServerName; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159b..02d4ab5c06 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -73,6 +73,8 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) if (iter==mDocuments.end()) throw std::runtime_error ("removing invalid document"); + emit documentAboutToBeRemoved (document); + mDocuments.erase (iter); document->deleteLater(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index b61656d4b1..f9b18bfe61 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -88,6 +88,8 @@ namespace CSMDoc void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void loadRequest (CSMDoc::Document *document); void lastDocumentDeleted(); diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a0..3e5c087883 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -56,3 +56,11 @@ void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible) { mType->setVisible(visible); } + +void CSVDoc::FileWidget::setName (const std::string& text) +{ + QString text2 = QString::fromUtf8 (text.c_str()); + + mInput->setText (text2); + textChanged (text2); +} diff --git a/apps/opencs/view/doc/filewidget.hpp b/apps/opencs/view/doc/filewidget.hpp index ff09d71a39..ab06f37f18 100644 --- a/apps/opencs/view/doc/filewidget.hpp +++ b/apps/opencs/view/doc/filewidget.hpp @@ -3,6 +3,8 @@ #include +#include + class QLabel; class QString; class QLineEdit; @@ -29,6 +31,8 @@ namespace CSVDoc void extensionLabelIsVisible(bool visible); + void setName (const std::string& text); + private slots: void textChanged (const QString& text); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 05c98b11f5..df7421a14a 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -66,6 +66,10 @@ void CSVDoc::View::setupFileMenu() connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); file->addAction (mVerify); + mMerge = new QAction (tr ("Merge"), this); + connect (mMerge, SIGNAL (triggered()), this, SLOT (merge())); + file->addAction (mMerge); + QAction *loadErrors = new QAction (tr ("Load Error Log"), this); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); file->addAction (loadErrors); @@ -393,6 +397,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); + + mMerge->setEnabled (mDocument->getContentFiles().size()>1); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -969,3 +975,8 @@ void CSVDoc::View::updateScrollbar() else mSubViewWindow.setMinimumWidth(0); } + +void CSVDoc::View::merge() +{ + emit mergeDocument (mDocument); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7f4255f8fc..adda735265 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -43,6 +43,7 @@ namespace CSVDoc QAction *mVerify; QAction *mShowStatusBar; QAction *mStopDebug; + QAction *mMerge; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; @@ -129,6 +130,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = ""); @@ -237,6 +240,8 @@ namespace CSVDoc void closeRequest (SubView *subView); void moveScrollBarToEnd(int min, int max); + + void merge(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf6..265c1f8326 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -175,6 +175,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); + connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *))); connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated(const QString &, const QStringList &)), diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index cdd5ac7686..70431107f6 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -77,6 +77,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void exitApplication (CSVDoc::View *view); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp new file mode 100644 index 0000000000..baadd91799 --- /dev/null +++ b/apps/opencs/view/tools/merge.cpp @@ -0,0 +1,123 @@ + +#include "merge.hpp" + +#include +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + +#include "../doc/filewidget.hpp" +#include "../doc/adjusterwidget.hpp" + +CSVTools::Merge::Merge (QWidget *parent) +: QDialog (parent), mDocument (0) +{ + setWindowTitle ("Merge Content Files into a new Game File"); + + QVBoxLayout *mainLayout = new QVBoxLayout; + setLayout (mainLayout); + + QSplitter *splitter = new QSplitter (Qt::Horizontal, this); + + mainLayout->addWidget (splitter, 1); + + // left panel (files to be merged) + QWidget *left = new QWidget (this); + left->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (left); + + QVBoxLayout *leftLayout = new QVBoxLayout; + left->setLayout (leftLayout); + + leftLayout->addWidget (new QLabel ("Files to be merged", this)); + + mFiles = new QListWidget (this); + leftLayout->addWidget (mFiles, 1); + + // right panel (new game file) + QWidget *right = new QWidget (this); + right->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (right); + + QVBoxLayout *rightLayout = new QVBoxLayout; + rightLayout->setAlignment (Qt::AlignTop); + right->setLayout (rightLayout); + + rightLayout->addWidget (new QLabel ("New game file", this)); + + mNewFile = new CSVDoc::FileWidget (this); + mNewFile->setType (false); + mNewFile->extensionLabelIsVisible (true); + rightLayout->addWidget (mNewFile); + + mAdjuster = new CSVDoc::AdjusterWidget (this); + + rightLayout->addWidget (mAdjuster); + + connect (mNewFile, SIGNAL (nameChanged (const QString&, bool)), + mAdjuster, SLOT (setName (const QString&, bool))); + connect (mAdjuster, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool))); + + // buttons + QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); + + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + mOkay->setDefault (true); + buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); + + mainLayout->addWidget (buttons); +} + +void CSVTools::Merge::configure (CSMDoc::Document *document) +{ + mDocument = document; + + mNewFile->setName (""); + + // content files + while (mFiles->count()) + delete mFiles->takeItem (0); + + std::vector files = document->getContentFiles(); + + for (std::vector::const_iterator iter (files.begin()); + iter!=files.end(); ++iter) + mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); +} + +void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData) +{ + mAdjuster->setLocalData (localData); +} + +CSMDoc::Document *CSVTools::Merge::getDocument() const +{ + return mDocument; +} + +void CSVTools::Merge::cancel() +{ + mDocument = 0; + hide(); +} + +void CSVTools::Merge::accept() +{ + QDialog::accept(); +} + +void CSVTools::Merge::reject() +{ + QDialog::reject(); + cancel(); +} + +void CSVTools::Merge::stateChanged (bool valid) +{ + mOkay->setEnabled (valid); +} diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp new file mode 100644 index 0000000000..4538baebe6 --- /dev/null +++ b/apps/opencs/view/tools/merge.hpp @@ -0,0 +1,60 @@ +#ifndef CSV_TOOLS_REPORTTABLE_H +#define CSV_TOOLS_REPORTTABLE_H + +#include + +#include + +class QPushButton; +class QListWidget; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class FileWidget; + class AdjusterWidget; +} + +namespace CSVTools +{ + class Merge : public QDialog + { + Q_OBJECT + + CSMDoc::Document *mDocument; + QPushButton *mOkay; + QListWidget *mFiles; + CSVDoc::FileWidget *mNewFile; + CSVDoc::AdjusterWidget *mAdjuster; + + public: + + Merge (QWidget *parent = 0); + + /// Configure dialogue for a new merge + void configure (CSMDoc::Document *document); + + void setLocalData (const boost::filesystem::path& localData); + + CSMDoc::Document *getDocument() const; + + void cancel(); + + public slots: + + virtual void accept(); + + virtual void reject(); + + private slots: + + void stateChanged (bool valid); + + }; +} + +#endif From 4fd3097c1cf2329cef071aee7a1b149e280e4974 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:58:52 +0200 Subject: [PATCH 0892/1812] improved adjuster widget problem reporting --- apps/opencs/view/doc/adjusterwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c81..6dc95a338a 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -64,6 +64,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) QString message; mValid = (!name.isEmpty()); + bool warning = false; if (!mValid) { @@ -106,13 +107,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { /// \todo add an user setting to make this an error. message += "

    A file with the same name already exists. If you continue, it will be overwritten."; + warning = true; } } } mMessage->setText (message); mIcon->setPixmap (style()->standardIcon ( - mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning). + mValid ? (warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxInformation) : QStyle::SP_MessageBoxCritical). pixmap (QSize (16, 16))); emit stateChanged (mValid); From ff2dab8d5657331b824b017908ca490ad8aa8216 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 6 Aug 2015 14:17:42 +0300 Subject: [PATCH 0893/1812] Remove check for an empty Particle from Magic effects verifier --- apps/opencs/model/tools/magiceffectcheck.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 22620929c9..5435881b34 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -103,11 +103,7 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); } - if (effect.mParticle.empty()) - { - messages.push_back(std::make_pair(id, "Particle is not specified")); - } - else if (!isTextureExists(effect.mParticle, false)) + if (!effect.mParticle.empty() && !isTextureExists(effect.mParticle, false)) { messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); } From 3235cecddfe11a1bbe70b231b7e1fa8fb716b1db Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 7 Aug 2015 00:08:18 -0500 Subject: [PATCH 0894/1812] Use Glare View for visibility of celestial bodies Fixed memory leak from Sun and Moon objects by pulling Updaters back out into separate objects. Removed code related to mCelestialBodyTransparency. --- apps/openmw/mwrender/sky.cpp | 235 ++++++++++++++++++-------------- apps/openmw/mwrender/sky.hpp | 9 +- apps/openmw/mwworld/weather.cpp | 22 --- apps/openmw/mwworld/weather.hpp | 6 +- 4 files changed, 140 insertions(+), 132 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f16f97bc21..788848cc48 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -322,8 +322,7 @@ private: }; /// A base class for the sun and moons. -/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. -class CelestialBody : public SceneUtil::StateSetUpdater +class CelestialBody { public: CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) @@ -336,14 +335,9 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); - - mGeode->addUpdateCallback(this); } - virtual ~CelestialBody() - { - mGeode->removeUpdateCallback(this); - } + virtual ~CelestialBody() {} virtual void adjustTransparency(const float ratio) = 0; @@ -365,31 +359,19 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { + mGeode->addUpdateCallback(mUpdater); } - virtual void setDefaults(osg::StateSet* stateset) + ~Sun() { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) - { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mColor.a() = ratio; + mUpdater->mColor.a() = ratio; } void setDirection(const osg::Vec3f& direction) @@ -403,8 +385,36 @@ public: } private: - Resource::TextureManager& mTextureManager; - osg::Vec4f mColor; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::Vec4f mColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) + { + } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + } + }; + + osg::ref_ptr mUpdater; }; class Moon : public CelestialBody @@ -418,53 +428,24 @@ public: Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) : CelestialBody(parentNode, scaleFactor, 2) - , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) - , mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { setPhase(MoonState::Phase_Full); setVisible(true); + + mGeode->addUpdateCallback(mUpdater); } - virtual void setDefaults(osg::StateSet *stateset) + ~Moon() { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) - { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mTransparency *= ratio; + mUpdater->mTransparency *= ratio; } void setState(const MoonState& state) @@ -484,18 +465,18 @@ public: mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - mTransparency = state.mMoonAlpha; - mShadowBlend = state.mShadowBlend; + mUpdater->mTransparency = state.mMoonAlpha; + mUpdater->mShadowBlend = state.mShadowBlend; } void setAtmosphereColor(const osg::Vec4f& color) { - mAtmosphereColor = color; + mUpdater->mAtmosphereColor = color; } void setColor(const osg::Vec4f& color) { - mMoonColor = color; + mUpdater->mMoonColor = color; } unsigned int getPhaseInt() const @@ -512,50 +493,102 @@ public: } private: - Resource::TextureManager& mTextureManager; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mPhaseTex() + , mCircleTex() + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mAtmosphereColor(1.0f, 1.0f, 1.0f, 1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + { + } + + virtual void setDefaults(osg::StateSet* stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + + reset(); + } + }; + Type mType; MoonState::Phase mPhase; - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; - - void setTextures(const std::string& phaseTex, const std::string& circleTex) - { - mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - - reset(); - } + osg::ref_ptr mUpdater; void setPhase(const MoonState::Phase& phase) { - if (mPhase == phase) + if(mPhase == phase) return; + mPhase = phase; std::string textureName = "textures/tx_"; - if (mType == Moon::Type_Secunda) textureName += "secunda_"; - else textureName += "masser_"; + if (mType == Moon::Type_Secunda) + textureName += "secunda_"; + else + textureName += "masser_"; - if (phase == MoonState::Phase_New) textureName += "new"; - else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; - else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; - else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == MoonState::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if(phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if(phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if(phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if(phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if(phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if(phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if(phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; if (mType == Moon::Type_Secunda) - setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); else - setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } }; @@ -621,11 +654,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); + mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); - mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); + mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -1067,11 +1100,11 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - mMasser->adjustTransparency(weather.mCelestialBodyTransparency); - mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); - mSun->adjustTransparency(weather.mCelestialBodyTransparency); + mMasser->adjustTransparency(weather.mGlareView); + mSecunda->adjustTransparency(weather.mGlareView); + mSun->adjustTransparency(weather.mGlareView); - float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) { mStarsOpacity = nextStarsOpacity; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 16509ef32c..4b1acadc37 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWRENDER_SKY_H #include +#include #include #include @@ -75,8 +76,6 @@ namespace MWRender float mRainSpeed; float mRainFrequency; - - float mCelestialBodyTransparency; }; struct MoonState @@ -179,9 +178,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSun; - osg::ref_ptr mMasser; - osg::ref_ptr mSecunda; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 679565e45f..c571b1d1dc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -294,54 +294,44 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; - clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; - rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; - overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; - blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; - snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; - blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -475,8 +465,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } - - mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) @@ -530,16 +518,6 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } - - const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; - const Weather& nextSettings = mWeatherSettings[mNextWeather]; - - if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = factor; - else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = 1 - factor; - else - mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 1bc3bc3577..d5ac6d8013 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -80,7 +80,8 @@ namespace MWWorld // Multiplier for clouds transparency float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect + // Value between 0 and 1, defines the strength of the sun glare effect. + // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; // Sound effect @@ -106,9 +107,6 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - - // Some weather patterns will obstruct the moons, sun, and stars. - bool mObstructsCelestialBodies; }; class MoonModel From 56b7196beaeb3c1ec8712605fa9d2ca9266f467a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 7 Aug 2015 15:34:01 +0200 Subject: [PATCH 0895/1812] Remove incorrect implementation of "Clouds Maximum Percent" weather setting --- apps/openmw/mwrender/sky.cpp | 12 ++++++------ apps/openmw/mwrender/sky.hpp | 3 --- apps/openmw/mwworld/weather.cpp | 3 --- apps/openmw/mwworld/weather.hpp | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 788848cc48..138365ae4f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -605,7 +605,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) - , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) @@ -666,12 +665,15 @@ void SkyManager::create() ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; + mCloudUpdater->setOpacity(1.f); mCloudMesh->addUpdateCallback(mCloudUpdater); mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); mCloudMesh2->accept(modClouds); mCloudUpdater2 = new CloudUpdater; + mCloudUpdater2->setOpacity(0.f); mCloudMesh2->addUpdateCallback(mCloudUpdater2); + mCloudMesh2->setNodeMask(0); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -1060,14 +1062,12 @@ void SkyManager::setWeather(const WeatherResult& weather) osg::Texture::REPEAT, osg::Texture::REPEAT)); } - if (mCloudBlendFactor != weather.mCloudBlendFactor - || mCloudOpacity != weather.mCloudOpacity) + if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - mCloudOpacity = weather.mCloudOpacity; - mCloudUpdater->setOpacity(mCloudOpacity * (1.f-mCloudBlendFactor)); - mCloudUpdater2->setOpacity(mCloudOpacity * mCloudBlendFactor); + mCloudUpdater->setOpacity((1.f-mCloudBlendFactor)); + mCloudUpdater2->setOpacity(mCloudBlendFactor); mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4b1acadc37..3855136a98 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -58,8 +58,6 @@ namespace MWRender float mCloudSpeed; - float mCloudOpacity; - float mGlareView; bool mNight; // use night skybox @@ -204,7 +202,6 @@ namespace MWRender std::string mClouds; std::string mNextClouds; float mCloudBlendFactor; - float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; osg::Vec4f mCloudColour; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c571b1d1dc..8d78b969ee 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -374,7 +374,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; - mResult.mCloudOpacity = current.mCloudsMaximumPercent; mResult.mWindSpeed = current.mWindSpeed; mResult.mCloudSpeed = current.mCloudSpeed; mResult.mGlareView = current.mGlareView; @@ -478,7 +477,6 @@ void WeatherManager::transition(float factor) mResult.mNextCloudTexture = other.mCloudTexture; mResult.mCloudBlendFactor = factor; - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); @@ -488,7 +486,6 @@ void WeatherManager::transition(float factor) mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d5ac6d8013..7f4858bc8d 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -77,7 +77,7 @@ namespace MWWorld // Cloud animation speed multiplier float mCloudSpeed; - // Multiplier for clouds transparency + // TODO: What is this supposed to do? float mCloudsMaximumPercent; // Value between 0 and 1, defines the strength of the sun glare effect. From 865491d1012c5bc2291fb7463f483c2cd045c244 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:06:33 -0400 Subject: [PATCH 0896/1812] Added a help message to niftest Now using the boost argument parser. --- apps/niftest/niftest.cpp | 66 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 20c8597f3d..fd060447c8 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -2,12 +2,17 @@ #include #include +#include #include #include #include #include +#include + +// Create local aliases for brevity +namespace bpo = boost::program_options; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -54,13 +59,68 @@ void readBSA(std::string filename) } } +std::vector parseOptions (int argc, char** argv) +{ + bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" + "Usages:\n" + " niftool \n" + " Scan the file for read errors.\n\n" + "Allowed options"); + desc.add_options() + ("help,h", "print help message.") + ("input-file", bpo::value< std::vector >(), "input file") + ; + + //Default option if none provided + bpo::positional_options_description p; + p.add("input-file", -1); + + bpo::variables_map variables; + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv). + options(desc).positional(p).run(); + bpo::store(valid_opts, variables); + } + catch(std::exception &e) + { + std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" + << desc << std::endl; + exit(1); + } + + bpo::notify(variables); + if (variables.count ("help")) + { + std::cout << desc << std::endl; + exit(1); + } + if (variables.count("input-file")) + { + std::vector files = variables["input-file"].as< std::vector >(); + + std::cout << "Input files are:"; + for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::cout <<" "<< *it; + } + std::cout << std::endl; + return files; + } + + std::cout << "No input files or directories specified!" << std::endl; + std::cout << desc << std::endl; + exit(1); +} + int main(int argc, char **argv) { + std::vector files = parseOptions (argc, argv); std::cout << "Reading Files" << std::endl; - for(int i = 1; i::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = *it; try{ if(isNIF(name)) From efadce3e906ccb0f23cca3554ea8e21efe9ce20c Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:20:31 -0400 Subject: [PATCH 0897/1812] Have niftest handle directories as well Note: BSA files within the directory must be passed manually. --- apps/niftest/niftest.cpp | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index fd060447c8..c138e45518 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -8,11 +8,14 @@ #include #include #include +#include #include +#include // Create local aliases for brevity namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -40,22 +43,30 @@ bool isBSA(std::string filename) return hasExtension(filename,"bsa"); } -///Check all the nif files in the given BSA archive -void readBSA(std::string filename) +/// Check all the nif files in a given VFS::Archive +/// \note Takes ownership! +void readVFS(VFS::Archive* anArchive) { VFS::Manager myManager(false); - myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.addArchive(anArchive); myManager.buildIndex(); std::map files=myManager.getIndex(); for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) { - std::string name = it->first; - if(isNIF(name)) - { -// std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); - } + std::string name = it->first; + + try{ + if(isNIF(name)) + { + // std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } + catch (std::exception& e) + { + std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl; + } } } @@ -97,15 +108,7 @@ std::vector parseOptions (int argc, char** argv) } if (variables.count("input-file")) { - std::vector files = variables["input-file"].as< std::vector >(); - - std::cout << "Input files are:"; - for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) - { - std::cout <<" "<< *it; - } - std::cout << std::endl; - return files; + return variables["input-file"].as< std::vector >(); } std::cout << "No input files or directories specified!" << std::endl; @@ -131,11 +134,16 @@ int main(int argc, char **argv) else if(isBSA(name)) { std::cout << "Reading BSA File: " << name << std::endl; - readBSA(name); + readVFS(new VFS::BsaArchive(name)); + } + else if(bfs::is_directory(bfs::path(name))) + { + std::cout << "Reading All Files in: " << name << std::endl; + readVFS(new VFS::FileSystemArchive(name)); } else { - std::cerr << "ERROR: \"" << name << "\" is not a nif or bsa file!" << std::endl; + std::cerr << "ERROR: \"" << name << "\" is not a nif file, bsa file, or directory!" << std::endl; } } catch (std::exception& e) From 6a6da42b85ed7a3cce05348b2f4b9b614539fe2f Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:22:18 -0400 Subject: [PATCH 0898/1812] Updated niftest's help message --- apps/niftest/niftest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c138e45518..c50e664b02 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -74,8 +74,8 @@ std::vector parseOptions (int argc, char** argv) { bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" "Usages:\n" - " niftool \n" - " Scan the file for read errors.\n\n" + " niftool \n" + " Scan the file or directories for nif errors.\n\n" "Allowed options"); desc.add_options() ("help,h", "print help message.") From 3d78ee0c2b9fff9e7dc801091f3c0a00fa159d91 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:39:43 -0400 Subject: [PATCH 0899/1812] niftest now scans BSA files in directories for nif errors The program is explicit so the user knows exactly where the bad file is. --- apps/niftest/niftest.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c50e664b02..6229d1e839 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,9 +45,9 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! -void readVFS(VFS::Archive* anArchive) +void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { - VFS::Manager myManager(false); + VFS::Manager myManager(true); myManager.addArchive(anArchive); myManager.buildIndex(); @@ -62,6 +62,15 @@ void readVFS(VFS::Archive* anArchive) // std::cout << "Decoding: " << name << std::endl; Nif::NIFFile temp_nif(myManager.get(name),name); } + else if(isBSA(name)) + { + if(!archivePath.empty()) + { + std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name)); + std::cout << "Done with BSA File: " << name << std::endl; + } + } } catch (std::exception& e) { @@ -139,7 +148,7 @@ int main(int argc, char **argv) else if(bfs::is_directory(bfs::path(name))) { std::cout << "Reading All Files in: " << name << std::endl; - readVFS(new VFS::FileSystemArchive(name)); + readVFS(new VFS::FileSystemArchive(name),name); } else { From c7b97ee9bab59c5e11c7237505c108fac58b1692 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:49:52 -0400 Subject: [PATCH 0900/1812] Cleaned up niftest's output A bad file inside of a bsa archive now looks like: /Data Files/TR_Data.bsa/meshes/tr/x/tr_act_ind_mark_alm.nif --- apps/niftest/niftest.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 6229d1e839..72393db40b 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,6 +45,7 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! +/// \note Can not read a bsa file inside of a bsa file. void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { VFS::Manager myManager(true); @@ -60,15 +61,15 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "") if(isNIF(name)) { // std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); + Nif::NIFFile temp_nif(myManager.get(name),archivePath+name); } else if(isBSA(name)) { - if(!archivePath.empty()) + if(!archivePath.empty() && !isBSA(archivePath)) { - std::cout << "Reading BSA File: " << name << std::endl; - readVFS(new VFS::BsaArchive(archivePath+name)); - std::cout << "Done with BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name),archivePath+name+"/"); +// std::cout << "Done with BSA File: " << name << std::endl; } } } @@ -129,7 +130,7 @@ int main(int argc, char **argv) { std::vector files = parseOptions (argc, argv); - std::cout << "Reading Files" << std::endl; +// std::cout << "Reading Files" << std::endl; for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) { std::string name = *it; @@ -142,12 +143,12 @@ int main(int argc, char **argv) } else if(isBSA(name)) { - std::cout << "Reading BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; readVFS(new VFS::BsaArchive(name)); } else if(bfs::is_directory(bfs::path(name))) { - std::cout << "Reading All Files in: " << name << std::endl; +// std::cout << "Reading All Files in: " << name << std::endl; readVFS(new VFS::FileSystemArchive(name),name); } else From 20078c41c36dfb7d2f482f2c0078cd73d1fb4bf9 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:53:43 -0400 Subject: [PATCH 0901/1812] Removed now unneeded script --- apps/niftest/find_bad_nifs.sh | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100755 apps/niftest/find_bad_nifs.sh diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh deleted file mode 100755 index 4b599f4427..0000000000 --- a/apps/niftest/find_bad_nifs.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#Script to test all nif files (both loose, and in BSA archives) in data files directory - -#The user input as an absolute path -DATAFILESDIR="`readlink -m "$1"`" -#Program used to test -TEST_PROG="`pwd`/niftest" - -#Make sure our files don't bother anyone -NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" -mkdir "$NIFTEST_TMP_DIR" -cd "$NIFTEST_TMP_DIR" - -find "$DATAFILESDIR" -iname *bsa > nifs.txt -find "$DATAFILESDIR" -iname *nif >> nifs.txt - -sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt - -xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt -# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null - -echo "List of bad NIF Files:" -cat nif_out.txt|grep File:|cut -d ' ' -f 2- - -rm nifs.txt -rm quoted_nifs.txt -rm nif_out.txt -rmdir "$NIFTEST_TMP_DIR" From 3046795a9c1197ed7fc9766fe78de84e37da1672 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 11:01:08 +0200 Subject: [PATCH 0902/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 291b0d56c7..16c8882393 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -29,6 +29,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) darkf + Dieho Dmitry Shkurskiy (endorph) Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) From 708cacdec403793a0337c6e536a1ecf53a58bd6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 16:47:58 +0200 Subject: [PATCH 0903/1812] disable merge menu item when a merge is already in progress --- apps/opencs/view/doc/view.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index df7421a14a..ea11bb0f9a 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -398,7 +398,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); - mMerge->setEnabled (mDocument->getContentFiles().size()>1); + mMerge->setEnabled (mDocument->getContentFiles().size()>1 && + !(mDocument->getState() & CSMDoc::State_Merging)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) From 1676bf917e60f8a0d0614d628be779b0f65d6e28 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:06:52 +1200 Subject: [PATCH 0904/1812] CombatMove logic moved into AiCombatStorage. Basically, copied from mrcheko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 91 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f386ec81be..c8876c8420 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -110,6 +110,10 @@ namespace MWMechanics mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} + + void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); + void updateCombatMove(float duration); + void stopCombatMove(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -192,19 +196,8 @@ namespace MWMechanics //Update every frame - bool& combatMove = storage.mCombatMove; - float& timerCombatMove = storage.mTimerCombatMove; + storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; - if(combatMove) - { - timerCombatMove -= duration; - if( timerCombatMove <= 0) - { - timerCombatMove = 0; - movement.mPosition[1] = movement.mPosition[0] = 0; - combatMove = false; - } - } UpdateActorsMovement(actor, movement); @@ -454,31 +447,12 @@ namespace MWMechanics if (followTarget && distToTarget > rangeAttack) { //Close-up combat: just run up on target + storage.stopCombatMove(); movement.mPosition[1] = 1; } else // (within attack dist) { - if(movement.mPosition[0] || movement.mPosition[1]) - { - storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - // only NPCs are smart enough to use dodge movements - else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) - { - //apply sideway movement (kind of dodging) with some probability - if (Misc::Rng::rollClosedProbability() < 0.25) - { - movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - } - - if(distantCombat && distToTarget < rangeAttack/4) - { - movement.mPosition[1] = -1; - } + storage.startCombatMove(actorClass.isNpc(), distantCombat, distToTarget, rangeAttack); readyToAttack = true; //only once got in melee combat, actor is allowed to use close-up shortcutting @@ -551,14 +525,13 @@ namespace MWMechanics } } - movement.mPosition[1] = 1; if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - storage.mCombatMove = true; - storage.mTimerCombatMove = 0; + storage.stopCombatMove(); + readyToAttack = false; } - readyToAttack = false; + movement.mPosition[1] = 1; } return false; @@ -663,6 +636,50 @@ namespace MWMechanics package.mPackage = combat.release(); sequence.mPackages.push_back(package); } + + void AiCombatStorage::startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack) + { + if (mMovement.mPosition[0] || mMovement.mPosition[1]) + { + mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + // only NPCs are smart enough to use dodge movements + else if (isNpc && (!isDistantCombat || (distToTarget < rangeAttack / 2))) + { + //apply sideway movement (kind of dodging) with some probability + if (Misc::Rng::rollClosedProbability() < 0.25) + { + mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + } + + if (isDistantCombat && distToTarget < rangeAttack / 4) + { + mMovement.mPosition[1] = -1; + } + } + + void AiCombatStorage::updateCombatMove(float duration) + { + if (mCombatMove) + { + mTimerCombatMove -= duration; + if (mTimerCombatMove <= 0) + { + stopCombatMove(); + } + } + } + + void AiCombatStorage::stopCombatMove() + { + mTimerCombatMove = 0; + mMovement.mPosition[1] = mMovement.mPosition[0] = 0; + mCombatMove = false; + } } From 0735e3e06e3c3a1241ea78ec402a28e38f8331e1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:08:42 +1200 Subject: [PATCH 0905/1812] move start attack logic to AiCombatStorage. Basically, copied from mrchenko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 82 +++++++++++++++------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c8876c8420..03dc91c0a5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -114,6 +114,8 @@ namespace MWMechanics void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); void updateCombatMove(float duration); void stopCombatMove(); + void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -194,7 +196,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - //Update every frame storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; @@ -318,41 +319,9 @@ namespace MWMechanics } - float& strength = storage.mStrength; bool& readyToAttack = storage.mReadyToAttack; // start new attack - if(readyToAttack && characterController.readyToStartAttack()) - { - if (storage.mAttackCooldown <= 0) - { - storage.mAttack = true; // attack starts just now - characterController.setAttackingOrSpell(true); - - if (!distantCombat) - chooseBestAttack(weapon, movement); - - strength = Misc::Rng::rollClosedProbability(); - - const MWWorld::ESMStore &store = world->getStore(); - - //say a provoking combat phrase - if (actor.getClass().isNpc()) - { - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } - } - float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); - if (actor.getClass().isNpc()) - baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); - storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); - } - else - storage.mAttackCooldown -= REACTION_INTERVAL; - } - + storage.startAttackIfReady(actor, characterController, weapon, distantCombat); /* * Some notes on meanings of variables: @@ -403,9 +372,6 @@ namespace MWMechanics bool canMoveByZ = (actorClass.canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor); - // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack - bool inLOS = distantCombat ? world->getLOS(actor, target) : true; - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. if (distToTarget >= rangeAttack && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) @@ -419,6 +385,9 @@ namespace MWMechanics return false; } + // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack + bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { @@ -432,7 +401,8 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -680,6 +650,42 @@ namespace MWMechanics mMovement.mPosition[1] = mMovement.mPosition[0] = 0; mCombatMove = false; } + + void AiCombatStorage::startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat) + { + if (mReadyToAttack && characterController.readyToStartAttack()) + { + if (mAttackCooldown <= 0) + { + mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); + + if (!distantCombat) + chooseBestAttack(weapon, mMovement); + + mStrength = Misc::Rng::rollClosedProbability(); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + + float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + if (actor.getClass().isNpc()) + { + baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + + //say a provoking combat phrase + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } + } + mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); + } + else + mAttackCooldown -= REACTION_INTERVAL; + } + } } From 50ddcd19532756016d668f38baa071009f98d208 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:10:08 +1200 Subject: [PATCH 0906/1812] more attack logic moved into AiCombatStorage. --- apps/openmw/mwmechanics/aicombat.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 03dc91c0a5..a5a48991a8 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -116,6 +116,7 @@ namespace MWMechanics void stopCombatMove(); void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); + void updateAttack(CharacterController& characterController); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -201,12 +202,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; UpdateActorsMovement(actor, movement); - - bool& attack = storage.mAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) - attack = false; - - characterController.setAttackingOrSpell(attack); + storage.updateAttack(characterController); float& actionCooldown = storage.mActionCooldown; actionCooldown -= duration; @@ -686,6 +682,15 @@ namespace MWMechanics mAttackCooldown -= REACTION_INTERVAL; } } + + void AiCombatStorage::updateAttack(CharacterController& characterController) + { + if (mAttack && (characterController.getAttackStrength() >= mStrength || characterController.readyToPrepareAttack())) + { + mAttack = false; + } + characterController.setAttackingOrSpell(mAttack); + } } From 038851420d5615d7ce470bd83312e0b3d00ee180 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:18:55 +1200 Subject: [PATCH 0907/1812] Removed unneeded temp variables. Corrected case of function names. --- apps/openmw/mwmechanics/aicombat.cpp | 16 ++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 4 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a5a48991a8..b1889605d8 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -199,13 +199,9 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - MWMechanics::Movement& movement = storage.mMovement; - - UpdateActorsMovement(actor, movement); + updateActorsMovement(actor, storage.mMovement); storage.updateAttack(characterController); - - float& actionCooldown = storage.mActionCooldown; - actionCooldown -= duration; + storage.mActionCooldown -= duration; float& timerReact = storage.mTimerReact; if(timerReact < REACTION_INTERVAL) @@ -503,7 +499,7 @@ namespace MWMechanics return false; } - void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -522,12 +518,12 @@ namespace MWMechanics else { actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); } } - void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void AiCombat::rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) { actorMovementSettings.mRotation[axis] = 0; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 4e40608196..73d0254f3b 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,8 +65,8 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); - void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 0884a3796f7e6174bf93b1b4311680faa1c67b0a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:20:55 +1200 Subject: [PATCH 0908/1812] extracted function isTargetMagicallyHidden(). --- apps/openmw/mwmechanics/aicombat.cpp | 3 +-- apps/openmw/mwmechanics/aipackage.cpp | 8 ++++++++ apps/openmw/mwmechanics/aipackage.hpp | 2 ++ apps/openmw/mwmechanics/aipursue.cpp | 3 +-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b1889605d8..8a51a4cb07 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -222,8 +222,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) { movement.mPosition[1] = movement.mPosition[0] = 0; return false; // TODO: run away instead of doing nothing diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 77efe62a88..d10edd5891 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -129,3 +130,10 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const { return distance(mPrevDest, dest) > 10; } + +bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) +{ + MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) + || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index da43dc6dae..d73833b948 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,8 @@ namespace MWMechanics /// Simulates the passing of time virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); + protected: /// Causes the actor to attempt to walk to the specified location /** \return If the actor has arrived at his destination **/ diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index e936505c93..055801fde0 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -43,8 +43,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte ) return true; //Target doesn't exist - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) return true; if(target.getClass().getCreatureStats(target).isDead()) From 2b9e22f593ebc862cfdc1df070249725e760a460 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:29:38 +1200 Subject: [PATCH 0909/1812] extracted function stopAttack(). --- apps/openmw/mwmechanics/aicombat.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 8a51a4cb07..5ea3ba6a3b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -117,6 +117,7 @@ namespace MWMechanics void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); void updateAttack(CharacterController& characterController); + void stopAttack(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -221,10 +222,9 @@ namespace MWMechanics { MWMechanics::Movement& movement = storage.mMovement; - // Stop attacking if target is not seen if (isTargetMagicallyHidden(target)) { - movement.mPosition[1] = movement.mPosition[0] = 0; + storage.stopAttack(); return false; // TODO: run away instead of doing nothing } @@ -368,11 +368,7 @@ namespace MWMechanics && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) { // TODO: start fleeing? - movement.mPosition[0] = 0; - movement.mPosition[1] = 0; - movement.mPosition[2] = 0; - readyToAttack = false; - characterController.setAttackingOrSpell(false); + storage.stopAttack(); return false; } @@ -686,6 +682,15 @@ namespace MWMechanics } characterController.setAttackingOrSpell(mAttack); } + + void AiCombatStorage::stopAttack() + { + mMovement.mPosition[0] = 0; + mMovement.mPosition[1] = 0; + mMovement.mPosition[2] = 0; + mReadyToAttack = false; + mAttack = false; + } } From e42a2478dcae9445d72c48384658c682acc11f42 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 17:58:40 +1200 Subject: [PATCH 0910/1812] Removed tests that are not necessary. --- apps/openmw/mwmechanics/pathfinding.cpp | 80 ++++++++++++------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index c7d71e13e6..f469832a51 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -51,8 +51,7 @@ namespace const MWWorld::CellStore *cell, const osg::Vec3f pos, int start) { - if(!grid || grid->mPoints.empty()) - return std::pair (-1, false); + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -76,8 +75,6 @@ namespace // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. - //if(start == closestReachableIndex) - //closestReachableIndex = -1; // couldn't find anyting other than start return std::pair (closestReachableIndex, closestReachableIndex == closestIndex); @@ -110,6 +107,11 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } + osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) + { + return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); + } + PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -139,8 +141,6 @@ namespace MWMechanics * pathgrid point (e.g. wander) then it may be worth while to call * pop_back() to remove the redundant entry. * - * mPathConstructed is set true if successful, false if not - * * NOTE: co-ordinates must be converted prior to calling getClosestPoint() * * | @@ -208,46 +208,40 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - int startNode = getClosestPoint(mPathgrid, - osg::Vec3f(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); - // Some cells don't have any pathgrids at all - if(startNode != -1) + osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); + + osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + std::pair endNode = getClosestReachablePoint(mPathgrid, cell, + endPointInLocalCoords, + startNode); + + // AiWander has logic that depends on whether a path was created, + // deleting allowed nodes if not. Hence a path needs to be created + // even if the start and the end points are the same. + // NOTE: aStarSearch will return an empty path if the start and end + // nodes are the same + if(startNode == endNode.first) { - std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - osg::Vec3f(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), - startNode); + mPath.push_back(endPoint); + return; + } - // this shouldn't really happen, but just in case - if(endNode.first != -1) - { - // AiWander has logic that depends on whether a path was created, - // deleting allowed nodes if not. Hence a path needs to be created - // even if the start and the end points are the same. - // NOTE: aStarSearch will return an empty path if the start and end - // nodes are the same - if(startNode == endNode.first) - { - mPath.push_back(endPoint); - return; - } + mPath = mCell->aStarSearch(startNode, endNode.first); - mPath = mCell->aStarSearch(startNode, endNode.first); - - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } - } + if(!mPath.empty()) + { + // Add the destination (which may be different to the closest + // pathgrid point). However only add if endNode was the closest + // point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); } return; From 55e3aaaa35c491ecd24edc74094c66c42ab3c3ef Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 10 Aug 2015 20:30:43 +1200 Subject: [PATCH 0911/1812] made variable const. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index d10edd5891..1ab3264b7b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -133,7 +133,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) { - MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + const MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } From 5fba7400a6320b5b8e943635719be9384d3ada7c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:17:26 +0200 Subject: [PATCH 0912/1812] Borrow modified bundle utilities from https://github.com/Slicer/Slicer They support dependencies with @rpath --- cmake/BundleUtilitiesWithRPath.cmake | 961 +++++++++++++++++++++++++ cmake/COPYING-CMAKE-SCRIPTS | 266 +++++++ cmake/GetPrerequisitesWithRPath.cmake | 990 ++++++++++++++++++++++++++ 3 files changed, 2217 insertions(+) create mode 100644 cmake/BundleUtilitiesWithRPath.cmake create mode 100644 cmake/GetPrerequisitesWithRPath.cmake diff --git a/cmake/BundleUtilitiesWithRPath.cmake b/cmake/BundleUtilitiesWithRPath.cmake new file mode 100644 index 0000000000..5254e1a529 --- /dev/null +++ b/cmake/BundleUtilitiesWithRPath.cmake @@ -0,0 +1,961 @@ +#.rst: +# BundleUtilities +# --------------- +# +# Functions to help assemble a standalone bundle application. +# +# A collection of CMake utility functions useful for dealing with .app +# bundles on the Mac and bundle-like directories on any OS. +# +# The following functions are provided by this module: +# +# :: +# +# fixup_bundle +# copy_and_fixup_bundle +# verify_app +# get_bundle_main_executable +# get_dotapp_dir +# get_bundle_and_executable +# get_bundle_all_executables +# get_item_key +# clear_bundle_keys +# set_bundle_key_values +# get_bundle_keys +# copy_resolved_item_into_bundle +# copy_resolved_framework_into_bundle +# fixup_bundle_item +# verify_bundle_prerequisites +# verify_bundle_symlinks +# +# Requires CMake 2.6 or greater because it uses function, break and +# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. +# +# :: +# +# FIXUP_BUNDLE( ) +# +# Fix up a bundle in-place and make it standalone, such that it can be +# drag-n-drop copied to another machine and run on that machine as long +# as all of the system libraries are compatible. +# +# If you pass plugins to fixup_bundle as the libs parameter, you should +# install them or copy them into the bundle before calling fixup_bundle. +# The "libs" parameter is a list of libraries that must be fixed up, but +# that cannot be determined by otool output analysis. (i.e., plugins) +# +# Gather all the keys for all the executables and libraries in a bundle, +# and then, for each key, copy each prerequisite into the bundle. Then +# fix each one up according to its own list of prerequisites. +# +# Then clear all the keys and call verify_app on the final bundle to +# ensure that it is truly standalone. +# +# :: +# +# COPY_AND_FIXUP_BUNDLE( ) +# +# Makes a copy of the bundle at location and then fixes up +# the new copied bundle in-place at ... +# +# :: +# +# VERIFY_APP() +# +# Verifies that an application appears valid based on running +# analysis tools on it. Calls "message(FATAL_ERROR" if the application +# is not verified. +# +# :: +# +# GET_BUNDLE_MAIN_EXECUTABLE( ) +# +# The result will be the full path name of the bundle's main executable +# file or an "error:" prefixed string if it could not be determined. +# +# :: +# +# GET_DOTAPP_DIR( ) +# +# Returns the nearest parent dir whose name ends with ".app" given the +# full path to an executable. If there is no such parent dir, then +# simply return the dir containing the executable. +# +# The returned directory may or may not exist. +# +# :: +# +# GET_BUNDLE_AND_EXECUTABLE( ) +# +# Takes either a ".app" directory name or the name of an executable +# nested inside a ".app" directory and returns the path to the ".app" +# directory in and the path to its main executable in +# +# +# :: +# +# GET_BUNDLE_ALL_EXECUTABLES( ) +# +# Scans the given bundle recursively for all executable files and +# accumulates them into a variable. +# +# :: +# +# GET_ITEM_KEY( ) +# +# Given a file (item) name, generate a key that should be unique +# considering the set of libraries that need copying or fixing up to +# make a bundle standalone. This is essentially the file name including +# extension with "." replaced by "_" +# +# This key is used as a prefix for CMake variables so that we can +# associate a set of variables with a given item based on its key. +# +# :: +# +# CLEAR_BUNDLE_KEYS() +# +# Loop over the list of keys, clearing all the variables associated with +# each key. After the loop, clear the list of keys itself. +# +# Caller of get_bundle_keys should call clear_bundle_keys when done with +# list of keys. +# +# :: +# +# SET_BUNDLE_KEY_VALUES( +# ) +# +# Add a key to the list (if necessary) for the given item. If added, +# also set all the variables associated with that key. +# +# :: +# +# GET_BUNDLE_KEYS( ) +# +# Loop over all the executable and library files within the bundle (and +# given as extra ) and accumulate a list of keys representing +# them. Set values associated with each key such that we can loop over +# all of them and copy prerequisite libs into the bundle and then do +# appropriate install_name_tool fixups. +# +# :: +# +# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) +# +# Copy a resolved item into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# :: +# +# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) +# +# Copy a resolved framework into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want +# full frameworks embedded in your bundles, set +# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By +# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework +# dylib itself plus the framework Resources directory. +# +# :: +# +# IS_RESOLVED_ITEM_EMBEDDED( ) +# +# Set variable to True if the resolved item is +# embedded into the bundle. The function does NOT check for the existence of the +# item, instead if checks if the provided path would correspond to an embeddable +# item. If is True, extra information will be displayed in case the item +# is not embedded. +# +# :: +# +# FIXUP_BUNDLE_ITEM( ) +# +# Get the direct/non-system prerequisites of the resolved embedded item. +# For each prerequisite, change the way it is referenced to the value of +# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely +# changing to an "@executable_path" style reference.) +# +# This function requires that the resolved_embedded_item be "inside" the +# bundle already. In other words, if you pass plugins to fixup_bundle +# as the libs parameter, you should install them or copy them into the +# bundle before calling fixup_bundle. The "libs" parameter is a list of +# libraries that must be fixed up, but that cannot be determined by +# otool output analysis. (i.e., plugins) +# +# Also, change the id of the item being fixed up to its own +# _EMBEDDED_ITEM value. +# +# Accumulate changes in a local variable and make *one* call to +# install_name_tool at the end of the function with all the changes at +# once. +# +# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be +# marked writable before install_name_tool tries to change them. +# +# :: +# +# VERIFY_BUNDLE_PREREQUISITES( ) +# +# Verifies that the sum of all prerequisites of all files inside the +# bundle are contained within the bundle or are "system" libraries, +# presumed to exist everywhere. +# +# :: +# +# VERIFY_BUNDLE_SYMLINKS( ) +# +# Verifies that any symlinks found in the bundle point to other files +# that are already also in the bundle... Anything that points to an +# external file causes this function to fail the verification. + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# The functions defined in this file depend on the get_prerequisites function +# (and possibly others) found in: +# +get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +include("${BundleUtilities_cmake_dir}/GetPrerequisitesWithRPath.cmake") + + +function(get_bundle_main_executable bundle result_var) + set(result "error: '${bundle}/Contents/Info.plist' file does not exist") + + if(EXISTS "${bundle}/Contents/Info.plist") + set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") + set(line_is_main_executable 0) + set(bundle_executable "") + + # Read Info.plist as a list of lines: + # + set(eol_char "E") + file(READ "${bundle}/Contents/Info.plist" info_plist) + string(REPLACE ";" "\\;" info_plist "${info_plist}") + string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") + string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") + + # Scan the lines for "CFBundleExecutable" - the line after that + # is the name of the main executable. + # + foreach(line ${info_plist}) + if(line_is_main_executable) + string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") + break() + endif() + + if(line MATCHES "CFBundleExecutable") + set(line_is_main_executable 1) + endif() + endforeach() + + if(NOT "${bundle_executable}" STREQUAL "") + if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") + set(result "${bundle}/Contents/MacOS/${bundle_executable}") + else() + + # Ultimate goal: + # If not in "Contents/MacOS" then scan the bundle for matching files. If + # there is only one executable file that matches, then use it, otherwise + # it's an error... + # + #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") + + # But for now, pragmatically, it's an error. Expect the main executable + # for the bundle to be in Contents/MacOS, it's an error if it's not: + # + set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") + endif() + endif() + else() + # + # More inclusive technique... (This one would work on Windows and Linux + # too, if a developer followed the typical Mac bundle naming convention...) + # + # If there is no Info.plist file, try to find an executable with the same + # base name as the .app directory: + # + endif() + + set(${result_var} "${result}" PARENT_SCOPE) +endfunction() + + +function(get_dotapp_dir exe dotapp_dir_var) + set(s "${exe}") + + if(s MATCHES "/.*\\.app/") + # If there is a ".app" parent directory, + # ascend until we hit it: + # (typical of a Mac bundle executable) + # + set(done 0) + while(NOT ${done}) + get_filename_component(snamewe "${s}" NAME_WE) + get_filename_component(sname "${s}" NAME) + get_filename_component(sdir "${s}" PATH) + set(s "${sdir}") + if(sname MATCHES "\\.app$") + set(done 1) + set(dotapp_dir "${sdir}/${sname}") + endif() + endwhile() + else() + # Otherwise use a directory containing the exe + # (typical of a non-bundle executable on Mac, Windows or Linux) + # + is_file_executable("${s}" is_executable) + if(is_executable) + get_filename_component(sdir "${s}" PATH) + set(dotapp_dir "${sdir}") + else() + set(dotapp_dir "${s}") + endif() + endif() + + + set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) +endfunction() + + +function(get_bundle_and_executable app bundle_var executable_var valid_var) + set(valid 0) + + if(EXISTS "${app}") + # Is it a directory ending in .app? + if(IS_DIRECTORY "${app}") + if(app MATCHES "\\.app$") + get_bundle_main_executable("${app}" executable) + if(EXISTS "${app}" AND EXISTS "${executable}") + set(${bundle_var} "${app}" PARENT_SCOPE) + set(${executable_var} "${executable}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled .app directory case...") + else() + message(STATUS "warning: *NOT* handled - .app directory case...") + endif() + else() + message(STATUS "warning: *NOT* handled - directory but not .app case...") + endif() + else() + # Is it an executable file? + is_file_executable("${app}" is_executable) + if(is_executable) + get_dotapp_dir("${app}" dotapp_dir) + if(EXISTS "${dotapp_dir}") + set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in .app dir case...") + else() + get_filename_component(app_dir "${app}" PATH) + set(${bundle_var} "${app_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in any dir case...") + endif() + else() + message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") + endif() + endif() + else() + message(STATUS "warning: *NOT* handled - directory/file does not exist...") + endif() + + if(NOT valid) + set(${bundle_var} "error: not a bundle" PARENT_SCOPE) + set(${executable_var} "error: not a bundle" PARENT_SCOPE) + endif() + + set(${valid_var} ${valid} PARENT_SCOPE) +endfunction() + + +function(get_bundle_all_executables bundle exes_var) + set(exes "") + + file(GLOB_RECURSE file_list "${bundle}/*") + if(UNIX) + find_program(find_cmd "find") + mark_as_advanced(find_cmd) + endif() + + # find command is much quicker than checking every file one by one on Unix + # which can take long time for large bundles, and since anyway we expect + # executable to have execute flag set we can narrow the list much quicker. + if(find_cmd) + execute_process(COMMAND "${find_cmd}" "${bundle}" + -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) + OUTPUT_VARIABLE file_list + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REPLACE "\n" ";" file_list "${file_list}") + else() + file(GLOB_RECURSE file_list "${bundle}/*") + endif() + + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + set(exes ${exes} "${f}") + endif() + endforeach() + + set(${exes_var} "${exes}" PARENT_SCOPE) +endfunction() + + +function(get_item_key item key_var) + get_filename_component(item_name "${item}" NAME) + if(WIN32) + string(TOLOWER "${item_name}" item_name) + endif() + string(REPLACE "." "_" ${key_var} "${item_name}") + set(${key_var} ${${key_var}} PARENT_SCOPE) +endfunction() + + +function(clear_bundle_keys keys_var) + foreach(key ${${keys_var}}) + set(${key}_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_ITEM PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_COPYFLAG PARENT_SCOPE) + endforeach() + set(${keys_var} PARENT_SCOPE) +endfunction() + + +function(set_bundle_key_values keys_var context item exepath dirs copyflag) + get_filename_component(item_name "${item}" NAME) + + get_item_key("${item}" key) + + list(LENGTH ${keys_var} length_before) + gp_append_unique(${keys_var} "${key}") + list(LENGTH ${keys_var} length_after) + + if(NOT length_before EQUAL length_after) + gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) + + gp_item_default_embedded_path("${item}" default_embedded_path) + + if(item MATCHES "[^/]+\\.framework/") + # For frameworks, construct the name under the embedded path from the + # opening "${item_name}.framework/" to the closing "/${item_name}": + # + string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") + else() + # For other items, just use the same name as the original, but in the + # embedded path: + # + set(embedded_item "${default_embedded_path}/${item_name}") + + if(APPLE) + # For executables inside the bundle, extract the expected path. + # This remove the hack introduced in commit 6f8bdd27 consisting in + # reseting the value of 'resolved_embedded_item' with 'resolved_item'. + get_dotapp_dir("${exepath}" exe_dotapp_dir) + if(NOT DEFINED gp_bundle_executables) + get_bundle_all_executables("${exe_dotapp_dir}" gp_bundle_executables) + endif() + foreach(exe ${gp_bundle_executables}) + get_item_key("${exe}" exe_key) + list(APPEND exe_keys ${exe_key}) + endforeach() + list(FIND exe_keys ${key} is_executable) + if(NOT is_executable EQUAL "-1") + get_filename_component(resolved_item_path ${resolved_item} PATH) + file(RELATIVE_PATH exe_relative_path_from_dir ${exe_dotapp_dir} ${resolved_item_path}) + # For example, if input variables are: + # resolved_item: /path/to/MyApp.app/Contents/bin/myapp + # exe_dotapp_dir: /path/to/MyApp.app + # Computed variables will be: + # resolved_item_path: /path/to/MyApp.app/Contents/bin + # exe_relative_path_from_dir: Contents/bin + set(embedded_item "@executable_path/../../${exe_relative_path_from_dir}/${item_name}") + set(show_status 0) + if(show_status) + message(STATUS "resolved_item='${resolved_item}'") + message(STATUS "exe_dotapp_dir='${exe_dotapp_dir}'") + message(STATUS "exe_relative_path_from_dir='${exe_relative_path_from_dir}'") + message(STATUS "item_name='${item_name}'") + message(STATUS "embedded_item='${embedded_item}'") + message(STATUS "") + endif() + endif() + endif() + endif() + + gp_resolve_embedded_item("${context}" "${embedded_item}" "${exepath}" resolved_embedded_item) + get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) + + # Do not copy already embedded item + set(verbose 0) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(EXISTS "${resolved_embedded_item}" AND is_embedded) + set(copyflag 0) + set(resolved_item "${resolved_embedded_item}") + endif() + + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + set(${key}_ITEM "${item}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) + set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) + else() + #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") + endif() +endfunction() + + +function(get_bundle_keys app libs dirs keys_var) + set(${keys_var} PARENT_SCOPE) + + get_bundle_and_executable("${app}" bundle executable valid) + if(valid) + # Always use the exepath of the main bundle executable for @executable_path + # replacements: + # + get_filename_component(exepath "${executable}" PATH) + + # But do fixups on all executables in the bundle: + # + get_bundle_all_executables("${bundle}" gp_bundle_executables) + + # For each extra lib, accumulate a key as well and then also accumulate + # any of its prerequisites. (Extra libs are typically dynamically loaded + # plugins: libraries that are prerequisites for full runtime functionality + # but that do not show up in otool -L output...) + # + foreach(lib ${libs}) + set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) + + set(prereqs "") + get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # For each executable found in the bundle, accumulate keys as we go. + # The list of keys should be complete when all prerequisites of all + # binaries in the bundle have been analyzed. + # + foreach(exe ${gp_bundle_executables}) + # Add the exe itself to the keys: + # + set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) + + # Add each prerequisite to the keys: + # + set(prereqs "") + get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # Propagate values to caller's scope: + # + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + foreach(key ${${keys_var}}) + set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) + endforeach() + endif() +endfunction() + + +function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + + +function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + if(BU_COPY_FULL_FRAMEWORK_CONTENTS) + # Full Framework (everything): + get_filename_component(resolved_dir "${resolved_item}" PATH) + get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) + get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) + get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") + else() + # Framework lib itself: + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + + # Plus Resources, if they exist: + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") + if(EXISTS "${resolved_resources}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") + endif() + + # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is + # missing in resources, copy it from other well known incorrect locations: + if(NOT EXISTS "${resolved_resources}/Info.plist") + # Check for Contents/Info.plist in framework root (older Qt SDK): + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") + if(EXISTS "${resolved_info_plist}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") + endif() + endif() + + # Check if framework is versioned and fix it layout + string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") + if(resolved_embedded_versions_basename STREQUAL "Versions") + # Ensure Current symlink points to the framework version + if(NOT EXISTS "${resolved_embedded_versions}/Current") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") + endif() + # Restore symlinks in framework root pointing to current framework + # binary and resources: + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}") + if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}") + endif() + if(NOT EXISTS "${resolved_embedded_root}/Resources") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources") + endif() + endif() + endif() + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + +function(is_resolved_item_embedded resolved_item exepath verbose is_embedded_var) + get_dotapp_dir("${exepath}" exe_dotapp_dir) + string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) + string(LENGTH "${resolved_item}" resolved_item_length) + set(path_too_short 0) + set(is_embedded 0) + if(${resolved_item_length} LESS ${exe_dotapp_dir_length}) + set(path_too_short 1) + endif() + if(NOT path_too_short) + string(SUBSTRING "${resolved_item}" 0 ${exe_dotapp_dir_length} item_substring) + if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") + set(is_embedded 1) + endif() + endif() + if(verbose AND NOT is_embedded) + message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") + message(" item_substring='${item_substring}'") + message(" resolved_item='${resolved_item}'") + message("") + endif() + set(${is_embedded_var} ${is_embedded} PARENT_SCOPE) +endfunction() + +function(fixup_bundle_item resolved_embedded_item exepath dirs) + # This item's key is "ikey": + # + get_item_key("${resolved_embedded_item}" ikey) + + # Ensure the item is "inside the .app bundle" -- it should not be fixed up if + # it is not in the .app bundle... Otherwise, we'll modify files in the build + # tree, or in other varied locations around the file system, with our call to + # install_name_tool. Make sure that doesn't happen here: + # + set(verbose 1) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(NOT is_embedded) + message("Install or copy the item into the bundle before calling fixup_bundle.") + message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") + message("") + message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") + endif() + + set(prereqs "") + get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") + + set(changes "") + + foreach(pr ${prereqs}) + # Each referenced item's key is "rkey" in the loop: + # + get_item_key("${pr}" rkey) + + if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") + set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") + else() + message("warning: unexpected reference to '${pr}'") + endif() + endforeach() + + if(BU_CHMOD_BUNDLE_ITEMS) + execute_process(COMMAND chmod u+w "${resolved_embedded_item}") + endif() + + # Change this item's id and all of its references in one call + # to install_name_tool: + # + execute_process(COMMAND install_name_tool + ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" + ) +endfunction() + + +function(fixup_bundle app libs dirs) + message(STATUS "fixup_bundle") + message(STATUS " app='${app}'") + message(STATUS " libs='${libs}'") + message(STATUS " dirs='${dirs}'") + + get_bundle_and_executable("${app}" bundle executable valid) + message(STATUS " bundle='${bundle}'") + message(STATUS " executable='${executable}'") + if(valid) + get_filename_component(exepath "${executable}" PATH) + + # TODO: Extract list of rpath dirs automatically. On MacOSX, the following could be + # done: otool -l path/to/executable | grep -A 3 LC_RPATH | grep path + # See http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html#comment-87ea054b4839586412727dcfc94c79d2 + set(GP_RPATH_DIR ${bundle}/Contents) + message(STATUS " GP_RPATH_DIR='${GP_RPATH_DIR}'") + + message(STATUS "fixup_bundle: preparing...") + get_bundle_keys("${app}" "${libs}" "${dirs}" keys) + + message(STATUS "fixup_bundle: copying...") + list(LENGTH keys n) + math(EXPR n ${n}*2) + + set(i 0) + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(${${key}_COPYFLAG}) + message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") + else() + message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") + endif() + + set(show_status 0) + if(show_status) + message(STATUS "key='${key}'") + message(STATUS "item='${${key}_ITEM}'") + message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") + message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") + message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") + message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") + message(STATUS "copyflag='${${key}_COPYFLAG}'") + message(STATUS "") + endif() + + if(${${key}_COPYFLAG}) + set(item "${${key}_ITEM}") + if(item MATCHES "[^/]+\\.framework/") + copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + else() + copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + endif() + endif() + endforeach() + + message(STATUS "fixup_bundle: fixing...") + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(APPLE) + message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") + fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") + else() + message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") + endif() + endforeach() + + message(STATUS "fixup_bundle: cleaning up...") + clear_bundle_keys(keys) + + message(STATUS "fixup_bundle: verifying...") + verify_app("${app}") + else() + message(SEND_ERROR "error: fixup_bundle: not a valid bundle") + endif() + + message(STATUS "fixup_bundle: done") +endfunction() + + +function(copy_and_fixup_bundle src dst libs dirs) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") + fixup_bundle("${dst}" "${libs}" "${dirs}") +endfunction() + + +function(verify_bundle_prerequisites bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + get_bundle_main_executable("${bundle}" main_bundle_exe) + + file(GLOB_RECURSE file_list "${bundle}/*") + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + get_filename_component(exepath "${f}" PATH) + math(EXPR count "${count} + 1") + + message(STATUS "executable file ${count}: ${f}") + + set(prereqs "") + get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") + + # On the Mac, + # "embedded" and "system" prerequisites are fine... anything else means + # the bundle's prerequisites are not verified (i.e., the bundle is not + # really "standalone") + # + # On Windows (and others? Linux/Unix/...?) + # "local" and "system" prereqs are fine... + # + set(external_prereqs "") + + foreach(p ${prereqs}) + set(p_type "") + gp_file_type("${f}" "${p}" p_type) + + if(APPLE) + if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + else() + if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + endif() + endforeach() + + if(external_prereqs) + # Found non-system/somehow-unacceptable prerequisites: + set(result 0) + set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") + endif() + endif() + endforeach() + + if(result) + set(info "Verified ${count} executable files in '${bundle}'") + endif() + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_bundle_symlinks bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + # TODO: implement this function for real... + # Right now, it is just a stub that verifies unconditionally... + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_app app) + set(verified 0) + set(info "") + + get_bundle_and_executable("${app}" bundle executable valid) + + message(STATUS "===========================================================================") + message(STATUS "Analyzing app='${app}'") + message(STATUS "bundle='${bundle}'") + message(STATUS "executable='${executable}'") + message(STATUS "valid='${valid}'") + + # Verify that the bundle does not have any "external" prerequisites: + # + verify_bundle_prerequisites("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + + if(verified) + # Verify that the bundle does not have any symlinks to external files: + # + verify_bundle_symlinks("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + endif() + + if(NOT verified) + message(FATAL_ERROR "error: verify_app failed") + endif() +endfunction() diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index d33c6f33bd..21f1dbf7d1 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -25,3 +25,269 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The following files are derived from the Slicer project +(https://github.com/Slicer/Slicer), which in turn derived from CMake project (http://cmake.org) and are covered under the licenses below. + +BundleUtilitiesWithRPath.cmake, GetPrerequisitesWithRPath.cmake + +# Slicer + +For more information, please see: + + http://www.slicer.org + +The 3D Slicer license below is a BSD style license, with extensions +to cover contributions and other issues specific to 3D Slicer. + + +3D Slicer Contribution and Software License Agreement ("Agreement") +Version 1.0 (December 20, 2005) + +This Agreement covers contributions to and downloads from the 3D +Slicer project ("Slicer") maintained by The Brigham and Women's +Hospital, Inc. ("Brigham"). Part A of this Agreement applies to +contributions of software and/or data to Slicer (including making +revisions of or additions to code and/or data already in Slicer). Part +B of this Agreement applies to downloads of software and/or data from +Slicer. Part C of this Agreement applies to all transactions with +Slicer. If you distribute Software (as defined below) downloaded from +Slicer, all of the paragraphs of Part B of this Agreement must be +included with and apply to such Software. + +Your contribution of software and/or data to Slicer (including prior +to the date of the first publication of this Agreement, each a +"Contribution") and/or downloading, copying, modifying, displaying, +distributing or use of any software and/or data from Slicer +(collectively, the "Software") constitutes acceptance of all of the +terms and conditions of this Agreement. If you do not agree to such +terms and conditions, you have no right to contribute your +Contribution, or to download, copy, modify, display, distribute or use +the Software. + +PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to +Sublicense ("Contribution Agreement"). + +1. As used in this Contribution Agreement, "you" means the individual + contributing the Contribution to Slicer and the institution or + entity which employs or is otherwise affiliated with such + individual in connection with such Contribution. + +2. This Contribution Agreement applies to all Contributions made to + Slicer, including without limitation Contributions made prior to + the date of first publication of this Agreement. If at any time you + make a Contribution to Slicer, you represent that (i) you are + legally authorized and entitled to make such Contribution and to + grant all licenses granted in this Contribution Agreement with + respect to such Contribution; (ii) if your Contribution includes + any patient data, all such data is de-identified in accordance with + U.S. confidentiality and security laws and requirements, including + but not limited to the Health Insurance Portability and + Accountability Act (HIPAA) and its regulations, and your disclosure + of such data for the purposes contemplated by this Agreement is + properly authorized and in compliance with all applicable laws and + regulations; and (iii) you have preserved in the Contribution all + applicable attributions, copyright notices and licenses for any + third party software or data included in the Contribution. + +3. Except for the licenses granted in this Agreement, you reserve all + right, title and interest in your Contribution. + +4. You hereby grant to Brigham, with the right to sublicense, a + perpetual, worldwide, non-exclusive, no charge, royalty-free, + irrevocable license to use, reproduce, make derivative works of, + display and distribute the Contribution. If your Contribution is + protected by patent, you hereby grant to Brigham, with the right to + sublicense, a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable license under your interest in patent + rights covering the Contribution, to make, have made, use, sell and + otherwise transfer your Contribution, alone or in combination with + any other code. + +5. You acknowledge and agree that Brigham may incorporate your + Contribution into Slicer and may make Slicer available to members + of the public on an open source basis under terms substantially in + accordance with the Software License set forth in Part B of this + Agreement. You further acknowledge and agree that Brigham shall + have no liability arising in connection with claims resulting from + your breach of any of the terms of this Agreement. + +6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION + DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN + SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting + example, the GNU General Public License or other so-called + "reciprocal" license that requires any derived work to be licensed + under the GNU General Public License or other "open source + license"). + +PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to +Sublicense ("Software License"). + +1. As used in this Software License, "you" means the individual + downloading and/or using, reproducing, modifying, displaying and/or + distributing the Software and the institution or entity which + employs or is otherwise affiliated with such individual in + connection therewith. The Brigham and Women?s Hospital, + Inc. ("Brigham") hereby grants you, with right to sublicense, with + respect to Brigham's rights in the software, and data, if any, + which is the subject of this Software License (collectively, the + "Software"), a royalty-free, non-exclusive license to use, + reproduce, make derivative works of, display and distribute the + Software, provided that: + +(a) you accept and adhere to all of the terms and conditions of this +Software License; + +(b) in connection with any copy of or sublicense of all or any portion +of the Software, all of the terms and conditions in this Software +License shall appear in and shall apply to such copy and such +sublicense, including without limitation all source and executable +forms and on any user documentation, prefaced with the following +words: "All or portions of this licensed product (such portions are +the "Software") have been obtained under license from The Brigham and +Women's Hospital, Inc. and are subject to the following terms and +conditions:" + +(c) you preserve and maintain all applicable attributions, copyright +notices and licenses included in or applicable to the Software; + +(d) modified versions of the Software must be clearly identified and +marked as such, and must not be misrepresented as being the original +Software; and + +(e) you consider making, but are under no obligation to make, the +source code of any of your modifications to the Software freely +available to others on an open source basis. + +2. The license granted in this Software License includes without + limitation the right to (i) incorporate the Software into + proprietary programs (subject to any restrictions applicable to + such programs), (ii) add your own copyright statement to your + modifications of the Software, and (iii) provide additional or + different license terms and conditions in your sublicenses of + modifications of the Software; provided that in each case your use, + reproduction or distribution of such modifications otherwise + complies with the conditions stated in this Software License. + +3. This Software License does not grant any rights with respect to + third party software, except those rights that Brigham has been + authorized by a third party to grant to you, and accordingly you + are solely responsible for (i) obtaining any permissions from third + parties that you need to use, reproduce, make derivative works of, + display and distribute the Software, and (ii) informing your + sublicensees, including without limitation your end-users, of their + obligations to secure any such required permissions. + +4. The Software has been designed for research purposes only and has + not been reviewed or approved by the Food and Drug Administration + or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL + APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any + commercialization of the Software is at the sole risk of the party + or parties engaged in such commercialization. You further agree to + use, reproduce, make derivative works of, display and distribute + the Software in compliance with all applicable governmental laws, + regulations and orders, including without limitation those relating + to export and import control. + +5. The Software is provided "AS IS" and neither Brigham nor any + contributor to the software (each a "Contributor") shall have any + obligation to provide maintenance, support, updates, enhancements + or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY + DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, + BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR + A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, + INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY + RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM + EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL + LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, + DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO + INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND + AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS + ARISING THEREFROM. + +6. None of the names, logos or trademarks of Brigham or any of + Brigham's affiliates or any of the Contributors, or any funding + agency, may be used to endorse or promote products produced in + whole or in part by operation of the Software or derived from or + based on the Software without specific prior written permission + from the applicable party. + +7. Any use, reproduction or distribution of the Software which is not + in accordance with this Software License shall automatically revoke + all rights granted to you under this Software License and render + Paragraphs 1 and 2 of this Software License null and void. + +8. This Software License does not grant any rights in or to any + intellectual property owned by Brigham or any Contributor except + those rights expressly granted hereunder. + +PART C. MISCELLANEOUS + +This Agreement shall be governed by and construed in accordance with +the laws of The Commonwealth of Massachusetts without regard to +principles of conflicts of law. This Agreement shall supercede and +replace any license terms that you may have agreed to previously with +respect to Slicer. + +# CMake + +CMake - Cross Platform Makefile Generator +Copyright 2000-2015 Kitware, Inc. +Copyright 2000-2011 Insight Software Consortium +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the names of Kitware, Inc., the Insight Software Consortium, + nor the names of their contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The above copyright and license notice applies to distributions of +CMake in source and binary form. Some source files contain additional +notices of original copyright by their contributors; see each source +for details. Third-party software packages supplied with CMake under +compatible licenses provide their own copyright notices documented in +corresponding subdirectories. + +------------------------------------------------------------------------------ + +CMake was initially developed by Kitware with the following sponsorship: + + * National Library of Medicine at the National Institutes of Health + as part of the Insight Segmentation and Registration Toolkit (ITK). + + * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel + Visualization Initiative. + + * National Alliance for Medical Image Computing (NAMIC) is funded by the + National Institutes of Health through the NIH Roadmap for Medical Research, + Grant U54 EB005149. + + * Kitware, Inc. diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake new file mode 100644 index 0000000000..b57295b3d2 --- /dev/null +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -0,0 +1,990 @@ +# - Functions to analyze and list executable file prerequisites. +# This module provides functions to list the .dll, .dylib or .so +# files that an executable or shared library file depends on. (Its +# prerequisites.) +# +# It uses various tools to obtain the list of required shared library files: +# dumpbin (Windows) +# objdump (MinGW on Windows) +# ldd (Linux/Unix) +# otool (Mac OSX) +# The following functions are provided by this module: +# get_prerequisites +# list_prerequisites +# list_prerequisites_by_glob +# gp_append_unique +# is_file_executable +# gp_item_default_embedded_path +# (projects can override with gp_item_default_embedded_path_override) +# gp_resolve_item +# (projects can override with gp_resolve_item_override) +# gp_resolve_embedded_item +# (projects can override with gp_resolve_embedded_item_override) +# gp_resolved_file_type +# (projects can override with gp_resolved_file_type_override) +# gp_file_type +# Requires CMake 2.6 or greater because it uses function, break, return and +# PARENT_SCOPE. +# +# GET_PREREQUISITES( +# ) +# Get the list of shared library files required by . The list in +# the variable named should be empty on first entry to +# this function. On exit, will contain the list of +# required shared library files. +# +# is the full path to an executable file. is the +# name of a CMake variable to contain the results. must be 0 +# or 1 indicating whether to include or exclude "system" prerequisites. If +# is set to 1 all prerequisites will be found recursively, if set to +# 0 only direct prerequisites are listed. is the path to the top +# level executable used for @executable_path replacment on the Mac. is +# a list of paths where libraries might be found: these paths are searched +# first when a target without any path info is given. Then standard system +# locations are also searched: PATH, Framework locations, /usr/lib... +# +# LIST_PREREQUISITES( [ [ []]]) +# Print a message listing the prerequisites of . +# +# is the name of a shared library or executable target or the full +# path to a shared library or executable file. If is set to 1 all +# prerequisites will be found recursively, if set to 0 only direct +# prerequisites are listed. must be 0 or 1 indicating whether +# to include or exclude "system" prerequisites. With set to 0 only +# the full path names of the prerequisites are printed, set to 1 extra +# informatin will be displayed. +# +# LIST_PREREQUISITES_BY_GLOB( ) +# Print the prerequisites of shared library and executable files matching a +# globbing pattern. is GLOB or GLOB_RECURSE and is a +# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve +# a list of matching files. If a matching file is executable, its prerequisites +# are listed. +# +# Any additional (optional) arguments provided are passed along as the +# optional arguments to the list_prerequisites calls. +# +# GP_APPEND_UNIQUE( ) +# Append to the list variable only if the value is not +# already in the list. +# +# IS_FILE_EXECUTABLE( ) +# Return 1 in if is a binary executable, 0 otherwise. +# +# GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX can be set to a regular expression used +# to give a hint to identify more quickly if a given file is an executable or not. +# This is particularly useful on unix platform where it can avoid a lot of +# time-consuming call to "file" external process. For packages bundling hundreds +# of libraries, executables, resources and data, it largely speeds up the function +# "get_bundle_all_executables". +# On unix, a convenient command line allowing to collect recursively all file extensions +# useful to generate a regular expression like "\\.(dylib|py|pyc|so)$" is: +# find . -type f -name '*.*' | sed 's@.*/.*\.@@' | sort | uniq | tr "\\n" "|" +# +# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# Override on a per-project basis by providing a project-specific +# gp_item_default_embedded_path_override function. +# +# GP_RESOLVE_ITEM( ) +# Resolve an item into an existing full path file. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_item_override function. +# +# GP_RESOLVE_EMBEDDED_ITEM( ) +# Resolve an embedded item into the full path within the full path. Since the item can be +# copied later, it doesn't have to exist when calling this function. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_embedded_item_override function. +# +# If GP_RPATH_DIR variable is set then item matching '@rpath' are +# resolved using the provided directory. Currently setting this variable +# has an effect only on MacOSX when fixing up application bundle. The directory +# are also assumed to be located within the application bundle. It is +# usually the directory passed to the 'rpath' linker option. +# +# GP_RESOLVED_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Use and if necessary to resolve non-absolute +# values -- but only for non-embedded items. +# +# Possible types are: +# system +# local +# embedded +# other +# Override on a per-project basis by providing a project-specific +# gp_resolved_file_type_override function. +# +# GP_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Possible types are: +# system +# local +# embedded +# other + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +function(gp_append_unique list_var value) + set(contains 0) + + foreach(item ${${list_var}}) + if("${item}" STREQUAL "${value}") + set(contains 1) + break() + endif() + endforeach() + + if(NOT contains) + set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) + endif() +endfunction() + + +function(is_file_executable file result_var) + # + # A file is not executable until proven otherwise: + # + set(${result_var} 0 PARENT_SCOPE) + + get_filename_component(file_full "${file}" ABSOLUTE) + string(TOLOWER "${file_full}" file_full_lower) + + # If file name ends in .exe on Windows, *assume* executable: + # + if(WIN32 AND NOT UNIX) + if("${file_full_lower}" MATCHES "\\.exe$") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + # A clause could be added here that uses output or return value of dumpbin + # to determine ${result_var}. In 99%+? practical cases, the exe name + # match will be sufficient... + # + endif() + + # Use the information returned from the Unix shell command "file" to + # determine if ${file_full} should be considered an executable file... + # + # If the file command's output contains "executable" and does *not* contain + # "text" then it is likely an executable suitable for prerequisite analysis + # via the get_prerequisites macro. + # + if(UNIX) + + if(NOT "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}" STREQUAL "") + if(${file_full} MATCHES "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}") + set(${result_var} 0 PARENT_SCOPE) + return() + endif() + endif() + + if(NOT file_cmd) + find_program(file_cmd "file") + mark_as_advanced(file_cmd) + endif() + + if(file_cmd) + execute_process(COMMAND "${file_cmd}" "${file_full}" + OUTPUT_VARIABLE file_ov + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Replace the name of the file in the output with a placeholder token + # (the string " _file_full_ ") so that just in case the path name of + # the file contains the word "text" or "executable" we are not fooled + # into thinking "the wrong thing" because the file name matches the + # other 'file' command output we are looking for... + # + string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") + string(TOLOWER "${file_ov}" file_ov) + + #message(STATUS "file_ov='${file_ov}'") + if("${file_ov}" MATCHES "executable") + #message(STATUS "executable!") + if("${file_ov}" MATCHES "text") + #message(STATUS "but text, so *not* a binary executable!") + else() + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + endif() + + # Also detect position independent executables on Linux, + # where "file" gives "shared object ... (uses shared libraries)" + if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + else() + message(STATUS "warning: No 'file' command, skipping execute_process...") + endif() + endif() +endfunction() + + +function(gp_item_default_embedded_path item default_embedded_path_var) + + # On Windows and Linux, "embed" prerequisites in the same directory + # as the executable by default: + # + set(path "@executable_path") + set(overridden 0) + + # On the Mac, relative to the executable depending on the type + # of the thing we are embedding: + # + if(APPLE) + # + # The assumption here is that all executables in the bundle will be + # in same-level-directories inside the bundle. The parent directory + # of an executable inside the bundle should be MacOS or a sibling of + # MacOS and all embedded paths returned from here will begin with + # "@executable_path/../" and will work from all executables in all + # such same-level-directories inside the bundle. + # + + # By default, embed things right next to the main bundle executable: + # + set(path "@executable_path/../../Contents/MacOS") + + # Embed .dylibs right next to the main bundle executable: + # + if(item MATCHES "\\.dylib$") + set(path "@executable_path/../MacOS") + set(overridden 1) + endif() + + # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): + # + if(NOT overridden) + if(item MATCHES "[^/]+\\.framework/") + set(path "@executable_path/../Frameworks") + set(overridden 1) + endif() + endif() + endif() + + # Provide a hook so that projects can override the default embedded location + # of any given library by whatever logic they choose: + # + if(COMMAND gp_item_default_embedded_path_override) + gp_item_default_embedded_path_override("${item}" path) + endif() + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction() + + +function(gp_resolve_item context item exepath dirs resolved_item_var) + set(resolved 0) + set(resolved_item "${item}") + + # Is it already resolved? + # + if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") + set(resolved 1) + endif() + + if(NOT resolved) + if(item MATCHES "@executable_path") + # + # @executable_path references are assumed relative to exepath + # + string(REPLACE "@executable_path" "${exepath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@loader_path") + # + # @loader_path references are assumed relative to the + # PATH of the given "context" (presumably another library) + # + get_filename_component(contextpath "${context}" PATH) + string(REPLACE "@loader_path" "${contextpath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@rpath") + # + # @rpath references are relative to the paths built into the binaries with -rpath + # We handle this case like we do for other Unixes. + # + # Two cases of item resolution are considered: + # + # (1) item has been copied into the bundle + # + # (2) item has NOT been copied into the bundle: Since the item can exist in a build or + # install tree outside of the bundle, the item is resolved using its name and the + # passed list of directories. + # + string(REPLACE "@rpath/" "" norpath_item "${item}") + + set(ri "ri-NOTFOUND") + if(EXISTS ${GP_RPATH_DIR}/${norpath_item}) + set(ri ${GP_RPATH_DIR}/${norpath_item}) + set(_msg "'find_file' in GP_RPATH_DIR (${ri})") + else() + get_filename_component(norpath_item_name ${norpath_item} NAME) + find_file(ri "${norpath_item_name}" ${exepath} ${dirs} NO_DEFAULT_PATH) + set(_msg "'find_file' in exepath/dirs (${ri})") + endif() + if(ri) + #message(STATUS "info: ${_msg}") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + + endif() + endif() + + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) + find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) + if(ri) + #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + + if(NOT resolved) + if(item MATCHES "[^/]+\\.framework/") + set(fw "fw-NOTFOUND") + find_file(fw "${item}" + "~/Library/Frameworks" + "/Library/Frameworks" + "/System/Library/Frameworks" + ) + if(fw) + #message(STATUS "info: 'find_file' found framework (${fw})") + set(resolved 1) + set(resolved_item "${fw}") + set(fw "fw-NOTFOUND") + endif() + endif() + endif() + + # Using find_program on Windows will find dll files that are in the PATH. + # (Converting simple file names into full path names if found.) + # + if(WIN32 AND NOT UNIX) + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) + find_program(ri "${item}" PATHS "${exepath};${dirs}") + if(ri) + #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + endif() + + # Provide a hook so that projects can override item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_item_override) + gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve item '${item}' + + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? +") +# message(STATUS " +#****************************************************************************** +#warning: cannot resolve item '${item}' +# +# possible problems: +# need more directories? +# need to use InstallRequiredSystemLibraries? +# run in install tree instead of build tree? +# +# context='${context}' +# item='${item}' +# exepath='${exepath}' +# dirs='${dirs}' +# resolved_item_var='${resolved_item_var}' +#****************************************************************************** +#") + endif() + + set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolve_embedded_item context embedded_item exepath resolved_embedded_item_var) + #message(STATUS "**") + set(resolved 0) + set(resolved_embedded_item "${embedded_item}") + + if(embedded_item MATCHES "@executable_path") + string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + if(EXISTS "${GP_RPATH_DIR}" AND embedded_item MATCHES "@rpath") + string(REPLACE "@rpath" "${GP_RPATH_DIR}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + + # Provide a hook so that projects can override embedded item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_embedded_item_override) + gp_resolve_embedded_item_override( + "${context}" "${embedded_item}" "${exepath}" resolved_embedded_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve embedded item '${embedded_item}' + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? + + context='${context}' + embedded_item='${embedded_item}' + GP_RPATH_DIR='${GP_RPATH_DIR}' + exepath='${exepath}' + resolved_embedded_item_var='${resolved_embedded_item_var}' +") + endif() + + set(${resolved_embedded_item_var} "${resolved_embedded_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolved_file_type original_file file exepath dirs type_var) + #message(STATUS "**") + + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") + endif() + + set(is_embedded 0) + set(is_local 0) + set(is_system 0) + + set(resolved_file "${file}") + + if("${file}" MATCHES "^@(executable_|loader_|r)path") + set(is_embedded 1) + endif() + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${file}") + gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) + endif() + + string(TOLOWER "${original_file}" original_lower) + string(TOLOWER "${resolved_file}" lower) + + if(UNIX) + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + set(is_system 1) + endif() + endif() + + if(APPLE) + if(resolved_file MATCHES "^(/System/Library/|/usr/lib/|/opt/X11/)") + set(is_system 1) + endif() + endif() + + if(WIN32) + string(TOLOWER "$ENV{SystemRoot}" sysroot) + string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") + + string(TOLOWER "$ENV{windir}" windir) + string(REGEX REPLACE "\\\\" "/" windir "${windir}") + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + + if(UNIX) + # if cygwin, we can get the properly formed windows paths from cygpath + find_program(CYGPATH_EXECUTABLE cygpath) + + if(CYGPATH_EXECUTABLE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W + OUTPUT_VARIABLE env_windir + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S + OUTPUT_VARIABLE env_sysdir + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOLOWER "${env_windir}" windir) + string(TOLOWER "${env_sysdir}" sysroot) + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + endif() + endif() + endif() + + if(NOT is_system) + get_filename_component(original_path "${original_lower}" PATH) + get_filename_component(path "${lower}" PATH) + if("${original_path}" STREQUAL "${path}") + set(is_local 1) + else() + string(LENGTH "${original_path}/" original_length) + string(LENGTH "${lower}" path_length) + if(${path_length} GREATER ${original_length}) + string(SUBSTRING "${lower}" 0 ${original_length} path) + if("${original_path}/" STREQUAL "${path}") + set(is_embedded 1) + endif() + endif() + endif() + endif() + endif() + + # Return type string based on computed booleans: + # + set(type "other") + + if(is_system) + set(type "system") + elseif(is_embedded) + set(type "embedded") + elseif(is_local) + set(type "local") + endif() + + #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") + #message(STATUS " type: '${type}'") + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${resolved_file}") + if(lower MATCHES "^msvc[^/]+dll" AND is_system) + message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") + else() + message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") + endif() + endif() + endif() + + # Provide a hook so that projects can override the decision on whether a + # library belongs to the system or not by whatever logic they choose: + # + if(COMMAND gp_resolved_file_type_override) + gp_resolved_file_type_override("${resolved_file}" type) + endif() + + set(${type_var} "${type}" PARENT_SCOPE) + + #message(STATUS "**") +endfunction() + + +function(gp_file_type original_file file type_var) + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") + endif() + + get_filename_component(exepath "${original_file}" PATH) + + set(type "") + gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) + + set(${type_var} "${type}" PARENT_SCOPE) +endfunction() + + +function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) + set(verbose 0) + set(eol_char "E") + + if(NOT IS_ABSOLUTE "${target}") + message("warning: target '${target}' is not absolute...") + endif() + + if(NOT EXISTS "${target}") + message("warning: target '${target}' does not exist...") + endif() + + set(gp_cmd_paths ${gp_cmd_paths} + "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" + "/usr/local/bin" + "/usr/bin" + ) + + # + # + # Try to choose the right tool by default. Caller can set gp_tool prior to + # calling this function to force using a different tool. + # + if("${gp_tool}" STREQUAL "") + set(gp_tool "ldd") + + if(APPLE) + set(gp_tool "otool") + endif() + + if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! + find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) + if(gp_dumpbin) + set(gp_tool "dumpbin") + else() # Try harder. Maybe we're on MinGW + set(gp_tool "objdump") + endif() + endif() + endif() + + find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) + + if(NOT gp_cmd) + message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") + return() + endif() + + set(gp_tool_known 0) + + if("${gp_tool}" STREQUAL "ldd") + set(gp_cmd_args "") + set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") + set(gp_regex_error "not found${eol_char}$") + set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "otool") + set(gp_cmd_args "-L") + set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 3) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "dumpbin") + set(gp_cmd_args "/dependents") + set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. + endif() + + if("${gp_tool}" STREQUAL "objdump") + set(gp_cmd_args "-p") + set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if(NOT gp_tool_known) + message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") + message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") + message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") + return() + endif() + + + if("${gp_tool}" STREQUAL "dumpbin") + # When running dumpbin, it also needs the "Common7/IDE" directory in the + # PATH. It will already be in the PATH if being run from a Visual Studio + # command prompt. Add it to the PATH here in case we are running from a + # different command prompt. + # + get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) + get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) + # Use cmake paths as a user may have a PATH element ending with a backslash. + # This will escape the list delimiter and create havoc! + if(EXISTS "${gp_cmd_dlls_dir}") + # only add to the path if it is not already in the path + set(gp_found_cmd_dlls_dir 0) + file(TO_CMAKE_PATH "$ENV{PATH}" env_path) + foreach(gp_env_path_element ${env_path}) + if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") + set(gp_found_cmd_dlls_dir 1) + endif() + endforeach() + + if(NOT gp_found_cmd_dlls_dir) + file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) + set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") + endif() + endif() + endif() + # + # + + if("${gp_tool}" STREQUAL "ldd") + set(old_ld_env "$ENV{LD_LIBRARY_PATH}") + foreach(dir ${exepath} ${dirs}) + set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") + endforeach() + endif() + + + # Track new prerequisites at each new level of recursion. Start with an + # empty list at each level: + # + set(unseen_prereqs) + + # Run gp_cmd on the target: + # + execute_process( + COMMAND ${gp_cmd} ${gp_cmd_args} ${target} + OUTPUT_VARIABLE gp_cmd_ov + ) + + if("${gp_tool}" STREQUAL "ldd") + set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") + endif() + + if(verbose) + message(STATUS "") + message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") + message(STATUS "") + endif() + + get_filename_component(target_dir "${target}" PATH) + + # Convert to a list of lines: + # + string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") + string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") + + # check for install id and remove it from list, since otool -L can include a + # reference to itself + set(gp_install_id) + if("${gp_tool}" STREQUAL "otool") + execute_process( + COMMAND otool -D ${target} + OUTPUT_VARIABLE gp_install_id_ov + ) + # second line is install name + string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") + if(gp_install_id) + # trim + string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") + #message("INSTALL ID is \"${gp_install_id}\"") + endif() + endif() + + # Analyze each line for file names that match the regular expression: + # + foreach(candidate ${candidates}) + if("${candidate}" MATCHES "${gp_regex}") + + # Extract information from each candidate: + if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") + string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") + else() + string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") + endif() + + if(gp_regex_cmp_count GREATER 1) + string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") + endif() + + if(gp_regex_cmp_count GREATER 2) + string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") + endif() + + # Use the raw_item as the list entries returned by this function. Use the + # gp_resolve_item function to resolve it to an actual full path file if + # necessary. + # + set(item "${raw_item}") + + # Add each item unless it is excluded: + # + set(add_item 1) + + if("${item}" STREQUAL "${gp_install_id}") + set(add_item 0) + endif() + + if(add_item AND ${exclude_system}) + set(type "") + gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) + + if("${type}" STREQUAL "system") + set(add_item 0) + endif() + endif() + + if(add_item) + list(LENGTH ${prerequisites_var} list_length_before_append) + gp_append_unique(${prerequisites_var} "${item}") + list(LENGTH ${prerequisites_var} list_length_after_append) + + if(${recurse}) + # If item was really added, this is the first time we have seen it. + # Add it to unseen_prereqs so that we can recursively add *its* + # prerequisites... + # + # But first: resolve its name to an absolute full path name such + # that the analysis tools can simply accept it as input. + # + if(NOT list_length_before_append EQUAL list_length_after_append) + gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) + set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") + endif() + endif() + endif() + else() + if(verbose) + message(STATUS "ignoring non-matching line: '${candidate}'") + endif() + endif() + endforeach() + + list(LENGTH ${prerequisites_var} prerequisites_var_length) + if(prerequisites_var_length GREATER 0) + list(SORT ${prerequisites_var}) + endif() + if(${recurse}) + set(more_inputs ${unseen_prereqs}) + foreach(input ${more_inputs}) + get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") + endforeach() + endif() + + set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) +endfunction() + + +function(list_prerequisites target) + if("${ARGV1}" STREQUAL "") + set(all 1) + else() + set(all "${ARGV1}") + endif() + + if("${ARGV2}" STREQUAL "") + set(exclude_system 0) + else() + set(exclude_system "${ARGV2}") + endif() + + if("${ARGV3}" STREQUAL "") + set(verbose 0) + else() + set(verbose "${ARGV3}") + endif() + + set(count 0) + set(count_str "") + set(print_count "${verbose}") + set(print_prerequisite_type "${verbose}") + set(print_target "${verbose}") + set(type_str "") + + get_filename_component(exepath "${target}" PATH) + + set(prereqs "") + get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") + + if(print_target) + message(STATUS "File '${target}' depends on:") + endif() + + foreach(d ${prereqs}) + math(EXPR count "${count} + 1") + + if(print_count) + set(count_str "${count}. ") + endif() + + if(print_prerequisite_type) + gp_file_type("${target}" "${d}" type) + set(type_str " (${type})") + endif() + + message(STATUS "${count_str}${d}${type_str}") + endforeach() +endfunction() + + +function(list_prerequisites_by_glob glob_arg glob_exp) + message(STATUS "=============================================================================") + message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") + message(STATUS "") + file(${glob_arg} file_list ${glob_exp}) + foreach(f ${file_list}) + is_file_executable("${f}" is_f_executable) + if(is_f_executable) + message(STATUS "=============================================================================") + list_prerequisites("${f}" ${ARGN}) + message(STATUS "") + endif() + endforeach() +endfunction() From c868010c20f1aa01b1a5fe66375340e4b12a9ada Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:02 +0200 Subject: [PATCH 0913/1812] OS X: don't consider libs from `/usr/local` as "system dependencies" during packaging Otherwise they won't be moved into final application bundle. --- cmake/GetPrerequisitesWithRPath.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake index b57295b3d2..5b5751ead3 100644 --- a/cmake/GetPrerequisitesWithRPath.cmake +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -537,7 +537,7 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) string(TOLOWER "${resolved_file}" lower) if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/)") set(is_system 1) endif() endif() From 2ded28f6aaf8da8ab6d069f3125e4eb53fdd58a9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:35 +0200 Subject: [PATCH 0914/1812] OS X: reintroduce packaging code It's much simpler now thanks to bundle utilities with @rpath support. --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb4235..f7c458da5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -736,13 +736,18 @@ if (APPLE) install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) - include(BundleUtilities) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) + include(BundleUtilitiesWithRPath) " COMPONENT Runtime) - #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail - set(DIRS "") + set(DIRS "${CMAKE_PREFIX_PATH}/lib") - include(CPack) + install(CODE " + cmake_policy(SET CMP0009 OLD) + fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + " COMPONENT Runtime) + include(CPack) endif (APPLE) # Doxygen Target -- simply run 'make doc' or 'make doc_pages' From 34d601360f5daad9bfc67afe67ff1ca9ec5ae34c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 8 Aug 2015 17:19:26 +0200 Subject: [PATCH 0915/1812] OS X: setup OSG plugins packaging --- CMakeLists.txt | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7c458da5e..9e966cf6d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,11 @@ add_subdirectory(files/) if (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") + + if (OPENMW_OSX_DEPLOYMENT) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + endif() else (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") @@ -740,12 +745,59 @@ if (APPLE) include(BundleUtilitiesWithRPath) " COMPONENT Runtime) + set(ABSOLUTE_PLUGINS "") + set(USED_OSG_PLUGINS + osgdb_tga + osgdb_dds + osgdb_imageio + ) + + foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) + set(PLUGIN_ABS "${OSG_PLUGIN_LIB_SEARCH_PATH}/${PLUGIN_NAME}.so") + set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) + endforeach () + + get_filename_component(PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) + + # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) + # and returns list of install paths for all installed plugins + function (install_plugins_for_bundle bundle_path plugins_var) + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${PLUGIN_PREFIX_DIR}") + + set(PLUGINS "") + set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") + + foreach (PLUGIN ${ABSOLUTE_PLUGINS}) + get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) + get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) + + set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") + + install(CODE " + copy_resolved_item_into_bundle(\"${PLUGIN}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") + " COMPONENT Runtime) + endforeach () + + set(${plugins_var} ${PLUGINS} PARENT_SCOPE) + endfunction (install_plugins_for_bundle) + + install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) + install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + set(DIRS "${CMAKE_PREFIX_PATH}/lib") install(CODE " + function(gp_item_default_embedded_path_override item default_embedded_path_var) + if (\${item} MATCHES ${PLUGIN_PREFIX_DIR}) + set(path \"@executable_path/../PlugIns/${PLUGIN_PREFIX_DIR}\") + set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) + endif() + endfunction() + cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From d9b11f963ad733d0ee105cd777202179e0b33658 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Tue, 11 Aug 2015 21:45:02 -0500 Subject: [PATCH 0916/1812] Gamepad: Slow down simulated mouse with right trigger in menus. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 09e0b638be..2d767c6f57 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -370,6 +370,9 @@ namespace MWInput float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor mGuiCursorX += xAxis * dt * 1500.0f * mInvUiScalingFactor; From 904ad949524864239f4b1f428d03a947360728a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:03:20 +0200 Subject: [PATCH 0917/1812] added merge operation (doesn't do anything yet) --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 5 ++-- apps/opencs/model/tools/mergeoperation.cpp | 15 +++++++++++ apps/opencs/model/tools/mergeoperation.hpp | 28 +++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 31 +++++++++++++++++++--- apps/opencs/model/tools/tools.hpp | 11 ++++++-- apps/opencs/view/tools/merge.cpp | 8 ++++++ 8 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 apps/opencs/model/tools/mergeoperation.cpp create mode 100644 apps/opencs/model/tools/mergeoperation.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 91c778c06b..833ca65515 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -42,6 +42,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + mergeoperation ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 44e6142b07..a331706bcf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2388,6 +2388,12 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } +void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +{ + mTools.runMerge (target); + emit stateChanged (getState(), this); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index c9271fa542..901a8e3e49 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -129,7 +129,9 @@ namespace CSMDoc CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); const CSMWorld::Data& getData() const; @@ -173,4 +175,3 @@ namespace CSMDoc } #endif - diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp new file mode 100644 index 0000000000..65cfdb4ff4 --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -0,0 +1,15 @@ + +#include "mergeoperation.hpp" + +#include "../doc/state.hpp" + +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Merging, true) +{ + +} + +void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +{ + +} diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp new file mode 100644 index 0000000000..84526b2f20 --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_MERGEOPERATION_H +#define CSM_TOOLS_MERGEOPERATION_H + +#include + +#include "../doc/operation.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class MergeOperation : public CSMDoc::Operation + { + + + public: + + MergeOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a merge is running. + void setTarget (const boost::filesystem::path& target); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c1160918..ba894a867d 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "mergeoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -35,6 +36,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { case CSMDoc::State_Verifying: return &mVerifier; case CSMDoc::State_Searching: return &mSearch; + case CSMDoc::State_Merging: return &mMerge; } return 0; @@ -53,7 +55,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() std::vector settings; settings.push_back ("script-editor/warnings"); - + mVerifierOperation->configureSettings (settings); connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); @@ -116,7 +118,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMTools::Tools::Tools (CSMDoc::Document& document) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -142,6 +144,12 @@ CSMTools::Tools::~Tools() delete mSearchOperation; } + if (mMergeOperation) + { + mMerge.abortAndWait(); + delete mMergeOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -153,7 +161,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& if (mReports.find (reportNumber)==mReports.end()) mReports.insert (std::make_pair (reportNumber, new ReportModel)); - + mActiveReports[CSMDoc::State_Verifying] = reportNumber; getVerifier()->start(); @@ -183,6 +191,21 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } +void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +{ + // not setting an active report, because merge does not produce messages + + if (!mMergeOperation) + { + mMergeOperation = new MergeOperation (mDocument); + mMerge.setOperation (mMergeOperation); + } + + mMergeOperation->setTarget (target); + + mMerge.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -195,6 +218,7 @@ int CSMTools::Tools::getRunningOperations() const { CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 }; @@ -225,4 +249,3 @@ void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type) if (iter!=mActiveReports.end()) mReports[iter->second]->add (message); } - diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 78484d15d9..9520999280 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,9 +1,11 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include + #include -#include +#include #include "../doc/operationholder.hpp" @@ -24,6 +26,7 @@ namespace CSMTools class ReportModel; class Search; class SearchOperation; + class MergeOperation; class Tools : public QObject { @@ -35,6 +38,8 @@ namespace CSMTools CSMDoc::OperationHolder mVerifier; SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; + MergeOperation *mMergeOperation; + CSMDoc::OperationHolder mMerge; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -67,7 +72,9 @@ namespace CSMTools CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index baadd91799..faf7be3b43 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -66,7 +66,9 @@ CSVTools::Merge::Merge (QWidget *parent) QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); mOkay->setDefault (true); buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); @@ -109,6 +111,12 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { QDialog::accept(); + + if ((mDocument->getState() & CSMDoc::State_Merging)==0) + { + mDocument->runMerge (mAdjuster->getPath()); + hide(); + } } void CSVTools::Merge::reject() From e2377396a7cf7b9cd1ec91e0f385721a124a49cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:53:00 +0200 Subject: [PATCH 0918/1812] inheriting Merge from QWidget instead of QDialog, because QDialog is bloody useless for non-modal dialogues (which makes the class completely useless, since modal dialogues are the spawn of Satan) --- apps/opencs/editor.cpp | 2 ++ apps/opencs/view/tools/merge.cpp | 24 ++++++++++++++---------- apps/opencs/view/tools/merge.hpp | 15 +++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 170e883201..0b385f2757 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -379,4 +379,6 @@ void CS::Editor::mergeDocument (CSMDoc::Document *document) { mMerge.configure (document); mMerge.show(); + mMerge.raise(); + mMerge.activateWindow(); } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index faf7be3b43..f775390ee8 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -7,14 +7,26 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" +void CSVTools::Merge::keyPressEvent (QKeyEvent *event) +{ + if (event->key()==Qt::Key_Escape) + { + event->accept(); + cancel(); + } + else + QWidget::keyPressEvent (event); +} + CSVTools::Merge::Merge (QWidget *parent) -: QDialog (parent), mDocument (0) +: QWidget (parent), mDocument (0) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -65,7 +77,7 @@ CSVTools::Merge::Merge (QWidget *parent) // buttons QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); - connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (cancel())); mOkay = new QPushButton ("Merge", this); connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); @@ -110,8 +122,6 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { - QDialog::accept(); - if ((mDocument->getState() & CSMDoc::State_Merging)==0) { mDocument->runMerge (mAdjuster->getPath()); @@ -119,12 +129,6 @@ void CSVTools::Merge::accept() } } -void CSVTools::Merge::reject() -{ - QDialog::reject(); - cancel(); -} - void CSVTools::Merge::stateChanged (bool valid) { mOkay->setEnabled (valid); diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index 4538baebe6..b8369ffa32 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -1,7 +1,7 @@ #ifndef CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H -#include +#include #include @@ -21,7 +21,7 @@ namespace CSVDoc namespace CSVTools { - class Merge : public QDialog + class Merge : public QWidget { Q_OBJECT @@ -31,6 +31,8 @@ namespace CSVTools CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + void keyPressEvent (QKeyEvent *event); + public: Merge (QWidget *parent = 0); @@ -42,18 +44,15 @@ namespace CSVTools CSMDoc::Document *getDocument() const; - void cancel(); - public slots: - virtual void accept(); - - virtual void reject(); + void cancel(); private slots: - void stateChanged (bool valid); + void accept(); + void stateChanged (bool valid); }; } From d8655f2ff862dbaf90fb285ef01cdf6891cdbea6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 14:49:32 +0200 Subject: [PATCH 0919/1812] forgot to connect merge operation signals --- apps/opencs/model/tools/tools.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index ba894a867d..681f74404b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -128,6 +128,10 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int))); + + connect (&mMerge, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mMerge, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + // don't need to connect report message, since there are no messages for merge } CSMTools::Tools::~Tools() From c07ced4c8fe626ab74f2c554504aefc55a86fb78 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Aug 2015 17:01:25 +0200 Subject: [PATCH 0920/1812] Editor: fix magic effect magnitudes incorrectly labelled as Min/Max Range --- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 3 +++ apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7aec68309c..579bc98996 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -35,6 +35,8 @@ namespace CSMWorld { ColumnId_Volume, "Volume" }, { ColumnId_MinRange, "Min Range" }, { ColumnId_MaxRange, "Max Range" }, + { ColumnId_MinMagnitude, "Min Magnitude" }, + { ColumnId_MaxMagnitude, "Max Magnitude" }, { ColumnId_SoundFile, "Sound File" }, { ColumnId_MapColour, "Map Colour" }, { ColumnId_SleepEncounter, "Sleep Encounter" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index d699c67b7e..5dfa479f61 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -306,6 +306,9 @@ namespace CSMWorld ColumnId_FileDescription = 276, ColumnId_Author = 277, + ColumnId_MinMagnitude = 278, + ColumnId_MaxMagnitude = 279, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6c..25a04715d5 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -224,9 +224,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -340,9 +340,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 947454d771..5b2d184a7b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -93,9 +93,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); EnchantableColumns enchantableColumns (inventoryColumns); From 86f0e505e956583e9d62f13fd565a30f4a8f388f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:27:25 +0200 Subject: [PATCH 0921/1812] Add a fixPosition for the --start exterior cell (Fixes #2790) --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2e..a97c8f0d4b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -228,6 +228,7 @@ namespace MWWorld if (findExteriorPosition (mStartCell, pos)) { changeToExteriorCell (pos); + fixPosition(getPlayerPtr()); } else { From 0d8f07d5634a8127c350d3418e5b9dd836e67aa2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 20:55:31 +0200 Subject: [PATCH 0922/1812] Properly apply changes when backing out of chargen dialogs (Fixes #2627) --- apps/openmw/mwgui/charactercreation.cpp | 107 +++++++++++------------- apps/openmw/mwgui/charactercreation.hpp | 5 ++ 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index d0a0505262..6585a0dd09 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -312,7 +312,7 @@ namespace MWGui }; } - void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectPickedClass() { if (mPickClassDialog) { @@ -332,20 +332,18 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + { + selectPickedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() { - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } + selectPickedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -390,29 +388,7 @@ namespace MWGui handleDialogDone(CSE_NameChosen, GM_Race); } - void CharacterCreation::onRaceDialogBack() - { - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); - } - - void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + void CharacterCreation::selectRace() { if (mRaceDialog) { @@ -433,11 +409,24 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onRaceDialogBack() + { + selectRace(); + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + } + + void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + { + selectRace(); handleDialogDone(CSE_RaceChosen, GM_Class); } - void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + void CharacterCreation::selectBirthSign() { if (mBirthSignDialog) { @@ -449,24 +438,24 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + selectBirthSign(); handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() { - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } + selectBirthSign(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } - void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectCreatedClass() { if (mCreateClassDialog) { @@ -495,19 +484,23 @@ namespace MWGui mPlayerClass = klass; MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later + // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); } - updatePlayerHealth(); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + selectCreatedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() { - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later - mCreateClassDialog->setVisible(false); + // not done in MW, but we do it for consistency with the other dialogs + selectCreatedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -631,18 +624,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); } - void CharacterCreation::onGenerateClassBack() - { - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - - void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + void CharacterCreation::selectGeneratedClass() { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; @@ -656,6 +638,19 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); updatePlayerHealth(); + } + + void CharacterCreation::onGenerateClassBack() + { + selectGeneratedClass(); + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + { + selectGeneratedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index f6e7c6c923..7fb67caf65 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -83,6 +83,7 @@ namespace MWGui //Race dialog void onRaceDialogDone(WindowBase* parWindow); void onRaceDialogBack(); + void selectRace(); //Class dialogs void onClassChoice(int _index); @@ -94,10 +95,14 @@ namespace MWGui void onClassQuestionChosen(int _index); void onGenerateClassBack(); void onGenerateClassDone(WindowBase* parWindow); + void selectGeneratedClass(); + void selectCreatedClass(); + void selectPickedClass(); //Birthsign dialog void onBirthSignDialogDone(WindowBase* parWindow); void onBirthSignDialogBack(); + void selectBirthSign(); //Review dialog void onReviewDialogDone(WindowBase* parWindow); From 211deeb63e2c5f70dd3a8a78dcb8f16cd17b2c5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:33:34 +0200 Subject: [PATCH 0923/1812] Don't attempt to lock or unlock unsuitable objects (Fixes #2826) --- apps/openmw/mwclass/container.cpp | 13 +++++++------ apps/openmw/mwclass/container.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 5 +++++ apps/openmw/mwclass/door.hpp | 2 ++ apps/openmw/mwmechanics/security.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 2 ++ 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 862ae6c5d9..8304936279 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -281,9 +281,12 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Container::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } - MWWorld::Ptr - Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -291,8 +294,7 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const + void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { const ESM::ContainerState& state2 = dynamic_cast (state); @@ -307,8 +309,7 @@ namespace MWClass readState (state2.mInventory); } - void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const + void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { ESM::ContainerState& state2 = dynamic_cast (state); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3268d45d13..3541937d12 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -57,6 +57,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5a8c736d91..5062cc5572 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -207,6 +207,11 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Door::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } + std::string Door::getScript (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 9cfb465098..db5a7f32a3 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -47,6 +47,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 9eab5bfef0..97878db874 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -31,7 +31,7 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (!(lock.getCellRef().getLockLevel() > 0)) //If it's unlocked back out immediately + if (!(lock.getCellRef().getLockLevel() > 0) || !lock.getClass().canLock(lock)) //If it's unlocked back out immediately return; int lockStrength = lock.getCellRef().getLockLevel(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1613300d76..675177508a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -562,7 +562,7 @@ namespace MWMechanics void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; - if (!target.getClass().isActor()) + if (target.getClass().canLock(target)) { if (effectId == ESM::MagicEffect::Lock) { @@ -570,7 +570,7 @@ namespace MWMechanics { if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(static_cast(magnitude)); + target.getClass().lock(target, static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -586,7 +586,7 @@ namespace MWMechanics if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } - target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); + target.getClass().unlock(target); } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 180cba3327..18200e33b4 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -144,6 +144,11 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } + bool Class::canLock(const Ptr &ptr) const + { + return false; + } + void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const { throw std::runtime_error ("class does not support time-based uses"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cd05b471b3..1157db6704 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -161,6 +161,8 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) + virtual bool canLock (const Ptr& ptr) const; + virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object, such as an equippable light /// source. (default implementation: throw an exception) From 1e18a73b1c7ba1551a2eecbd1c4b45fd4298dd9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:55:38 +0200 Subject: [PATCH 0924/1812] Don't play magic effect sounds & visual effects for unsuitable targets (Fixes #2811) --- apps/openmw/mwmechanics/spellcasting.cpp | 43 ++++++++++++++++-------- apps/openmw/mwmechanics/spellcasting.hpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 --- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 675177508a..eacd674ede 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -489,8 +489,8 @@ namespace MWMechanics if (!wasDead && isDead) MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); } - else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + else if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) + continue; } // Re-casting a summon effect will remove the creature from previous castings of that effect. @@ -559,7 +559,7 @@ namespace MWMechanics target.getClass().onHit(target, 0.f, true, MWWorld::Ptr(), caster, true); } - void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) + bool CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; if (target.getClass().canLock(target)) @@ -572,6 +572,7 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } + return true; } else if (effectId == ESM::MagicEffect::Open) { @@ -590,43 +591,55 @@ namespace MWMechanics } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); + return true; } } - else + else if (target.getClass().isActor()) { - if (effectId == ESM::MagicEffect::CurePoison) + switch (effectId) + { + case ESM::MagicEffect::CurePoison: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); - else if (effectId == ESM::MagicEffect::CureParalyzation) + return true; + case ESM::MagicEffect::CureParalyzation: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); - else if (effectId == ESM::MagicEffect::CureCommonDisease) + return true; + case ESM::MagicEffect::CureCommonDisease: target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease(); - else if (effectId == ESM::MagicEffect::CureBlightDisease) + return true; + case ESM::MagicEffect::CureBlightDisease: target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease(); - else if (effectId == ESM::MagicEffect::CureCorprusDisease) + return true; + case ESM::MagicEffect::CureCorprusDisease: target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); - else if (effectId == ESM::MagicEffect::Dispel) + return true; + case ESM::MagicEffect::Dispel: target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); - else if (effectId == ESM::MagicEffect::RemoveCurse) + return true; + case ESM::MagicEffect::RemoveCurse: target.getClass().getCreatureStats(target).getSpells().purgeCurses(); + return true; + } if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) - return; - if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) - return; + return false; if (effectId == ESM::MagicEffect::DivineIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker"); + return true; } else if (effectId == ESM::MagicEffect::AlmsiviIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker"); + return true; } else if (effectId == ESM::MagicEffect::Mark) { MWBase::Environment::get().getWorld()->getPlayer().markPosition( target.getCell(), target.getRefData().getPosition()); + return true; } else if (effectId == ESM::MagicEffect::Recall) { @@ -640,8 +653,10 @@ namespace MWMechanics markedPosition, false); action.execute(target); } + return true; } } + return false; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 418e9f56dc..5b48bd4a8d 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -97,7 +97,8 @@ namespace MWMechanics const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false); /// @note \a caster can be any type of object, or even an empty object. - void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); + /// @return was the target suitable for the effect? + bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a97c8f0d4b..fb27789404 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2656,10 +2656,6 @@ namespace MWWorld target = result.mHitObject; hitPosition = result.mHitPos; - // don't allow casting on non-activatable objects - if (!target.isEmpty() && !target.getClass().isActor() && target.getClass().getName(target).empty()) - target = MWWorld::Ptr(); - std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From e8c9d3ea2ae72fe72ae974e69a24490ab9c361a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 23:29:19 +0200 Subject: [PATCH 0925/1812] Fix cell names on world map not always being translated (Fixes #2832) --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index e26c076e72..2df1c8f3c2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,7 +783,7 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); - markerWidget->setUserString("Caption_TextOneLine", name); + markerWidget->setUserString("Caption_TextOneLine", "#{sCell=" + name + "}"); setGlobalMapMarkerTooltip(markerWidget, x, y); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a5594bee82..a41d5d5270 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -190,7 +190,8 @@ namespace MWGui void renderGlobalMap(Loading::Listener* loadingListener); - // adds the marker to the global map + /// adds the marker to the global map + /// @param name The ESM::Cell::mName void addVisitedLocation(const std::string& name, int x, int y); // reveals this cell's map on the global map diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4552c42f21..db55937043 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -993,7 +993,7 @@ namespace MWGui if (cell->getCell()->isExterior()) { if (!cell->getCell()->mName.empty()) - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->getCell()->getGridX (), cell->getCell()->getGridY ()); + mMap->addVisitedLocation (name, cell->getCell()->getGridX (), cell->getCell()->getGridY ()); mMap->cellExplored (cell->getCell()->getGridX(), cell->getCell()->getGridY()); } From d76fb2d26601bf6d082762b68b157860d41fec0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Aug 2015 13:38:39 +0200 Subject: [PATCH 0926/1812] Apply disintegrate only to weapons and armor (Fixes #2853) --- apps/openmw/mwmechanics/spellcasting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index eacd674ede..b98bf9f96f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -941,7 +941,8 @@ namespace MWMechanics MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator item = inv.getSlot(slot); - if (item != inv.end()) + + if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor || item.getType() == MWWorld::ContainerStore::Type_Weapon)) { if (!item->getClass().hasItemHealth(*item)) return false; From c57e72fe03c35e3c888e7e894f718914ef71744d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 16:09:53 +0200 Subject: [PATCH 0927/1812] Adjust the sleep interruption chance (Fixes #2781) --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4aeec146ff..37a827745f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -157,7 +157,7 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < fSleepRandMod * hoursToWait) + if (x < static_cast(fSleepRandMod * hoursToWait)) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); From e36ebc77d57e48973b9514e31a0d82aa02547fa5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 18:39:00 +0200 Subject: [PATCH 0928/1812] Editor: remove creature flag of unknown purpose from the UI --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 579bc98996..177fb59ce4 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -109,7 +109,6 @@ namespace CSMWorld { ColumnId_OriginalCreature, "Original Creature" }, { ColumnId_Biped, "Biped" }, { ColumnId_HasWeapon, "Has Weapon" }, - { ColumnId_NoMovement, "No Movement" }, { ColumnId_Swims, "Swims" }, { ColumnId_Flies, "Flies" }, { ColumnId_Walks, "Walks" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5dfa479f61..2f66542b1e 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -102,7 +102,7 @@ namespace CSMWorld ColumnId_OriginalCreature = 87, ColumnId_Biped = 88, ColumnId_HasWeapon = 89, - ColumnId_NoMovement = 90, + // unused ColumnId_Swims = 91, ColumnId_Flies = 92, ColumnId_Walks = 93, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5b2d184a7b..16da4aad9f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -321,7 +321,6 @@ CSMWorld::RefIdCollection::RefIdCollection() { { Columns::ColumnId_Biped, ESM::Creature::Bipedal }, { Columns::ColumnId_HasWeapon, ESM::Creature::Weapon }, - { Columns::ColumnId_NoMovement, ESM::Creature::None }, { Columns::ColumnId_Swims, ESM::Creature::Swims }, { Columns::ColumnId_Flies, ESM::Creature::Flies }, { Columns::ColumnId_Walks, ESM::Creature::Walks }, From 58cd2b1a84828f406e2970b7d688fc1e01b0ba38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 19:01:21 +0200 Subject: [PATCH 0929/1812] Remove "Tri Bip*" nodes in creature meshes (meant for debugging)? (Fixes #2148) --- apps/openmw/mwrender/animation.cpp | 43 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ee0ce6df1a..c1ae5fed5d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -208,6 +208,38 @@ namespace std::vector mToRemove; }; + class RemoveTriBipVisitor : public osg::NodeVisitor + { + public: + RemoveTriBipVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &node) + { + const std::string toFind = "tri bip"; + if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) + { + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(&node); + } + } + + void remove() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + } + + private: + std::vector mToRemove; + }; + } namespace MWRender @@ -898,7 +930,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { if (mObjectRoot) { @@ -933,6 +965,13 @@ namespace MWRender removeDrawableVisitor.remove(); } + if (isCreature) + { + RemoveTriBipVisitor removeTriBipVisitor; + mObjectRoot->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); + } + NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); @@ -1308,7 +1347,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, false); if (animated) addAnimSource(model); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 23f8072388..30b6d156ad 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -273,7 +273,7 @@ protected: * @param baseonly If true, then any meshes or particle systems in the model are ignored * (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files). */ - void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly); + void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 35294b1b59..f46736a394 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -24,7 +24,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); @@ -42,7 +42,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model, true, false); + setObjectRoot(model, true, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6417bc812c..c5a107837e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -378,7 +378,7 @@ void NpcAnimation::updateNpcBase() : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel, true, true); + setObjectRoot(smodel, true, true, false); if(mViewMode != VM_FirstPerson) { From 7dd09dd637c317d3d94497b9d1cca4e1c4e54420 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 20:44:15 +0200 Subject: [PATCH 0930/1812] Fix being able to flip journal pages with the mousewheel when the options overlay is active (Fixes #2855) --- apps/openmw/mwgui/journalwindow.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4cfcc80641..8238f6585c 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -61,6 +61,7 @@ namespace DisplayStateStack mStates; Book mTopicIndexBook; bool mQuestMode; + bool mOptionsMode; bool mAllQuests; template @@ -182,6 +183,7 @@ namespace mQuestMode = false; mAllQuests = false; + mOptionsMode = false; } void adjustButton (char const * name, bool optional = false) @@ -244,6 +246,7 @@ namespace void setBookMode () { + mOptionsMode = false; setVisible (OptionsBTN, true); setVisible (OptionsOverlay, false); @@ -253,6 +256,8 @@ namespace void setOptionsMode () { + mOptionsMode = true; + setVisible (OptionsBTN, false); setVisible (OptionsOverlay, true); @@ -508,6 +513,8 @@ namespace void notifyNextPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; @@ -523,6 +530,8 @@ namespace void notifyPrevPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; From 47ac20af40a8d322380e0e6d81a22812466e4666 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:28:59 +0200 Subject: [PATCH 0931/1812] Workaround flipped cursor on OS X --- components/sdlutil/sdlcursormanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 89928d1651..70a1593066 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,7 +126,13 @@ namespace glViewport(0, 0, width, height); +#if defined(__APPLE__) + // FIXME: why are the extra flips needed on Mac? glReadPixels bug? + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); +#else osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); +#endif + geom->drawImplementation(renderInfo); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); From dbcce482a686f1b568663585d01e99b6fcab6447 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 12 Aug 2015 00:38:02 +0200 Subject: [PATCH 0932/1812] OS X: enable high resolution mode for OpenMW & OpenCS We don't support retina completely yet, but it's still better than blurry mess, and Qt does pretty good job for OpenCS already. --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 1 + .../mac/{Info.plist => openmw-Info.plist.in} | 2 + files/mac/openmw-cs-Info.plist.in | 38 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) rename files/mac/{Info.plist => openmw-Info.plist.in} (95%) create mode 100644 files/mac/openmw-cs-Info.plist.in diff --git a/CMakeLists.txt b/CMakeLists.txt index ad3c21e53d..1e966a1635 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ if(MYGUI_STATIC) endif (MYGUI_STATIC) if (APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw-Info.plist.in "${APP_BUNDLE_DIR}/Contents/Info.plist") configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e6dd045e1e..b1953ee975 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -192,6 +192,7 @@ if(APPLE) MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION} + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs-Info.plist.in" ) set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES diff --git a/files/mac/Info.plist b/files/mac/openmw-Info.plist.in similarity index 95% rename from files/mac/Info.plist rename to files/mac/openmw-Info.plist.in index f832b09c9d..efd55ee5c3 100644 --- a/files/mac/Info.plist +++ b/files/mac/openmw-Info.plist.in @@ -26,5 +26,7 @@ NSHumanReadableCopyright + NSHighResolutionCapable + diff --git a/files/mac/openmw-cs-Info.plist.in b/files/mac/openmw-cs-Info.plist.in new file mode 100644 index 0000000000..684ad79087 --- /dev/null +++ b/files/mac/openmw-cs-Info.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + From af5ffa554821b4263c9a28ec279a48b1bd5937b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:53:29 +0200 Subject: [PATCH 0933/1812] Don't warn about SDL touch events --- components/sdlutil/sdlinputwrapper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f607b7046b..200d19bd8c 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -138,6 +138,16 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v break; case SDL_CLIPBOARDUPDATE: break; // We don't need this event, clipboard is retrieved on demand + + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + case SDL_DOLLARGESTURE: + case SDL_DOLLARRECORD: + case SDL_MULTIGESTURE: + // No use for touch & gesture events + break; + default: std::ios::fmtflags f(std::cerr.flags()); std::cerr << "Unhandled SDL event of type 0x" << std::hex << evt.type << std::endl; From 82419763687c7afea51ec807324099bff925d77a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 23:27:37 +0200 Subject: [PATCH 0934/1812] Don't attempt to play non-existing hit animations (Fixes #2856) --- apps/openmw/mwmechanics/character.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 22ddf1fb77..3959c413a6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -247,15 +247,16 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); if(mHitState == CharState_None) { - if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 + if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) + && mAnimation->hasAnimation("knockout")) { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } - else if(knockdown) + else if(knockdown && mAnimation->hasAnimation("knockdown")) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; @@ -263,11 +264,15 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else if (recovery) { - mHitState = CharState_Hit; - mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + std::string anim = chooseRandomGroup("hit"); + if (mAnimation->hasAnimation(anim)) + { + mHitState = CharState_Hit; + mCurrentHit = anim; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + } } - else if (block) + else if (block && mAnimation->hasAnimation("shield")) { mHitState = CharState_Block; mCurrentHit = "shield"; From c25dacb4802c97761e66b9d5f157d847951774b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:50:44 +0200 Subject: [PATCH 0935/1812] Fix "Level" string in the save/load menu not being localised (Bug #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d490d49cdb..ae36cbacc3 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -347,7 +347,7 @@ namespace MWGui char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; - text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; + text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << mCurrentSlot->mProfile.mPlayerCell << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; From afb3d94ba41263127d90416302ed26f97885fc98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:55:14 +0200 Subject: [PATCH 0936/1812] Fix cell names in the save/load menu not being localised (Fixes #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ae36cbacc3..82dd0d8a9f 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -348,7 +348,7 @@ namespace MWGui if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; - text << mCurrentSlot->mProfile.mPlayerCell << "\n"; + text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); From 8426d376f02765a5e446c818a1f2d0b40c481f3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 02:06:04 +0200 Subject: [PATCH 0937/1812] Use separate touch spell raycasts for actors and objects (Fixes #2849) --- apps/openmw/mwworld/worldimp.cpp | 34 ++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb27789404..f1bcec7316 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2624,12 +2624,10 @@ namespace MWWorld { MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - // Get the target to use for "on touch" effects + // Get the target to use for "on touch" effects, using the facing direction from Head node MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - - // For NPCs use facing direction from Head node osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); MWRender::Animation* anim = mRendering->getAnimation(actor); @@ -2652,9 +2650,33 @@ namespace MWWorld osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f dest = origin + direction * distance; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); - target = result.mHitObject; - hitPosition = result.mHitPos; + // For actor targets, we want to use bounding boxes (physics raycast). + // This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise. + // For object targets, we want the detailed shapes (rendering raycast). + // If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf. + + MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, MWPhysics::CollisionType_Actor); + + MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + + float dist1 = FLT_MAX; + float dist2 = FLT_MAX; + + if (result1.mHit) + dist1 = (origin - result1.mHitPos).length(); + if (result2.mHit) + dist2 = (origin - result2.mHitPointWorld).length(); + + if (dist1 <= dist2 && result1.mHit) + { + target = result1.mHitObject; + hitPosition = result1.mHitPos; + } + else if (result2.mHit) + { + target = result2.mHitObject; + hitPosition = result2.mHitPointWorld; + } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 3d419a612a1898847e5a536462072dae34ec0345 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 15 Aug 2015 23:38:49 -0500 Subject: [PATCH 0938/1812] Corrected some weather transition calculations Reversed some formulas for Transition Delta and Clouds Maximum Percent and implemented them. Refactored Weather some to encapsulate those formulas (to more closely match MoonModel). Did some small cleanup of WeatherManager. --- apps/openmw/mwworld/weather.cpp | 222 ++++++++++++++++---------------- apps/openmw/mwworld/weather.hpp | 68 ++++++---- 2 files changed, 153 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8d78b969ee..99193de672 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,68 @@ namespace } } +Weather::Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) + : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) + , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) + , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) + , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) + , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) + , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) + , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) + , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) + , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) + , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) + , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) + , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) + , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) + , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) + , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) + , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) + , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) + , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) + , mAmbientLoopSoundID(ambientLoopSoundID) + , mIsStorm(mWindSpeed > stormWindSpeed) + , mRainSpeed(rainSpeed) + , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) + , mParticleEffect(particleEffect) + , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") + , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) + , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) +{ +/* +Unhandled: +Rain Diameter=600 ? +Rain Height Min=200 ? +Rain Height Max=700 ? +Rain Threshold=0.6 ? +Max Raindrops=650 ? +*/ +} + +float Weather::transitionSeconds() const +{ + // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds + // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. + static const float deltasPerHour = 0.00835; + return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; +} + +float Weather::cloudBlendFactor(float transitionRatio) const +{ + // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. + return transitionRatio / mCloudsMaximumPercent; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -206,80 +268,29 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) -{ - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); - weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); - - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); - - weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; - - bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); - if (usesPrecip) - weather.mRainEffect = "meshes\\raindrop.nif"; - weather.mRainSpeed = mRainSpeed; - weather.mRainFrequency = mFallback->getFallbackFloat("Weather_"+upper+"_Rain_Entrance_Speed"); - /* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ - - mWeatherSettings[name] = weather; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals - mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); + mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; - mRainSpeed = mFallback->getFallbackFloat("Weather_Precip_Gravity"); + mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); //Some useful values /* TODO: Use pre-sunrise_time, pre-sunset_time, @@ -292,47 +303,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; - //Weather - Weather clear; - setFallbackWeather(clear,"clear"); - - Weather cloudy; - setFallbackWeather(cloudy,"cloudy"); - - Weather foggy; - setFallbackWeather(foggy,"foggy"); - - Weather thunderstorm; - thunderstorm.mAmbientLoopSoundID = "rain heavy"; - thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(thunderstorm,"thunderstorm"); - - Weather rain; - rain.mAmbientLoopSoundID = "rain"; - rain.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(rain,"rain"); - - Weather overcast; - setFallbackWeather(overcast,"overcast"); - - Weather ashstorm; - ashstorm.mAmbientLoopSoundID = "ashstorm"; - ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - setFallbackWeather(ashstorm,"ashstorm"); - - Weather blight; - blight.mAmbientLoopSoundID = "blight"; - blight.mParticleEffect = "meshes\\blightcloud.nif"; - setFallbackWeather(blight,"blight"); - - Weather snow; - snow.mParticleEffect = "meshes\\snow.nif"; - setFallbackWeather(snow, "snow"); - - Weather blizzard; - blizzard.mAmbientLoopSoundID = "BM Blizzard"; - blizzard.mParticleEffect = "meshes\\blizzard.nif"; - setFallbackWeather(blizzard,"blizzard"); + addWeather("Clear", *fallback); + addWeather("Cloudy", *fallback); + addWeather("Foggy", *fallback); + addWeather("Overcast", *fallback); + addWeather("Rain", *fallback, "rain"); + addWeather("Thunderstorm", *fallback, "rain heavy"); + addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", *fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); } WeatherManager::~WeatherManager() @@ -358,19 +338,19 @@ void WeatherManager::setWeather(const std::string& weather, bool instant) if (mNextWeather != "") { // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600) <= 0.5) + if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) mCurrentWeather = mNextWeather; } mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f; + mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); } mFirstUpdate = false; } void WeatherManager::setResult(const std::string& weatherType) { - const Weather& current = mWeatherSettings[weatherType]; + const Weather& current = findWeather(weatherType); mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; @@ -473,9 +453,11 @@ void WeatherManager::transition(float factor) setResult(mNextWeather); const MWRender::WeatherResult other = mResult; + const Weather& nextWeather = findWeather(mNextWeather); + mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = factor; + mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); @@ -547,7 +529,7 @@ void WeatherManager::update(float duration, bool paused) } if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); + transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); else setResult(mCurrentWeather); @@ -945,3 +927,23 @@ void WeatherManager::advanceTime(double hours) { mTimePassed += hours*3600; } + +inline void WeatherManager::addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) +{ + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + + std::string lower = name; + lower[0] = tolower(lower[0]); + mWeatherSettings.insert(std::make_pair(lower, weather)); +} + +inline Weather& WeatherManager::findWeather(const std::string& name) +{ + return mWeatherSettings.at(name); +} + diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7f4858bc8d..710e45d9b6 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -33,53 +33,55 @@ namespace MWWorld class Fallback; /// Defines a single weather setting (according to INI) - struct Weather + class Weather { + public: + Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect); + std::string mCloudTexture; // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor, - mSkyDayColor, - mSkySunsetColor, - mSkyNightColor; + osg::Vec4f mSkySunriseColor; + osg::Vec4f mSkyDayColor; + osg::Vec4f mSkySunsetColor; + osg::Vec4f mSkyNightColor; // Fog colors - osg::Vec4f mFogSunriseColor, - mFogDayColor, - mFogSunsetColor, - mFogNightColor; + osg::Vec4f mFogSunriseColor; + osg::Vec4f mFogDayColor; + osg::Vec4f mFogSunsetColor; + osg::Vec4f mFogNightColor; // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor, - mAmbientDayColor, - mAmbientSunsetColor, - mAmbientNightColor; + osg::Vec4f mAmbientSunriseColor; + osg::Vec4f mAmbientDayColor; + osg::Vec4f mAmbientSunsetColor; + osg::Vec4f mAmbientNightColor; // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor, - mSunDayColor, - mSunSunsetColor, - mSunNightColor; + osg::Vec4f mSunSunriseColor; + osg::Vec4f mSunDayColor; + osg::Vec4f mSunSunsetColor; + osg::Vec4f mSunNightColor; // Fog depth/density - float mLandFogDayDepth, - mLandFogNightDepth; + float mLandFogDayDepth; + float mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) osg::Vec4f mSunDiscSunsetColor; - // Duration of weather transition (in days) - float mTransitionDelta; - // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) float mWindSpeed; // Cloud animation speed multiplier float mCloudSpeed; - // TODO: What is this supposed to do? - float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect. // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; @@ -107,6 +109,13 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + float transitionSeconds() const; + float cloudBlendFactor(float transitionRatio) const; + + private: + float mTransitionDelta; + float mCloudsMaximumPercent; }; class MoonModel @@ -197,9 +206,7 @@ namespace MWWorld MWBase::SoundPtr mAmbientSound; std::string mPlayingSoundID; - MWWorld::Fallback* mFallback; MWWorld::ESMStore* mStore; - void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; @@ -251,6 +258,13 @@ namespace MWWorld std::string mThunderSoundID3; MoonModel mMasser; MoonModel mSecunda; + + void addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID = "", + const std::string& particleEffect = ""); + + Weather& findWeather(const std::string& name); }; } From 5049c9ab6a85a58c0b56c2498ea55f36e359a397 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 17:41:33 +1200 Subject: [PATCH 0939/1812] removed unnecessary tests. --- apps/openmw/mwmechanics/pathfinding.cpp | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f469832a51..d8e6a37b7e 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -25,8 +25,7 @@ namespace // int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { - if(!grid || grid->mPoints.empty()) - return -1; + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -228,21 +227,22 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); + assert(!mPath.empty()); - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } + // If endNode found is NOT the closest PathGrid point to the endPoint, + // assume endPoint is not reachable from endNode. In which case, + // path ends at endNode. + // + // So only add the destination (which may be different to the closest + // pathgrid point) when endNode was the closest point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); return; } From 942a987d528de8202e15c63607a20539675d3b85 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:55:02 +1200 Subject: [PATCH 0940/1812] centralize the world/cell coordinate conversion logic. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 13 ++---- .../mwmechanics/coordinateconverter.cpp | 43 +++++++++++++++++++ .../mwmechanics/coordinateconverter.hpp | 37 ++++++++++++++++ apps/openmw/mwmechanics/pathfinding.cpp | 24 +++++------ apps/openmw/mwmechanics/pathgrid.cpp | 20 ++------- apps/openmw/mwrender/pathgrid.cpp | 7 +-- 7 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 apps/openmw/mwmechanics/coordinateconverter.cpp create mode 100644 apps/openmw/mwmechanics/coordinateconverter.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cd1ac31ec5..c33b711e68 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects aistate + character actors objects aistate coordinateconverter ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 440814fb7c..afe34218e4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -20,6 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" +#include "coordinateconverter.hpp" @@ -587,11 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - if (cell->isExterior()) - { - point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; - point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; - } + CoordinateConverter(cell).ToWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -749,11 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - if(cell->isExterior()) - { - npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter(cell).ToLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp new file mode 100644 index 0000000000..583ac41c52 --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -0,0 +1,43 @@ +#include "coordinateconverter.hpp" + +#include +#include + +namespace MWMechanics +{ + CoordinateConverter::CoordinateConverter(const ESM::Cell* cell) + : mCellX(0), mCellY(0) + { + if (cell->isExterior()) + { + mCellX = cell->mData.mX * ESM::Land::REAL_SIZE; + mCellY = cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + + void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + { + point.mX += mCellX; + point.mY += mCellY; + } + + void CoordinateConverter::ToWorld(osg::Vec3f& point) + { + point.x() += static_cast(mCellX); + point.y() += static_cast(mCellY); + } + + void CoordinateConverter::ToLocal(osg::Vec3f& point) + { + point.x() -= static_cast(mCellX); + point.y() -= static_cast(mCellY); + } + + osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + { + return osg::Vec3f( + static_cast(point.mX - mCellX), + static_cast(point.mY - mCellY), + static_cast(point.mZ)); + } +} diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp new file mode 100644 index 0000000000..2c4d3d3ba8 --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H +#define GAME_MWMECHANICS_COORDINATECONVERTER_H + +#include +#include + +namespace ESM +{ + struct Cell; +} + +namespace MWMechanics +{ + /// \brief convert coordinates between world and local cell + class CoordinateConverter + { + public: + CoordinateConverter(const ESM::Cell* cell); + + /// in-place conversion from local to world + void ToWorld(ESM::Pathgrid::Point& point); + + /// in-place conversion from local to world + void ToWorld(osg::Vec3f& point); + + /// in-place conversion from world to local + void ToLocal(osg::Vec3f& point); + + osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + + private: + int mCellX; + int mCellY; + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d8e6a37b7e..1147371b19 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -5,6 +5,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "coordinateconverter.hpp" namespace { @@ -106,11 +107,6 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) - { - return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); - } - PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -194,23 +190,17 @@ namespace MWMechanics } // NOTE: getClosestPoint expects local co-ordinates - float xCell = 0; - float yCell = 0; - if (mCell->isExterior()) - { - xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter converter(mCell->getCell()); // NOTE: It is possible that getClosestPoint returns a pathgrind point index // that is unreachable in some situations. e.g. actor is standing // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -229,6 +219,12 @@ namespace MWMechanics mPath = mCell->aStarSearch(startNode, endNode.first); assert(!mPath.empty()); + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } + // If endNode found is NOT the closest PathGrid point to the endPoint, // assume endPoint is not reachable from endNode. In which case, // path ends at endNode. diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 66af864ea1..871baecdc3 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -312,29 +312,15 @@ namespace MWMechanics if(current != goal) return path; // for some reason couldn't build a path - // reconstruct path to return, using world co-ordinates - int xCell = 0; - int yCell = 0; - if (mIsExterior) - { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; - } - + // reconstruct path to return, using local co-ordinates while(graphParent[current] != -1) { - ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[current]); current = graphParent[current]; } // add first node to path explicitly - ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[start]); return path; } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 9fffd76d10..bd22446dea 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -17,6 +17,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" +#include "../mwmechanics/coordinateconverter.hpp" #include "vismask.hpp" @@ -207,11 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - if (store->getCell()->isExterior()) - { - cellPathGridPos.x() = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); - cellPathGridPos.y() = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 4d9d8a060d6821744e03ea5ddbfcd298885219c2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:56:28 +1200 Subject: [PATCH 0941/1812] Pathing bugfix. When path contains one one point from path grid, point is no longer being discarded. --- apps/openmw/mwmechanics/pathfinding.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1147371b19..777ccacae8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -212,6 +212,10 @@ namespace MWMechanics // nodes are the same if(startNode == endNode.first) { + ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); + converter.ToWorld(temp); + mPath.push_back(temp); + mPath.push_back(endPoint); return; } From 1b663f01aff94811a46825467cad8f38ed025b24 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 15:24:48 +0200 Subject: [PATCH 0942/1812] create merged document and open a view for it (document is still empty at this point) --- apps/opencs/CMakeLists.txt | 8 +++++-- apps/opencs/editor.cpp | 3 ++- apps/opencs/model/doc/document.cpp | 4 +++- apps/opencs/model/doc/document.hpp | 6 ++++- apps/opencs/model/doc/documentmanager.cpp | 16 ++++++++++++- apps/opencs/model/doc/documentmanager.hpp | 13 +++++++++++ apps/opencs/model/doc/operation.hpp | 4 +++- apps/opencs/model/tools/mergeoperation.cpp | 19 ++++++++++++---- apps/opencs/model/tools/mergeoperation.hpp | 19 ++++++++++++++-- apps/opencs/model/tools/mergestages.cpp | 18 +++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 26 ++++++++++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 20 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 4 +++- apps/opencs/model/tools/tools.hpp | 7 +++++- apps/opencs/view/tools/merge.cpp | 13 ++++++++--- apps/opencs/view/tools/merge.hpp | 4 +++- 16 files changed, 165 insertions(+), 19 deletions(-) create mode 100644 apps/opencs/model/tools/mergestages.cpp create mode 100644 apps/opencs/model/tools/mergestages.hpp create mode 100644 apps/opencs/model/tools/mergestate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 833ca65515..091b566d1b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,14 +35,18 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel + tools reportmodel mergeoperation ) opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck - mergeoperation + mergestages + ) + +opencs_hdrs_noqt (model/tools + mergestate ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 0b385f2757..7f9e2746e2 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,8 @@ CS::Editor::Editor () : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), - mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) + mLock(), mMerge (mDocumentManager), + mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a331706bcf..67ecbd6418 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2294,6 +2294,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); + connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); @@ -2388,7 +2390,7 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } -void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +void CSMDoc::Document::runMerge (std::auto_ptr target) { mTools.runMerge (target); emit stateChanged (getState(), this); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 901a8e3e49..3eaa5bb148 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -130,7 +130,7 @@ namespace CSMDoc void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); @@ -158,6 +158,10 @@ namespace CSMDoc void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + private slots: void modificationStateChanged (bool clean); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 02d4ab5c06..03758dc6a9 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -57,10 +57,24 @@ bool CSMDoc::DocumentManager::isEmpty() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + Document *document = makeDocument (files, savePath, new_); + insertDocument (document); +} +CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( + const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_) +{ + return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); +} + +void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) +{ mDocuments.push_back (document); + connect (document, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SLOT (insertDocument (CSMDoc::Document*))); + emit loadRequest (document); mLoader.hasThingsToDo().wakeAll(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index f9b18bfe61..4f6b2b2c99 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -56,6 +56,15 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. + /// Create a new document. The ownership of the created document is transferred to + /// the calling function. The DocumentManager does not manage it. Loading has not + /// taken place at the point when the document is returned. + /// + /// \param new_ Do not load the last content file in \a files and instead create in an + /// appropriate way. + Document *makeDocument (const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -84,6 +93,10 @@ namespace CSMDoc void removeDocument (CSMDoc::Document *document); ///< Emits the lastDocumentDeleted signal, if applicable. + /// Hand over document to *this. The ownership is transferred. The DocumentManager + /// will initiate the load procedure, if necessary + void insertDocument (CSMDoc::Document *document); + signals: void documentAdded (CSMDoc::Document *document); diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 703f9d44b7..3c86a6e235 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -83,7 +83,9 @@ namespace CSMDoc void executeStage(); - void operationDone(); + protected slots: + + virtual void operationDone(); }; } diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 65cfdb4ff4..c93452dad9 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -2,14 +2,25 @@ #include "mergeoperation.hpp" #include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "mergestages.hpp" CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) -: CSMDoc::Operation (CSMDoc::State_Merging, true) +: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - + appendStage (new FinishMergedDocumentStage (mState)); } -void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +void CSMTools::MergeOperation::setTarget (std::auto_ptr document) { - + mState.mTarget = document; +} + +void CSMTools::MergeOperation::operationDone() +{ + CSMDoc::Operation::operationDone(); + + if (mState.mCompleted) + emit mergeDone (mState.mTarget.release()); } diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index 84526b2f20..dc958d31b0 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -1,10 +1,12 @@ #ifndef CSM_TOOLS_MERGEOPERATION_H #define CSM_TOOLS_MERGEOPERATION_H -#include +#include #include "../doc/operation.hpp" +#include "mergestate.hpp" + namespace CSMDoc { class Document; @@ -14,14 +16,27 @@ namespace CSMTools { class MergeOperation : public CSMDoc::Operation { + Q_OBJECT + MergeState mState; public: MergeOperation (CSMDoc::Document& document); /// \attention Do not call this function while a merge is running. - void setTarget (const boost::filesystem::path& target); + void setTarget (std::auto_ptr document); + + protected slots: + + virtual void operationDone(); + + signals: + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + }; } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp new file mode 100644 index 0000000000..16ea0495a7 --- /dev/null +++ b/apps/opencs/model/tools/mergestages.cpp @@ -0,0 +1,18 @@ + +#include "mergestages.hpp" + +#include "mergestate.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) +: mState (state) +{} + +int CSMTools::FinishMergedDocumentStage::setup() +{ + return 1; +} + +void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = true; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp new file mode 100644 index 0000000000..138b89d72e --- /dev/null +++ b/apps/opencs/model/tools/mergestages.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_TOOLS_MERGESTAGES_H +#define CSM_TOOLS_MERGESTAGES_H + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + struct MergeState; + + class FinishMergedDocumentStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + FinishMergedDocumentStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp new file mode 100644 index 0000000000..4482ba6f4a --- /dev/null +++ b/apps/opencs/model/tools/mergestate.hpp @@ -0,0 +1,20 @@ +#ifndef CSM_TOOLS_MERGESTATE_H +#define CSM_TOOLS_MERGESTATE_H + +#include + +#include "../doc/document.hpp" + +namespace CSMTools +{ + struct MergeState + { + std::auto_ptr mTarget; + CSMDoc::Document& mSource; + bool mCompleted; + + MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 681f74404b..78b0528135 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -195,7 +195,7 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } -void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +void CSMTools::Tools::runMerge (std::auto_ptr target) { // not setting an active report, because merge does not produce messages @@ -203,6 +203,8 @@ void CSMTools::Tools::runMerge (const boost::filesystem::path& target) { mMergeOperation = new MergeOperation (mDocument); mMerge.setOperation (mMergeOperation); + connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); } mMergeOperation->setTarget (target); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 9520999280..2302fe2e05 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,6 +1,7 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include #include #include @@ -73,7 +74,7 @@ namespace CSMTools void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); ///< \attention The operation is not aborted immediately. @@ -92,6 +93,10 @@ namespace CSMTools void progress (int current, int max, int type); void done (int type, bool failed); + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); }; } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index f775390ee8..566a5ee062 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -10,6 +10,7 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/doc/documentmanager.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" @@ -25,8 +26,8 @@ void CSVTools::Merge::keyPressEvent (QKeyEvent *event) QWidget::keyPressEvent (event); } -CSVTools::Merge::Merge (QWidget *parent) -: QWidget (parent), mDocument (0) +CSVTools::Merge::Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent) +: QWidget (parent), mDocument (0), mDocumentManager (documentManager) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -124,7 +125,13 @@ void CSVTools::Merge::accept() { if ((mDocument->getState() & CSMDoc::State_Merging)==0) { - mDocument->runMerge (mAdjuster->getPath()); + std::vector< boost::filesystem::path > files (1, mAdjuster->getPath()); + + std::auto_ptr target ( + mDocumentManager.makeDocument (files, files[0], true)); + + mDocument->runMerge (target); + hide(); } } diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index b8369ffa32..d4ed7e34b8 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -11,6 +11,7 @@ class QListWidget; namespace CSMDoc { class Document; + class DocumentManager; } namespace CSVDoc @@ -30,12 +31,13 @@ namespace CSVTools QListWidget *mFiles; CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + CSMDoc::DocumentManager& mDocumentManager; void keyPressEvent (QKeyEvent *event); public: - Merge (QWidget *parent = 0); + Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent = 0); /// Configure dialogue for a new merge void configure (CSMDoc::Document *document); From c8d6679a25130a3085a8563c3d7411aa46ead54c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:40:20 +0200 Subject: [PATCH 0943/1812] Remove an unused function --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 ---- apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 183ab07ff9..1d086f2ee3 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -71,7 +71,6 @@ namespace MWGui SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel) : mCategory(Category_All) , mFilter(0) - , mShowEquipped(true) , mSortByType(true) { mSourceModel = sourceModel; @@ -91,9 +90,6 @@ namespace MWGui { MWWorld::Ptr base = item.mBase; - if (item.mType == ItemStack::Type_Equipped && !mShowEquipped) - return false; - int category = 0; if (base.getTypeName() == typeid(ESM::Armor).name() || base.getTypeName() == typeid(ESM::Clothing).name()) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 1b68bdd4f1..064f62e771 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -24,7 +24,6 @@ namespace MWGui void setCategory (int category); void setFilter (int filter); - void setShowEquipped (bool show) { mShowEquipped = show; } /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } @@ -49,7 +48,6 @@ namespace MWGui int mCategory; int mFilter; - bool mShowEquipped; bool mSortByType; }; From 9fad33cd14b33c7fde4523a1189801b7e6689e1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:49:37 +0200 Subject: [PATCH 0944/1812] Don't reset the item model's sort/filter options in updatePlayer (Fixes #2863) --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++++++- apps/openmw/mwgui/itemmodel.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/itemmodel.hpp | 4 ++++ apps/openmw/mwgui/itemview.cpp | 4 ++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 9c9138ed51..580e583c95 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -119,7 +119,12 @@ namespace MWGui { mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); - mSortModel = new SortFilterItemModel(mTradeModel); + + if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings + mSortModel->setSourceModel(mTradeModel); + else + mSortModel = new SortFilterItemModel(mTradeModel); + mItemView->setModel(mSortModel); mPreview->updatePtr(mPtr); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 9fce6e84dd..a1e36bce67 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -120,6 +120,11 @@ namespace MWGui } + ProxyItemModel::ProxyItemModel() + : mSourceModel(NULL) + { + } + ProxyItemModel::~ProxyItemModel() { delete mSourceModel; @@ -164,4 +169,18 @@ namespace MWGui return mSourceModel->getIndex(item); } + void ProxyItemModel::setSourceModel(ItemModel *sourceModel) + { + if (mSourceModel == sourceModel) + return; + + if (mSourceModel) + { + delete mSourceModel; + mSourceModel = NULL; + } + + mSourceModel = sourceModel; + } + } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 53c7018e22..2019c10426 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -80,11 +80,15 @@ namespace MWGui class ProxyItemModel : public ItemModel { public: + ProxyItemModel(); virtual ~ProxyItemModel(); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); + /// @note Takes ownership of the passed pointer. + void setSourceModel(ItemModel* sourceModel); + ModelIndex mapToSource (ModelIndex index); ModelIndex mapFromSource (ModelIndex index); protected: diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index df44eb33c3..2cdfcada4d 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -30,8 +30,12 @@ ItemView::~ItemView() void ItemView::setModel(ItemModel *model) { + if (mModel == model) + return; + delete mModel; mModel = model; + update(); } From 47dd9505a9464dc5c947f409c3c4a80cf4d8e395 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 18:27:17 +0200 Subject: [PATCH 0945/1812] copy meta data from game file when merging --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/tools/mergeoperation.cpp | 4 ++-- apps/opencs/model/tools/mergeoperation.hpp | 4 +++- apps/opencs/model/tools/mergestages.cpp | 27 ++++++++++++++++++++-- apps/opencs/model/tools/mergestages.hpp | 5 +++- apps/opencs/model/tools/tools.cpp | 6 ++--- apps/opencs/model/tools/tools.hpp | 5 +++- apps/opencs/model/world/data.cpp | 10 ++++++-- apps/opencs/model/world/data.hpp | 2 ++ 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 67ecbd6418..8d5580bcf7 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2250,7 +2250,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), - mTools (*this), + mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSavingOperation (*this, mProjectPath, encoding), diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index c93452dad9..9e5fb27456 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -6,10 +6,10 @@ #include "mergestages.hpp" -CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index dc958d31b0..bdaeb2ccda 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../doc/operation.hpp" #include "mergestate.hpp" @@ -22,7 +24,7 @@ namespace CSMTools public: - MergeOperation (CSMDoc::Document& document); + MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding); /// \attention Do not call this function while a merge is running. void setTarget (std::auto_ptr document); diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 16ea0495a7..776808b269 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -3,8 +3,11 @@ #include "mergestate.hpp" -CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) -: mState (state) +#include "../doc/document.hpp" +#include "../world/data.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) +: mState (state), mEncoder (encoding) {} int CSMTools::FinishMergedDocumentStage::setup() @@ -14,5 +17,25 @@ int CSMTools::FinishMergedDocumentStage::setup() void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) { + // We know that the content file list contains at least two entries and that the first one + // does exist on disc (otherwise it would have been impossible to initiate a merge on that + // document). + boost::filesystem::path path = mState.mSource.getContentFiles()[0]; + + ESM::ESMReader reader; + reader.setEncoder (&mEncoder); + reader.open (path.string()); + + CSMWorld::MetaData source; + source.mId = "sys::meta"; + source.load (reader); + + CSMWorld::MetaData target = mState.mTarget->getData().getMetaData(); + + target.mAuthor = source.mAuthor; + target.mDescription = source.mDescription; + + mState.mTarget->getData().setMetaData (target); + mState.mCompleted = true; } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 138b89d72e..9844feaca3 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include "../doc/stage.hpp" namespace CSMTools @@ -10,10 +12,11 @@ namespace CSMTools class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; + ToUTF8::Utf8Encoder mEncoder; public: - FinishMergedDocumentStage (MergeState& state); + FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding); virtual int setup(); ///< \return number of steps diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78b0528135..c4ff6868bf 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -116,9 +116,9 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() return &mVerifier; } -CSMTools::Tools::Tools (CSMDoc::Document& document) +CSMTools::Tools::Tools (CSMDoc::Document& document, ToUTF8::FromType encoding) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0), mEncoding (encoding) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -201,7 +201,7 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) if (!mMergeOperation) { - mMergeOperation = new MergeOperation (mDocument); + mMergeOperation = new MergeOperation (mDocument, mEncoding); mMerge.setOperation (mMergeOperation); connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), this, SIGNAL (mergeDone (CSMDoc::Document*))); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 2302fe2e05..e16a3854cc 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -44,6 +46,7 @@ namespace CSMTools std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number + ToUTF8::FromType mEncoding; // not implemented Tools (const Tools&); @@ -59,7 +62,7 @@ namespace CSMTools public: - Tools (CSMDoc::Document& document); + Tools (CSMDoc::Document& document, ToUTF8::FromType encoding); virtual ~Tools(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6c..d8999d950b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -483,7 +483,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mMetaData.addColumn (new FormatColumn); mMetaData.addColumn (new AuthorColumn); mMetaData.addColumn (new FileDescriptionColumn); - + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); @@ -828,6 +828,12 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const return mMetaData.getRecord (0).get(); } +void CSMWorld::Data::setMetaData (const MetaData& metaData) +{ + Record record (RecordBase::State_ModifiedOnly, 0, &metaData); + mMetaData.setRecord (0, record); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -880,7 +886,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); } - + return mReader->getRecordCount(); } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 06f76607fd..5706b005b7 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -255,6 +255,8 @@ namespace CSMWorld const MetaData& getMetaData() const; + void setMetaData (const MetaData& metaData); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// From d1e1c0f38bfd2f94b6120571bb49ead59e298e87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 23:42:08 +0200 Subject: [PATCH 0946/1812] Editor: fix a typo in ESM::Light flag mappings --- apps/opencs/model/world/refidcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 16da4aad9f..85ddbacdb3 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -380,7 +380,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { Columns::ColumnId_Portable, ESM::Light::Carry }, { Columns::ColumnId_NegativeLight, ESM::Light::Negative }, { Columns::ColumnId_Flickering, ESM::Light::Flicker }, - { Columns::ColumnId_SlowFlickering, ESM::Light::Flicker }, + { Columns::ColumnId_SlowFlickering, ESM::Light::FlickerSlow }, { Columns::ColumnId_Pulsing, ESM::Light::Pulse }, { Columns::ColumnId_SlowPulsing, ESM::Light::PulseSlow }, { Columns::ColumnId_Fire, ESM::Light::Fire }, From be7bd9529d312c64de2c5d1329dfbe8caefc02e8 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 16 Aug 2015 16:56:44 -0500 Subject: [PATCH 0947/1812] Classes shouldn't use MWBase::Environment to access their own members. --- apps/openmw/engine.cpp | 74 +++++++++---------- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8d25a923fe..95851b75fd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,7 +66,7 @@ namespace void OMW::Engine::executeLocalScripts() { - MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); + MWWorld::LocalScripts& localScripts = mEnvironment.getWorld()->getLocalScripts(); localScripts.startIteration(); @@ -76,7 +76,7 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); - MWBase::Environment::get().getScriptManager()->run (script.first, interpreterContext); + mEnvironment.getScriptManager()->run (script.first, interpreterContext); } localScripts.setIgnore (MWWorld::Ptr()); @@ -90,7 +90,7 @@ void OMW::Engine::frame(float frametime) mEnvironment.setFrameDuration (frametime); // update input - MWBase::Environment::get().getInputManager()->update(frametime, false); + mEnvironment.getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. @@ -99,76 +99,76 @@ void OMW::Engine::frame(float frametime) // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update(frametime); + mEnvironment.getSoundManager()->update(frametime); // Main menu opened? Then scripts are also paused. - bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); + bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state - MWBase::Environment::get().getStateManager()->update (frametime); + mEnvironment.getStateManager()->update (frametime); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { if (!paused) { - if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + if (mEnvironment.getWorld()->getScriptsEnabled()) { // local scripts executeLocalScripts(); // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + mEnvironment.getScriptManager()->getGlobalScripts().run(); } - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + mEnvironment.getWorld()->markCellAsUnchanged(); } if (!guiActive) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTime( + frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getMechanicsManager()->update(frametime, + mEnvironment.getMechanicsManager()->update(frametime, guiActive); } osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if(!guiActive && player.getClass().getCreatureStats(player).isDead()) - MWBase::Environment::get().getStateManager()->endGame(); + mEnvironment.getStateManager()->endGame(); } // update world osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getWorld()->update(frametime, guiActive); + mEnvironment.getWorld()->update(frametime, guiActive); } osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI - MWBase::Environment::get().getWindowManager()->onFrame(frametime); - if (MWBase::Environment::get().getStateManager()->getState()!= + mEnvironment.getWindowManager()->onFrame(frametime); + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { #if 0 - MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps); + mEnvironment.getWindowManager()->wmUpdateFps(fps); #endif - MWBase::Environment::get().getWindowManager()->update(); + mEnvironment.getWindowManager()->update(); } int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); @@ -511,7 +511,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); - MWBase::Environment::get().getWorld()->setupPlayer(); + mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); @@ -528,7 +528,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); - mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), + mEnvironment.setScriptManager (new MWScript::ScriptManager (mEnvironment.getWorld()->getStore(), mVerboseScripts, *mScriptContext, mWarningsMode, mScriptBlacklistUse ? mScriptBlacklist : std::vector())); @@ -543,7 +543,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // scripts if (mCompileAll) { - std::pair result = MWBase::Environment::get().getScriptManager()->compileAll(); + std::pair result = mEnvironment.getScriptManager()->compileAll(); if (result.first) std::cout << "compiled " << result.second << " of " << result.first << " scripts (" @@ -648,38 +648,38 @@ void OMW::Engine::go() if (!mSaveGameFile.empty()) { - MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); + mEnvironment.getStateManager()->loadGame(mSaveGameFile); } else if (!mSkipMenu) { // start in main menu - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try { // Is there an ini setting for this filename or something? - MWBase::Environment::get().getSoundManager()->streamMusic("Special/morrowind title.mp3"); + mEnvironment.getSoundManager()->streamMusic("Special/morrowind title.mp3"); std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; if (!logo.empty()) - MWBase::Environment::get().getWindowManager()->playVideo(logo, true); + mEnvironment.getWindowManager()->playVideo(logo, true); } catch (...) {} } else { - MWBase::Environment::get().getStateManager()->newGame (!mNewGame); + mEnvironment.getStateManager()->newGame (!mNewGame); } // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; - while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); dt = std::min(dt, 0.2); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); if (!guiActive) simulationTime += dt; @@ -700,15 +700,15 @@ void OMW::Engine::go() void OMW::Engine::activate() { - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + if (mEnvironment.getWindowManager()->isGuiMode()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 || player.getClass().getCreatureStats(player).getKnockedDown()) return; - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); + MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); if (ptr.isEmpty()) return; @@ -724,7 +724,7 @@ void OMW::Engine::activate() return; } - MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + mEnvironment.getWorld()->activate(ptr, mEnvironment.getWorld()->getPlayerPtr()); } void OMW::Engine::screenshot() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b2cd8414e3..9436e35d2d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1367,7 +1367,7 @@ namespace MWMechanics // Doesn't handle possible edge case where no one reported the assault, but in such a case, // for bystanders it is not possible to tell who attacked first, anyway. if (victimStats.getCrimeId() != -1) - MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2e..1738878eaf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1421,7 +1421,7 @@ namespace MWWorld if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) { + if(ptr != getPlayerPtr() ) { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); @@ -1738,7 +1738,7 @@ namespace MWWorld else { cellid.mPaged = true; - MWBase::Environment::get().getWorld()->positionToIndex( + positionToIndex( ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1], cellid.mIndex.mX, @@ -2516,7 +2516,7 @@ namespace MWWorld if (reported) { npcStats.setBounty(npcStats.getBounty()+ - MWBase::Environment::get().getWorld()->getStore().get().find("iWereWolfBounty")->getInt()); + mStore.get().find("iWereWolfBounty")->getInt()); windowManager->messageBox("#{sCrimeMessage}"); } } From b583a2ec330592ca1cf38d260640e2782dd121ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 17 Aug 2015 00:05:57 +0200 Subject: [PATCH 0948/1812] Make SetDelete a no-op for items in containers (Fixes #2864) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6e5029cc32..d345cdf7e2 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -256,6 +256,7 @@ namespace MWBase virtual void fixPosition (const MWWorld::Ptr& actor) = 0; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2e..e1de0f07a0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1050,7 +1050,7 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (!ptr.getRefData().isDeleted()) + if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) { ptr.getRefData().setCount(0); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5251427c52..35e4335492 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -336,7 +336,9 @@ namespace MWWorld /// use the "Head" node as a basis. virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr); virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); From dca08b0b42e1151e598d0e4cf95c4cb4306b508e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 14:51:32 +0200 Subject: [PATCH 0949/1812] Remove a firing assert (Fixes #2871) --- apps/openmw/mwmechanics/pathfinding.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 777ccacae8..798a0ea21c 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -221,7 +221,8 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); - assert(!mPath.empty()); + if (mPath.empty()) + return; // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) From 67bd6cd70837605e1acebe41048b0f7ff88190ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 23:06:12 +0200 Subject: [PATCH 0950/1812] Remove empty line at the beginning of files git ls-files -z | xargs -0 sed -i '1{/^$/d}' --- apps/opencs/editor.cpp | 1 - apps/opencs/main.cpp | 1 - apps/opencs/model/doc/blacklist.cpp | 1 - apps/opencs/model/doc/documentmanager.cpp | 1 - apps/opencs/model/doc/loader.cpp | 1 - apps/opencs/model/doc/messages.cpp | 1 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/doc/operationholder.cpp | 1 - apps/opencs/model/doc/runner.cpp | 1 - apps/opencs/model/doc/saving.cpp | 1 - apps/opencs/model/doc/savingstages.cpp | 1 - apps/opencs/model/doc/savingstate.cpp | 1 - apps/opencs/model/doc/stage.cpp | 1 - apps/opencs/model/filter/andnode.cpp | 1 - apps/opencs/model/filter/booleannode.cpp | 1 - apps/opencs/model/filter/leafnode.cpp | 1 - apps/opencs/model/filter/narynode.cpp | 1 - apps/opencs/model/filter/node.cpp | 1 - apps/opencs/model/filter/notnode.cpp | 1 - apps/opencs/model/filter/ornode.cpp | 1 - apps/opencs/model/filter/parser.cpp | 1 - apps/opencs/model/filter/textnode.cpp | 1 - apps/opencs/model/filter/unarynode.cpp | 1 - apps/opencs/model/filter/valuenode.cpp | 1 - apps/opencs/model/tools/birthsigncheck.cpp | 1 - apps/opencs/model/tools/classcheck.cpp | 1 - apps/opencs/model/tools/factioncheck.cpp | 1 - apps/opencs/model/tools/mandatoryid.cpp | 1 - apps/opencs/model/tools/racecheck.cpp | 1 - apps/opencs/model/tools/regioncheck.cpp | 1 - apps/opencs/model/tools/reportmodel.cpp | 1 - apps/opencs/model/tools/scriptcheck.cpp | 1 - apps/opencs/model/tools/search.cpp | 1 - apps/opencs/model/tools/searchoperation.cpp | 1 - apps/opencs/model/tools/searchstage.cpp | 1 - apps/opencs/model/tools/skillcheck.cpp | 1 - apps/opencs/model/tools/soundcheck.cpp | 1 - apps/opencs/model/tools/spellcheck.cpp | 1 - apps/opencs/model/tools/startscriptcheck.cpp | 1 - apps/opencs/model/tools/tools.cpp | 1 - apps/opencs/model/world/cell.cpp | 1 - apps/opencs/model/world/cellcoordinates.cpp | 1 - apps/opencs/model/world/cellselection.cpp | 1 - apps/opencs/model/world/collectionbase.cpp | 1 - apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/commanddispatcher.cpp | 1 - apps/opencs/model/world/data.cpp | 1 - apps/opencs/model/world/idtablebase.cpp | 1 - apps/opencs/model/world/idtableproxymodel.cpp | 1 - apps/opencs/model/world/infocollection.cpp | 1 - apps/opencs/model/world/metadata.cpp | 1 - apps/opencs/model/world/record.cpp | 1 - apps/opencs/model/world/ref.cpp | 1 - apps/opencs/model/world/refcollection.cpp | 1 - apps/opencs/model/world/refiddata.cpp | 1 - apps/opencs/model/world/regionmap.cpp | 1 - apps/opencs/model/world/resources.cpp | 1 - apps/opencs/model/world/resourcesmanager.cpp | 1 - apps/opencs/model/world/resourcetable.cpp | 1 - apps/opencs/model/world/scope.cpp | 1 - apps/opencs/model/world/scriptcontext.cpp | 1 - apps/opencs/model/world/tablemimedata.hpp | 1 - apps/opencs/model/world/universalid.cpp | 1 - apps/opencs/view/doc/adjusterwidget.cpp | 1 - apps/opencs/view/doc/filewidget.cpp | 1 - apps/opencs/view/doc/globaldebugprofilemenu.cpp | 1 - apps/opencs/view/doc/loader.cpp | 1 - apps/opencs/view/doc/newgame.cpp | 1 - apps/opencs/view/doc/runlogsubview.cpp | 1 - apps/opencs/view/doc/startup.cpp | 1 - apps/opencs/view/doc/subviewfactory.cpp | 1 - apps/opencs/view/doc/viewmanager.cpp | 1 - apps/opencs/view/filter/editwidget.cpp | 1 - apps/opencs/view/filter/filterbox.cpp | 1 - apps/opencs/view/filter/recordfilterbox.cpp | 1 - apps/opencs/view/render/cell.cpp | 1 - apps/opencs/view/render/editmode.cpp | 1 - apps/opencs/view/render/lightingbright.cpp | 1 - apps/opencs/view/render/pagedworldspacewidget.cpp | 1 - apps/opencs/view/render/previewwidget.cpp | 1 - apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.cpp | 1 - apps/opencs/view/tools/reportsubview.cpp | 1 - apps/opencs/view/tools/reporttable.cpp | 1 - apps/opencs/view/tools/searchbox.cpp | 1 - apps/opencs/view/tools/searchsubview.cpp | 1 - apps/opencs/view/tools/subviews.cpp | 1 - apps/opencs/view/widget/modebutton.cpp | 1 - apps/opencs/view/widget/pushbutton.cpp | 1 - apps/opencs/view/widget/scenetool.cpp | 1 - apps/opencs/view/widget/scenetoolbar.cpp | 1 - apps/opencs/view/widget/scenetoolmode.cpp | 1 - apps/opencs/view/widget/scenetoolrun.cpp | 1 - apps/opencs/view/widget/scenetooltoggle.cpp | 1 - apps/opencs/view/widget/scenetooltoggle2.cpp | 1 - apps/opencs/view/world/cellcreator.cpp | 1 - apps/opencs/view/world/creator.cpp | 1 - apps/opencs/view/world/dialoguecreator.cpp | 1 - apps/opencs/view/world/enumdelegate.cpp | 1 - apps/opencs/view/world/genericcreator.cpp | 1 - apps/opencs/view/world/idvalidator.cpp | 1 - apps/opencs/view/world/infocreator.cpp | 1 - apps/opencs/view/world/previewsubview.cpp | 1 - apps/opencs/view/world/recordbuttonbar.cpp | 1 - apps/opencs/view/world/referenceablecreator.cpp | 1 - apps/opencs/view/world/referencecreator.cpp | 1 - apps/opencs/view/world/regionmap.cpp | 1 - apps/opencs/view/world/regionmapsubview.cpp | 1 - apps/opencs/view/world/scenesubview.cpp | 1 - apps/opencs/view/world/scripterrortable.cpp | 1 - apps/opencs/view/world/scripthighlighter.cpp | 1 - apps/opencs/view/world/subviews.cpp | 1 - apps/opencs/view/world/table.cpp | 1 - apps/opencs/view/world/tablebottombox.cpp | 1 - apps/opencs/view/world/tablesubview.cpp | 1 - apps/opencs/view/world/util.cpp | 1 - apps/opencs/view/world/vartypedelegate.cpp | 1 - apps/openmw/android_commandLine.h | 1 - apps/openmw/mwbase/environment.cpp | 1 - apps/openmw/mwclass/activator.cpp | 1 - apps/openmw/mwclass/apparatus.cpp | 1 - apps/openmw/mwclass/armor.cpp | 1 - apps/openmw/mwclass/classes.cpp | 1 - apps/openmw/mwclass/clothing.cpp | 1 - apps/openmw/mwclass/container.cpp | 1 - apps/openmw/mwclass/creature.cpp | 1 - apps/openmw/mwclass/creaturelevlist.cpp | 1 - apps/openmw/mwclass/door.cpp | 1 - apps/openmw/mwclass/ingredient.cpp | 1 - apps/openmw/mwclass/itemlevlist.cpp | 1 - apps/openmw/mwclass/light.cpp | 1 - apps/openmw/mwclass/lockpick.cpp | 1 - apps/openmw/mwclass/misc.cpp | 1 - apps/openmw/mwclass/npc.cpp | 1 - apps/openmw/mwclass/potion.cpp | 1 - apps/openmw/mwclass/probe.cpp | 1 - apps/openmw/mwclass/repair.cpp | 1 - apps/openmw/mwclass/static.cpp | 1 - apps/openmw/mwclass/weapon.cpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - apps/openmw/mwdialogue/filter.cpp | 1 - apps/openmw/mwdialogue/journalentry.cpp | 1 - apps/openmw/mwdialogue/journalimp.cpp | 1 - apps/openmw/mwdialogue/quest.cpp | 1 - apps/openmw/mwdialogue/selectwrapper.cpp | 1 - apps/openmw/mwdialogue/topic.cpp | 1 - apps/openmw/mwgui/tooltips.hpp | 1 - apps/openmw/mwmechanics/alchemy.cpp | 1 - apps/openmw/mwmechanics/magiceffects.cpp | 1 - apps/openmw/mwmechanics/npcstats.cpp | 1 - apps/openmw/mwmechanics/spells.cpp | 1 - apps/openmw/mwscript/aiextensions.cpp | 1 - apps/openmw/mwscript/animationextensions.cpp | 1 - apps/openmw/mwscript/compilercontext.cpp | 1 - apps/openmw/mwscript/consoleextensions.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 1 - apps/openmw/mwscript/controlextensions.cpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 1 - apps/openmw/mwscript/extensions.cpp | 1 - apps/openmw/mwscript/globalscripts.cpp | 1 - apps/openmw/mwscript/guiextensions.cpp | 1 - apps/openmw/mwscript/interpretercontext.cpp | 1 - apps/openmw/mwscript/miscextensions.cpp | 1 - apps/openmw/mwscript/scriptmanagerimp.cpp | 1 - apps/openmw/mwscript/skyextensions.cpp | 1 - apps/openmw/mwscript/soundextensions.cpp | 1 - apps/openmw/mwscript/userextensions.cpp | 1 - apps/openmw/mwstate/character.cpp | 1 - apps/openmw/mwstate/charactermanager.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/action.cpp | 1 - apps/openmw/mwworld/actionapply.cpp | 1 - apps/openmw/mwworld/actioneat.cpp | 1 - apps/openmw/mwworld/actionopen.hpp | 1 - apps/openmw/mwworld/actiontake.cpp | 1 - apps/openmw/mwworld/actiontalk.cpp | 1 - apps/openmw/mwworld/class.cpp | 1 - apps/openmw/mwworld/containerstore.cpp | 1 - apps/openmw/mwworld/globals.cpp | 1 - apps/openmw/mwworld/inventorystore.cpp | 1 - apps/openmw/mwworld/ptr.cpp | 1 - apps/openmw/mwworld/refdata.cpp | 1 - components/compiler/controlparser.cpp | 1 - components/compiler/declarationparser.cpp | 1 - components/compiler/discardparser.cpp | 1 - components/compiler/errorhandler.cpp | 1 - components/compiler/errorhandler.hpp | 1 - components/compiler/exprparser.cpp | 1 - components/compiler/extensions.cpp | 1 - components/compiler/generator.cpp | 1 - components/compiler/junkparser.cpp | 1 - components/compiler/lineparser.cpp | 1 - components/compiler/literals.cpp | 1 - components/compiler/locals.cpp | 1 - components/compiler/nullerrorhandler.cpp | 1 - components/compiler/nullerrorhandler.hpp | 1 - components/compiler/output.cpp | 1 - components/compiler/parser.cpp | 1 - components/compiler/quickfileparser.cpp | 1 - components/compiler/scanner.cpp | 1 - components/compiler/scriptparser.cpp | 1 - components/compiler/skipparser.cpp | 1 - components/compiler/streamerrorhandler.cpp | 1 - components/compiler/streamerrorhandler.hpp | 1 - components/compiler/stringparser.cpp | 1 - components/esm/cellid.cpp | 1 - components/esm/cellref.cpp | 1 - components/esm/cellstate.cpp | 1 - components/esm/containerstate.cpp | 1 - components/esm/creaturestate.cpp | 1 - components/esm/debugprofile.cpp | 1 - components/esm/dialoguestate.cpp | 1 - components/esm/filter.cpp | 1 - components/esm/globalscript.cpp | 1 - components/esm/inventorystate.cpp | 1 - components/esm/journalentry.cpp | 1 - components/esm/loadtes3.cpp | 1 - components/esm/locals.cpp | 1 - components/esm/npcstate.cpp | 1 - components/esm/objectstate.cpp | 1 - components/esm/player.cpp | 1 - components/esm/queststate.cpp | 1 - components/esm/savedgame.cpp | 1 - components/esm/variantimp.cpp | 1 - components/files/multidircollection.cpp | 1 - components/interpreter/installopcodes.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/interpreter/runtime.cpp | 1 - files/mygui/CMakeLists.txt | 1 - 229 files changed, 229 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf2..e4c65907e6 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index fd7370a40f..de2e6e83e1 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 0837264124..b1d402c699 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -1,4 +1,3 @@ - #include "blacklist.hpp" #include diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159b..3a31e86872 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -1,4 +1,3 @@ - #include "documentmanager.hpp" #include diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 33725a6f94..cb3ff2cd0f 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index c8d26d39bb..86e96a88d6 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,4 +1,3 @@ - #include "messages.hpp" CSMDoc::Message::Message() {} diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 8b27170868..cb9b7ec295 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -1,4 +1,3 @@ - #include "operation.hpp" #include diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index 25fc6fc263..db0d1a9a4b 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,4 +1,3 @@ - #include "operationholder.hpp" #include "../settings/usersettings.hpp" diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 14fe0cda8f..5a0bc39be5 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -1,4 +1,3 @@ - #include "runner.hpp" #include diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 9f6e469b8f..25372f1a6e 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -1,4 +1,3 @@ - #include "saving.hpp" #include "../world/data.hpp" diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd6..ef3b23ec88 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -1,4 +1,3 @@ - #include "savingstages.hpp" #include diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index e7ad551b27..10539c1b55 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -1,4 +1,3 @@ - #include "savingstate.hpp" #include "operation.hpp" diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 78aa145742..c8da860693 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,3 @@ - #include "stage.hpp" CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/andnode.cpp b/apps/opencs/model/filter/andnode.cpp index 4249fc228e..9086627991 100644 --- a/apps/opencs/model/filter/andnode.cpp +++ b/apps/opencs/model/filter/andnode.cpp @@ -1,4 +1,3 @@ - #include "andnode.hpp" #include diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 35fc98e085..ee7ddc1c05 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -1,4 +1,3 @@ - #include "booleannode.hpp" CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp index 055a1747cc..6745e165ec 100644 --- a/apps/opencs/model/filter/leafnode.cpp +++ b/apps/opencs/model/filter/leafnode.cpp @@ -1,4 +1,3 @@ - #include "leafnode.hpp" std::vector CSMFilter::LeafNode::getReferencedColumns() const diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index 98f706c875..f2e0e5cb2c 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -1,4 +1,3 @@ - #include "narynode.hpp" #include diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 091dc46988..e25610675e 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -1,4 +1,3 @@ - #include "node.hpp" CSMFilter::Node::Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index b5d9da7b7d..ba5302bbee 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -1,4 +1,3 @@ - #include "notnode.hpp" CSMFilter::NotNode::NotNode (boost::shared_ptr child) : UnaryNode (child, "not") {} diff --git a/apps/opencs/model/filter/ornode.cpp b/apps/opencs/model/filter/ornode.cpp index c5d15a3846..41ec7b5cf3 100644 --- a/apps/opencs/model/filter/ornode.cpp +++ b/apps/opencs/model/filter/ornode.cpp @@ -1,4 +1,3 @@ - #include "ornode.hpp" #include diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 51338dfc98..7936a1ae2b 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 73c378f113..246ebae249 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -1,4 +1,3 @@ - #include "textnode.hpp" #include diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index c40d191b62..cbdadf6fc1 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -1,4 +1,3 @@ - #include "unarynode.hpp" CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child, const std::string& name) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 6fdb5cb021..85c5a8e27f 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -1,4 +1,3 @@ - #include "valuenode.hpp" #include diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 4e6da4631f..9898352f10 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -1,4 +1,3 @@ - #include "birthsigncheck.hpp" #include diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index be57a37290..e4964d4e34 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -1,4 +1,3 @@ - #include "classcheck.hpp" #include diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 0dfdee7754..621b28070f 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -1,4 +1,3 @@ - #include "factioncheck.hpp" #include diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 4c97d22665..23adb9d376 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -1,4 +1,3 @@ - #include "mandatoryid.hpp" #include "../world/collectionbase.hpp" diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 3b2c8d290e..b300886208 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -1,4 +1,3 @@ - #include "racecheck.hpp" #include diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 42abc35c93..2fdff5f388 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -1,4 +1,3 @@ - #include "regioncheck.hpp" #include diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 4bf7d1581d..77a14de841 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -1,4 +1,3 @@ - #include "reportmodel.hpp" #include diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 665edd7a33..d7c41cfcf3 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -1,4 +1,3 @@ - #include "scriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 449df2c638..0409199afe 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -1,4 +1,3 @@ - #include "search.hpp" #include diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 8cbc5dc8e6..8fba1cc1ef 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -1,4 +1,3 @@ - #include "searchoperation.hpp" #include "../doc/state.hpp" diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp index 17859d9309..3db10b0c37 100644 --- a/apps/opencs/model/tools/searchstage.cpp +++ b/apps/opencs/model/tools/searchstage.cpp @@ -1,4 +1,3 @@ - #include "searchstage.hpp" #include "../world/idtablebase.hpp" diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index 2b55526e09..77ba8d4a21 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -1,4 +1,3 @@ - #include "skillcheck.hpp" #include diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index f78932a32b..6a059bee22 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -1,4 +1,3 @@ - #include "soundcheck.hpp" #include diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index bd076d2a5a..91aed37edf 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -1,4 +1,3 @@ - #include "spellcheck.hpp" #include diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp index e3c01368bd..2207517971 100644 --- a/apps/opencs/model/tools/startscriptcheck.cpp +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -1,4 +1,3 @@ - #include "startscriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 97943b1fb7..0c6e36a61f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -1,4 +1,3 @@ - #include "tools.hpp" #include diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 40520a9ba7..91becdb74e 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index b1c8441e63..95e206e2d3 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -1,4 +1,3 @@ - #include "cellcoordinates.hpp" #include diff --git a/apps/opencs/model/world/cellselection.cpp b/apps/opencs/model/world/cellselection.cpp index 73b5196f13..c6988e4880 100644 --- a/apps/opencs/model/world/cellselection.cpp +++ b/apps/opencs/model/world/cellselection.cpp @@ -1,4 +1,3 @@ - #include "cellselection.hpp" #include diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index b8eed4192d..6134dc1727 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -1,4 +1,3 @@ - #include "collectionbase.hpp" #include diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 177fb59ce4..1fcf0ae41f 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -1,4 +1,3 @@ - #include "columns.hpp" #include diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index b9d5bd7fec..0b1af0e840 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -1,4 +1,3 @@ - #include "commanddispatcher.hpp" #include diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 25a04715d5..12ff1a38cc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1,4 +1,3 @@ - #include "data.hpp" #include diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 389f5396e4..274446b796 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -1,4 +1,3 @@ - #include "idtablebase.hpp" CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features) {} diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 7572854121..fbf7b6cf36 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -1,4 +1,3 @@ - #include "idtableproxymodel.hpp" #include diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 560be8131e..60c6130416 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -1,4 +1,3 @@ - #include "infocollection.hpp" #include diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp index 40b8e95197..960fdc9e4e 100644 --- a/apps/opencs/model/world/metadata.cpp +++ b/apps/opencs/model/world/metadata.cpp @@ -1,4 +1,3 @@ - #include "metadata.hpp" #include diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index ef2f4d3202..f13a36afc0 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -1,4 +1,3 @@ - #include "record.hpp" CSMWorld::RecordBase::~RecordBase() {} diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 13706c950c..638f7ec9ca 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,4 +1,3 @@ - #include "ref.hpp" #include diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index ff30dafae6..f8818807bc 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -1,4 +1,3 @@ - #include "refcollection.hpp" #include diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f368..c391201e6d 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -1,4 +1,3 @@ - #include "refiddata.hpp" #include diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 42bde9c81a..10c67c909d 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 4dd480e773..b31e211eec 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -1,4 +1,3 @@ - #include "resources.hpp" #include diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 3e2f72d93d..2ec661cb1a 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -1,4 +1,3 @@ - #include "resourcesmanager.hpp" #include diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 2cd44781ab..5227ec3e63 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -1,4 +1,3 @@ - #include "resourcetable.hpp" #include diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index 6e4ce4c027..b026c34c32 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -1,4 +1,3 @@ - #include "scope.hpp" #include diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index a8c2c94526..bcbca4b28d 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -1,4 +1,3 @@ - #include "scriptcontext.hpp" #include diff --git a/apps/opencs/model/world/tablemimedata.hpp b/apps/opencs/model/world/tablemimedata.hpp index 06d252435f..a42e975618 100644 --- a/apps/opencs/model/world/tablemimedata.hpp +++ b/apps/opencs/model/world/tablemimedata.hpp @@ -1,4 +1,3 @@ - #ifndef TABLEMIMEDATA_H #define TABLEMIMEDATA_H diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 73d893a260..77db2be108 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -1,4 +1,3 @@ - #include "universalid.hpp" #include diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c81..ba5dd90f83 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,4 +1,3 @@ - #include "adjusterwidget.hpp" #include diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a0..bbb824823a 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -1,4 +1,3 @@ - #include "filewidget.hpp" #include diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index b883813859..f0d9655dd0 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -1,4 +1,3 @@ - #include "globaldebugprofilemenu.hpp" #include diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 30235d0f5c..713295d702 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index 32b4837285..b3e2a4f637 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -1,4 +1,3 @@ - #include "newgame.hpp" #include diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 1293969996..2b7182228b 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -1,4 +1,3 @@ - #include "runlogsubview.hpp" #include diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 58a46c603b..a9d697f1c2 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -1,4 +1,3 @@ - #include "startup.hpp" #include diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 3137f7e324..82a8aeb054 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -1,4 +1,3 @@ - #include "subviewfactory.hpp" #include diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7914d2d8c3..7c9686277f 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,4 +1,3 @@ - #include "viewmanager.hpp" #include diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index bc7f9b5a16..657a47750d 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -1,4 +1,3 @@ - #include "editwidget.hpp" #include diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index 7a42ef0a57..c6c6cc6ccc 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -1,4 +1,3 @@ - #include "filterbox.hpp" #include diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index 97490d5083..2bf589215e 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -1,4 +1,3 @@ - #include "recordfilterbox.hpp" #include diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab0666..77bcff4fdb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 9361030a30..8a99ba0490 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -1,4 +1,3 @@ - #include "editmode.hpp" #include "worldspacewidget.hpp" diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 00c4fb8151..07900d6b04 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -1,4 +1,3 @@ - #include "lightingbright.hpp" #include diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 2b53483ada..274c776201 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "pagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f512a8bb6c..a03b277d30 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -1,4 +1,3 @@ - #include "previewwidget.hpp" #include diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8e6e72cba5..a5733ad102 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "unpagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 39ce09f315..d45fc45a80 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "worldspacewidget.hpp" #include diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index e29447f250..a7316359e5 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -1,4 +1,3 @@ - #include "reportsubview.hpp" #include "reporttable.hpp" diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 550c53969e..d4cecc9719 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -1,4 +1,3 @@ - #include "reporttable.hpp" #include diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1307c1aab1..d980447603 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -1,4 +1,3 @@ - #include "searchbox.hpp" #include diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 8b35db6aed..d3fdbbf5da 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,4 +1,3 @@ - #include "searchsubview.hpp" #include diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8a343ebe86..8c3d6d50ea 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/widget/modebutton.cpp b/apps/opencs/view/widget/modebutton.cpp index 56896b4220..7c62f6bb16 100644 --- a/apps/opencs/view/widget/modebutton.cpp +++ b/apps/opencs/view/widget/modebutton.cpp @@ -1,4 +1,3 @@ - #include "modebutton.hpp" CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QWidget *parent) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 1baeb7ca27..424aaf68a0 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -1,4 +1,3 @@ - #include "pushbutton.hpp" #include diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index b8e9f895f4..796b985678 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -1,4 +1,3 @@ - #include "scenetool.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index f7023b31f3..b2e988dc9a 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -1,4 +1,3 @@ - #include "scenetoolbar.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 39e051c485..9f963873c8 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -1,4 +1,3 @@ - #include "scenetoolmode.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 4c9eb676e8..1e2d44e7a1 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -1,4 +1,3 @@ - #include "scenetoolrun.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle.cpp b/apps/opencs/view/widget/scenetooltoggle.cpp index 07c448e453..d7251882a7 100644 --- a/apps/opencs/view/widget/scenetooltoggle.cpp +++ b/apps/opencs/view/widget/scenetooltoggle.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index 313e519cb4..e0431476eb 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle2.hpp" #include diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index c7d909f4cf..2a710a9400 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -1,4 +1,3 @@ - #include "cellcreator.hpp" #include diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index 7a8c8d48f0..7a93339c5b 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -1,4 +1,3 @@ - #include "creator.hpp" #include diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3d451ed2dd..7c6fb2e81f 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -1,4 +1,3 @@ - #include "dialoguecreator.hpp" #include diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 2190a62c69..e582e3356d 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,4 +1,3 @@ - #include "enumdelegate.hpp" #include diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 5f04d9a7a8..8ed52bf803 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -1,4 +1,3 @@ - #include "genericcreator.hpp" #include diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 13b05d2d17..1092d72171 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -1,4 +1,3 @@ - #include "idvalidator.hpp" #include diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 268a82a280..1139afd691 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -1,4 +1,3 @@ - #include "infocreator.hpp" #include diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 756e79fe6f..f3312bb208 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -1,4 +1,3 @@ - #include "previewsubview.hpp" #include diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 9cae0d0c9d..1a838a3b31 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -1,4 +1,3 @@ - #include "recordbuttonbar.hpp" #include diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index e8055ed317..1357ca46f0 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -1,4 +1,3 @@ - #include "referenceablecreator.hpp" #include diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 2b0d44df0c..73ca62e025 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -1,4 +1,3 @@ - #include "referencecreator.hpp" #include diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index bc96b0952a..49764bd178 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index 411e24e754..996d1dc8b8 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -1,4 +1,3 @@ - #include "regionmapsubview.hpp" #include "regionmap.hpp" diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b7a795e230..2ca2548c0c 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -1,4 +1,3 @@ - #include "scenesubview.hpp" #include diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 415e6c9dca..b44e1c0bde 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -1,4 +1,3 @@ - #include "scripterrortable.hpp" #include diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 4923a44d89..487b5b1395 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -1,4 +1,3 @@ - #include "scripthighlighter.hpp" #include diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b8a6ba4298..299ac6ebec 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 41c33761e7..72e0c82d03 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -1,4 +1,3 @@ - #include "table.hpp" #include diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 7e66106fc0..eed522227e 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -1,4 +1,3 @@ - #include "tablebottombox.hpp" #include diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 5fd0945060..81b2699934 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -1,4 +1,3 @@ - #include "tablesubview.hpp" #include diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f216585811..2654644c49 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,4 +1,3 @@ - #include "util.hpp" #include diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 90a686a67e..a63e6028c2 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -1,4 +1,3 @@ - #include "vartypedelegate.hpp" #include diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h index 21d1064c6c..5ca79c2d0f 100644 --- a/apps/openmw/android_commandLine.h +++ b/apps/openmw/android_commandLine.h @@ -1,5 +1,4 @@ - /* DO NOT EDIT THIS FILE - it is machine generated */ #include #ifndef _Included_ui_activity_GameActivity_commandLine diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index a90eec5bf6..4efa7c2737 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -1,4 +1,3 @@ - #include "environment.hpp" #include diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 4cf33ceb85..3a0f1b951b 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -1,4 +1,3 @@ - #include "activator.hpp" #include diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6f11a36c79..f93556ef90 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -1,4 +1,3 @@ - #include "apparatus.hpp" #include diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 04c98e437f..2ba8ba03bc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -1,4 +1,3 @@ - #include "armor.hpp" #include diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index e9538a6cb4..c303b23af0 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -1,4 +1,3 @@ - #include "classes.hpp" #include "activator.hpp" diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8964b65e04..cea30d561f 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -1,4 +1,3 @@ - #include "clothing.hpp" #include diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 8304936279..f785797c10 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -1,4 +1,3 @@ - #include "container.hpp" #include diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8b7bcf6b92..60874bb5e9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,4 +1,3 @@ - #include "creature.hpp" #include diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index dbc4b6af7b..433e5fcea6 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -1,4 +1,3 @@ - #include "creaturelevlist.hpp" #include diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5062cc5572..6749afa6bc 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -1,4 +1,3 @@ - #include "door.hpp" #include diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index fb409cb55b..c9e6e70f21 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -1,4 +1,3 @@ - #include "ingredient.hpp" #include diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index d31080bb2c..a70f311159 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -1,4 +1,3 @@ - #include "itemlevlist.hpp" #include diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 1e882b5688..c532b5d65d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -1,4 +1,3 @@ - #include "light.hpp" #include diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 8f22c3fa13..5cffdf13a7 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,4 +1,3 @@ - #include "lockpick.hpp" #include diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 0c80209f29..98b4faab9b 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,4 +1,3 @@ - #include "misc.hpp" #include diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 75b612dade..e2b714a64f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1,4 +1,3 @@ - #include "npc.hpp" #include diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 647f83f676..cf6b0919b3 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -1,4 +1,3 @@ - #include "potion.hpp" #include diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index cb43ccce6a..ff717c5062 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,4 +1,3 @@ - #include "probe.hpp" #include diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 0bc64a99e1..e6baea2e0d 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,4 +1,3 @@ - #include "repair.hpp" #include diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 6438046ded..9755df28e5 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,4 +1,3 @@ - #include "static.hpp" #include diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8c3d7fb10e..da4c7deb22 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -1,4 +1,3 @@ - #include "weapon.hpp" #include diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 042267ebeb..35f205eb8d 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "dialoguemanagerimp.hpp" #include diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 29fac1c673..5e6b83b507 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 9f07f7b6fc..2f5f02b01f 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 99dab0cf8b..e6ffe22ab2 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,4 +1,3 @@ - #include "journalimp.hpp" #include diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index a9e39b3798..8465978863 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -1,4 +1,3 @@ - #include "quest.hpp" #include diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index fa0fbfe136..a4eba30ae4 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -1,4 +1,3 @@ - #include "selectwrapper.hpp" #include diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index c1a45f841c..eb7fbdc1de 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -1,4 +1,3 @@ - #include "topic.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index b2f172076f..384bccfea5 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -1,4 +1,3 @@ - #ifndef MWGUI_TOOLTIPS_H #define MWGUI_TOOLTIPS_H diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index dd25e5a555..38d85a7cd3 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,4 +1,3 @@ - #include "alchemy.hpp" #include diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 0b19df0a82..021691d6a9 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,4 +1,3 @@ - #include "magiceffects.hpp" #include diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aa8b301c..10d603ff14 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -1,4 +1,3 @@ - #include "npcstats.hpp" #include diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index fe0f892db1..6d7673a591 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,4 +1,3 @@ - #include "spells.hpp" #include diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 4a7952c446..78c84141a6 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -1,4 +1,3 @@ - #include "aiextensions.hpp" #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index c43cdf5650..07a8a300af 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -1,4 +1,3 @@ - #include "animationextensions.hpp" #include diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 3ff75eeae8..083f463bc3 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,4 +1,3 @@ - #include "compilercontext.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp index 30956d429f..d2e07d3e14 100644 --- a/apps/openmw/mwscript/consoleextensions.cpp +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -1,4 +1,3 @@ - #include "consoleextensions.hpp" #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ba18d8e37c..6749739780 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -1,4 +1,3 @@ - #include "containerextensions.hpp" #include diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 904e0ee850..626fafb5a4 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -1,4 +1,3 @@ - #include "controlextensions.hpp" #include diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 8b68052647..c305fb81fc 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -1,4 +1,3 @@ - #include "dialogueextensions.hpp" #include diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 2170ba4fb3..12bf3413a0 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 44d96e949c..f339fa5200 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,4 +1,3 @@ - #include "globalscripts.hpp" #include diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 40c555f503..f48360c047 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,4 +1,3 @@ - #include "guiextensions.hpp" #include diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index df675aebbd..b0d4d3f2df 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -1,4 +1,3 @@ - #include "interpretercontext.hpp" #include diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9a9127977a..faf5749934 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1,4 +1,3 @@ - #include "miscextensions.hpp" #include diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 5f755e5424..084beb8121 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -1,4 +1,3 @@ - #include "scriptmanagerimp.hpp" #include diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index d28d01b638..e0fccd16d2 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -1,4 +1,3 @@ - #include "skyextensions.hpp" #include diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 606de7aa01..a9896d203b 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/userextensions.cpp b/apps/openmw/mwscript/userextensions.cpp index 538133c65d..165a93062f 100644 --- a/apps/openmw/mwscript/userextensions.cpp +++ b/apps/openmw/mwscript/userextensions.cpp @@ -1,4 +1,3 @@ - #include "userextensions.hpp" #include diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index fcd1ca19e9..733ac1171c 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,4 +1,3 @@ - #include "character.hpp" #include diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 70e9f09258..22192c355d 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -1,4 +1,3 @@ - #include "charactermanager.hpp" #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index ac8dc863a1..f4a7ee9f23 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "statemanagerimp.hpp" #include diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 5e1fb41a6c..fb2059de92 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -1,4 +1,3 @@ - #include "action.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index bfd64c85d8..00c9628cec 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -1,4 +1,3 @@ - #include "actionapply.hpp" #include "class.hpp" diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 8bb80b564b..d9ca4aaf58 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,4 +1,3 @@ - #include "actioneat.hpp" #include diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 8578995aee..454cc09f11 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -1,4 +1,3 @@ - #ifndef GAME_MWWORLD_ACTIONOPEN_H #define GAME_MWWORLD_ACTIONOPEN_H diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 269d941dc6..4e61357642 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -1,4 +1,3 @@ - #include "actiontake.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 905497f85b..051380ff52 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,4 +1,3 @@ - #include "actiontalk.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 18200e33b4..4c73c603bc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -1,4 +1,3 @@ - #include "class.hpp" #include diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3a7c023327..05ae4f134e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -1,4 +1,3 @@ - #include "containerstore.hpp" #include diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index e7cb04590b..dcd7924a22 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -1,4 +1,3 @@ - #include "globals.hpp" #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2fe914a4e1..2dbc222349 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -1,4 +1,3 @@ - #include "inventorystore.hpp" #include diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 1cf22744a8..4d74c3c581 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -1,4 +1,3 @@ - #include "ptr.hpp" #include diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c4f63137a7..2062e78d90 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,4 +1,3 @@ - #include "refdata.hpp" #include diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index aefe6d16da..b202467db8 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -1,4 +1,3 @@ - #include "controlparser.hpp" #include diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 7961b8f411..ffac252d54 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -1,4 +1,3 @@ - #include "declarationparser.hpp" #include diff --git a/components/compiler/discardparser.cpp b/components/compiler/discardparser.cpp index 6028968bb2..da114fb3dd 100644 --- a/components/compiler/discardparser.cpp +++ b/components/compiler/discardparser.cpp @@ -1,4 +1,3 @@ - #include "discardparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index bcd30ef2d5..a987a86da2 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -1,4 +1,3 @@ - #include "errorhandler.hpp" namespace Compiler diff --git a/components/compiler/errorhandler.hpp b/components/compiler/errorhandler.hpp index c92e7bb8d9..ea904e3851 100644 --- a/components/compiler/errorhandler.hpp +++ b/components/compiler/errorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_ERRORHANDLER_H_INCLUDED #define COMPILER_ERRORHANDLER_H_INCLUDED diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 1818d04df2..b588b6196b 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -1,4 +1,3 @@ - #include "exprparser.hpp" #include diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index c2b11c6156..dbb953e201 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index ead0c72901..7e6437e20a 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -1,4 +1,3 @@ - #include "generator.hpp" #include diff --git a/components/compiler/junkparser.cpp b/components/compiler/junkparser.cpp index cfa94044e7..7608e9bab4 100644 --- a/components/compiler/junkparser.cpp +++ b/components/compiler/junkparser.cpp @@ -1,4 +1,3 @@ - #include "junkparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 4d6e147fc4..032af7d650 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,4 +1,3 @@ - #include "lineparser.hpp" #include diff --git a/components/compiler/literals.cpp b/components/compiler/literals.cpp index 626b03afbe..ee2c4d3450 100644 --- a/components/compiler/literals.cpp +++ b/components/compiler/literals.cpp @@ -1,4 +1,3 @@ - #include "literals.hpp" #include diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 60a5704bf3..768fc077ca 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index ee28847059..a0db53a002 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "nullerrorhandler.hpp" void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp index bb4db99a28..3dcff92508 100644 --- a/components/compiler/nullerrorhandler.hpp +++ b/components/compiler/nullerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED #define COMPILER_NULLERRORHANDLER_H_INCLUDED diff --git a/components/compiler/output.cpp b/components/compiler/output.cpp index 46e04b8dc5..785b2ce843 100644 --- a/components/compiler/output.cpp +++ b/components/compiler/output.cpp @@ -1,4 +1,3 @@ - #include "output.hpp" #include diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 0f442c3504..fe019718a6 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 4e9f76e13c..53aaf96e5d 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -1,4 +1,3 @@ - #include "quickfileparser.hpp" #include "skipparser.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index de7f7e1e16..5af396d275 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -1,4 +1,3 @@ - #include "scanner.hpp" #include diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ea11be5f03..a3bf232888 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -1,4 +1,3 @@ - #include "scriptparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/skipparser.cpp b/components/compiler/skipparser.cpp index c7cb31f58e..3e704253dd 100644 --- a/components/compiler/skipparser.cpp +++ b/components/compiler/skipparser.cpp @@ -1,4 +1,3 @@ - #include "skipparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index fc1a059432..9ca8aa74bf 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "streamerrorhandler.hpp" #include "tokenloc.hpp" diff --git a/components/compiler/streamerrorhandler.hpp b/components/compiler/streamerrorhandler.hpp index 96e02b5882..85de1833ab 100644 --- a/components/compiler/streamerrorhandler.hpp +++ b/components/compiler/streamerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_STREAMERRORHANDLER_H_INCLUDED #define COMPILER_STREAMERRORHANDLER_H_INCLUDED diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 7a2098fb36..f8798eccd4 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -1,4 +1,3 @@ - #include "stringparser.hpp" #include diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index c77b27b227..f77e2eb551 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -1,4 +1,3 @@ - #include "cellid.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c3b889df59..33ac4a91e8 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -1,4 +1,3 @@ - #include "cellref.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellstate.cpp b/components/esm/cellstate.cpp index 4df04d0e52..83b130dcd9 100644 --- a/components/esm/cellstate.cpp +++ b/components/esm/cellstate.cpp @@ -1,4 +1,3 @@ - #include "cellstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 80ad5cbdc8..301549d597 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -1,4 +1,3 @@ - #include "containerstate.hpp" void ESM::ContainerState::load (ESMReader &esm) diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index c15becd981..bffa4e5e45 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -1,4 +1,3 @@ - #include "creaturestate.hpp" void ESM::CreatureState::load (ESMReader &esm) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 6c05fac2a2..9d605a6af9 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -1,4 +1,3 @@ - #include "debugprofile.hpp" #include "esmreader.hpp" diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f302e36dc8..2b1887e4eb 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -1,4 +1,3 @@ - #include "dialoguestate.hpp" #include "esmreader.hpp" diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index a80427bbed..5bc768f725 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include "esmreader.hpp" diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 0129f8eb7d..a42cdc2309 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -1,4 +1,3 @@ - #include "globalscript.hpp" #include "esmreader.hpp" diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 4eaaa9f9f1..e7257ae537 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -1,4 +1,3 @@ - #include "inventorystate.hpp" #include "esmreader.hpp" diff --git a/components/esm/journalentry.cpp b/components/esm/journalentry.cpp index 445213de40..93011e581b 100644 --- a/components/esm/journalentry.cpp +++ b/components/esm/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include "esmreader.hpp" diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 7d749c4d95..df35a2579d 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -1,4 +1,3 @@ - #include "loadtes3.hpp" #include "esmcommon.hpp" diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index f0cfd49f03..bd51be08f6 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include "esmreader.hpp" diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index 724d673265..6c9988d50d 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -1,4 +1,3 @@ - #include "npcstate.hpp" void ESM::NpcState::load (ESMReader &esm) diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 0ae690ee8a..62aa0452a8 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -1,4 +1,3 @@ - #include "objectstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/player.cpp b/components/esm/player.cpp index e64cefc304..9ec53240a2 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -1,4 +1,3 @@ - #include "player.hpp" #include "esmreader.hpp" diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index c8cff7adc9..5408cd2ffd 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -1,4 +1,3 @@ - #include "queststate.hpp" #include "esmreader.hpp" diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 9cdb28766a..2e5509b7a5 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -1,4 +1,3 @@ - #include "savedgame.hpp" #include "esmreader.hpp" diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index eeb0bf04f3..aeea5017e1 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -1,4 +1,3 @@ - #include "variantimp.hpp" #include diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 1abbae3ae8..7b3b0c440c 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -1,4 +1,3 @@ - #include "multidircollection.hpp" #include diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index d705a109c7..31e911f8ba 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -1,4 +1,3 @@ - #include "installopcodes.hpp" #include diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index f5dee0dba3..263cea9a53 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -1,4 +1,3 @@ - #include "interpreter.hpp" #include diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dc3da07a8d..6599882f12 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -1,4 +1,3 @@ - #include "runtime.hpp" #include diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 6023977437..dc9e8ea848 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -1,4 +1,3 @@ - # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) From 681183df31a1b695b119a6ab6049a4083b796aaf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:13:14 +0200 Subject: [PATCH 0951/1812] Restore handling of fog depth == 0 values (Bug #1549) --- apps/openmw/mwrender/renderingmanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b01095f122..bac8fca6cb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -379,8 +379,17 @@ namespace MWRender else { setFogColor(mFogColor); - mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); - mStateUpdater->setFogEnd(mViewDistance); + + if (mFogDepth == 0.f) + { + mStateUpdater->setFogStart(0.f); + mStateUpdater->setFogEnd(FLT_MAX); + } + else + { + mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); + mStateUpdater->setFogEnd(mViewDistance); + } } } From 232dfdc07e978a690d0320915684af403ce9b7d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:24:54 +0200 Subject: [PATCH 0952/1812] Make an error message slightly more helpful --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 83931ba151..9efb866d46 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1255,7 +1255,7 @@ namespace MWMechanics } else { - std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index a0e9cd242b..94b552a38f 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -88,7 +88,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro } else { - std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } From e1baf1ea48526c8b5e5d1ffe005573ca3b70676f Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 09:51:04 -0400 Subject: [PATCH 0953/1812] NPCs scream when they die --- apps/openmw/mwmechanics/actors.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d46..f6ad5906b2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -18,6 +18,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1175,6 +1176,12 @@ namespace MWMechanics if (iter->second->getCharacterController()->kill()) { + // TODO: It's not known whether the soundgen tags scream, roar, and moan are reliable + // for NPCs since some of the npc death animation files are missing them. + + // Play dying words + MWBase::Environment::get().getDialogueManager()->say(iter->first, "hit"); + iter->first.getClass().getCreatureStats(iter->first).notifyDied(); ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; From e86891d6e16508229732dfb55dd9bae27780ceb7 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:05:08 -0400 Subject: [PATCH 0954/1812] Time played displayed in save/load menus --- apps/openmw/mwgui/savegamedialog.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 82dd0d8a9f..4559fc6951 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,8 @@ #include "savegamedialog.hpp" +#include +#include + #include #include #include @@ -309,6 +312,21 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } + std::string formatTimeplayed(const long int timePlayed) + { + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; + + std::stringstream stream; + stream << std::setfill('0') << std::setw(2) << days << ":"; + stream << std::setfill('0') << std::setw(2) << hours << ":"; + stream << std::setfill('0') << std::setw(2) << minutes << ":"; + stream << std::setfill('0') << std::setw(2) << seconds; + return stream.str(); + } + void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) { mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving); @@ -349,7 +367,6 @@ namespace MWGui text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; - // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); bool pm = hour >= 12; @@ -359,7 +376,9 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + + text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); mInfoText->setCaptionWithReplacing(text.str()); From 69729046bf669235e69f0de7b750358da1b9f769 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:11:40 -0400 Subject: [PATCH 0955/1812] Updated parameter name to reflect units --- apps/openmw/mwgui/savegamedialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4559fc6951..83b458a2b3 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -312,12 +312,12 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timePlayed) + std::string formatTimeplayed(const long int timeInSeconds) { - int days = timePlayed / 60 / 60 / 24; - int hours = (timePlayed / 60 / 60) % 24; - int minutes = (timePlayed / 60) % 60; - int seconds = timePlayed % 60; + int days = timeInSeconds / 60 / 60 / 24; + int hours = (timeInSeconds / 60 / 60) % 24; + int minutes = (timeInSeconds / 60) % 60; + int seconds = timeInSeconds % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; From d91f197119ac6cfb1ed6002c48ff1c50f83674c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 11:31:43 -0400 Subject: [PATCH 0956/1812] Time played display setting --- apps/openmw/mwgui/savegamedialog.cpp | 7 +++++-- files/settings-default.cfg | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 83b458a2b3..0375bfda30 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -376,9 +376,12 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); - text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + if (Settings::Manager::getBool("timeplayed","Saves")) + { + text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + } mInfoText->setCaptionWithReplacing(text.str()); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0f7349eb9f..f2b6aa34f7 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -177,6 +177,8 @@ show owned = 0 character = # Save when resting autosave = true +# display time played +timeplayed = false [Windows] inventory x = 0 From 4a68ceaeb7561f6d00cd25d80b075956c8f6fd39 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 19:06:24 +0200 Subject: [PATCH 0957/1812] Restrict the OS X cursor workaround to Intel graphics systems --- components/sdlutil/sdlcursormanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 70a1593066..b64b68132a 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -127,11 +127,13 @@ namespace glViewport(0, 0, width, height); #if defined(__APPLE__) - // FIXME: why are the extra flips needed on Mac? glReadPixels bug? - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); -#else - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + // Extra flip needed on Intel graphics OS X systems due to a driver bug + std::string vendorString = (const char*)glGetString(GL_VENDOR); + if (vendorString.find("Intel") != std::string::npos) + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + else #endif + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From 61bb55aff40d9efb594ced44799b7bda98d2ca23 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:23:40 -0400 Subject: [PATCH 0958/1812] Removed long int parameter --- apps/openmw/mwgui/savegamedialog.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0375bfda30..3d509e9fd5 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,6 @@ #include "savegamedialog.hpp" +#include #include #include @@ -312,12 +313,13 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timeInSeconds) + std::string formatTimeplayed(const double timeInSeconds) { - int days = timeInSeconds / 60 / 60 / 24; - int hours = (timeInSeconds / 60 / 60) % 24; - int minutes = (timeInSeconds / 60) % 60; - int seconds = timeInSeconds % 60; + int timePlayed = (int)floor(timeInSeconds); + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; @@ -380,7 +382,7 @@ namespace MWGui if (Settings::Manager::getBool("timeplayed","Saves")) { - text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + text << "\n" << "Time played: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed); } mInfoText->setCaptionWithReplacing(text.str()); From f94d3237fcb9bae1a51e8f442029b2d4496060cb Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:28:01 -0400 Subject: [PATCH 0959/1812] Removed unused cmake import --- apps/openmw/mwgui/savegamedialog.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3d509e9fd5..be9ef21395 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,6 +1,5 @@ #include "savegamedialog.hpp" -#include #include #include From 166df28906dcfa1e7758d9e97e5e4e0b6de781f7 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 19 Aug 2015 21:23:16 +0200 Subject: [PATCH 0960/1812] OS X cursor workaround build fix --- components/sdlutil/sdlcursormanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b64b68132a..e1a67aff81 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,14 +126,16 @@ namespace glViewport(0, 0, width, height); + osg::ref_ptr geom; + #if defined(__APPLE__) // Extra flip needed on Intel graphics OS X systems due to a driver bug std::string vendorString = (const char*)glGetString(GL_VENDOR); if (vendorString.find("Intel") != std::string::npos) - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); else #endif - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From ff5ef7055e843797a65d5174b9cd8f14d389ef4f Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:12:37 +1200 Subject: [PATCH 0961/1812] extracted function CreatureStats::isParalyzed() --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 5 ++--- apps/openmw/mwmechanics/combat.cpp | 6 +++--- apps/openmw/mwmechanics/creaturestats.cpp | 5 +++++ apps/openmw/mwmechanics/creaturestats.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++--- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75fd..6b393ebcbc 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -704,8 +704,8 @@ void OMW::Engine::activate() return; MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); - if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 - || player.getClass().getCreatureStats(player).getKnockedDown()) + const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); + if (playerStats.isParalyzed() || playerStats.getKnockedDown()) return; MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d46..2abd94eb3f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1037,8 +1037,7 @@ namespace MWMechanics > sqrProcessingDistance) continue; - if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( - ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); // Handle player last, in case a cell transition occurs by casting a teleportation spell @@ -1426,7 +1425,7 @@ namespace MWMechanics MWWorld::Ptr ptr = it->first; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || !isConscious(ptr) - || ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); seq.fastForward(ptr, it->second->getAiState()); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 097dcadc27..11619e4c32 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -60,7 +60,7 @@ namespace MWMechanics if (blockerStats.getKnockedDown() // Used for both knockout or knockdown || blockerStats.getHitRecovery() - || blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || blockerStats.isParalyzed()) return false; if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker)) @@ -250,7 +250,7 @@ namespace MWMechanics && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || - victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + victimStats.isParalyzed() || unaware )) { defenseTerm = victimStats.getEvasion(); @@ -375,7 +375,7 @@ namespace MWMechanics damage *= minstrike + ((maxstrike-minstrike)*attackStrength); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); - healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown(); bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf()); if(isWerewolf) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 48374c173c..0638637fa5 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -221,6 +221,11 @@ namespace MWMechanics setAiSetting(index, stat); } + bool CreatureStats::isParalyzed() const + { + return mMagicEffects.get(ESM::MagicEffect::Paralyze).getMagnitude() > 0; + } + bool CreatureStats::isDead() const { return mDead; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 5d22da7cc3..46c5bab31e 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -155,6 +155,8 @@ namespace MWMechanics float getFatigueTerm() const; ///< Return effective fatigue + bool isParalyzed() const; + bool isDead() const; void notifyDied(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bde..4c9074eee9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1927,16 +1927,15 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - bool isParalyzed = (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0); if(!ptr.getClass().isActor()) return false; - if (ptr.getClass().getCreatureStats(ptr).isDead()) + if (stats.isDead()) return false; if (ptr.getClass().canFly(ptr)) - return !isParalyzed; + return !stats.isParalyzed(); if(stats.getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && isLevitationEnabled()) From 0ee7407101aedf4a0fa3910d437842399b7a452a Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:17:02 +1200 Subject: [PATCH 0962/1812] extracted common sub-expressions. --- apps/openmw/mwclass/creature.cpp | 8 +++----- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++-------- apps/openmw/mwmechanics/combat.cpp | 10 +++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 11 ++++++----- apps/openmw/mwmechanics/spellcasting.cpp | 7 ++++--- apps/openmw/mwscript/statsextensions.cpp | 14 +++++++------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 60874bb5e9..5604aa783f 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -603,11 +603,9 @@ namespace MWClass { float weight = getContainerStore (ptr).getWeight(); - const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).getMagnitude(); - - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).getMagnitude(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); + weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); if (weight<0) weight = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2abd94eb3f..584c4c320b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -538,19 +538,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -596,8 +596,8 @@ namespace MWMechanics // TODO: dirty flag for magic effects to avoid some unnecessary work below? // any value of calm > 0 will stop the actor from fighting - if ((creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) - || (creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) + if ((effects.get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) + || (effects.get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) { for (std::list::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ) { @@ -630,7 +630,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = effects.get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 11619e4c32..2e20d0e1f2 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -147,9 +147,9 @@ namespace MWMechanics void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { - MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - float resistance = std::min(100.f, stats.getMagicEffects().get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - stats.getMagicEffects().get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() + - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); float multiplier = 1.f - resistance / 100.f; @@ -242,9 +242,9 @@ namespace MWMechanics const MWWorld::Store &gmst = world->getStore().get(); float defenseTerm = 0; - if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + if (victimStats.getFatigue().getCurrent() >= 0) { - MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9436e35d2d..075747ffef 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1310,11 +1310,12 @@ namespace MWMechanics return false; std::list followers = getActorsFollowing(attacker); + MWMechanics::CreatureStats& targetStats = ptr.getClass().getCreatureStats(ptr); if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) { - ptr.getClass().getCreatureStats(ptr).friendlyHit(); + targetStats.friendlyHit(); - if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) + if (targetStats.getFriendlyHits() < 4) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); return false; @@ -1322,7 +1323,7 @@ namespace MWMechanics } // Attacking an NPC that is already in combat with any other NPC is not a crime - AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + AiSequence& seq = targetStats.getAiSequence(); bool isFightingNpc = false; for (std::list::const_iterator it = seq.begin(); it != seq.end(); ++it) { @@ -1334,13 +1335,13 @@ namespace MWMechanics } } - if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) + if (ptr.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker) && !isAggressive(ptr, attacker) && !isFightingNpc) commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) + && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. // Note: accidental or collateral damage attacks are ignored. diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96f..12ed044282 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -332,9 +332,10 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search (mId); if (spell && (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight)) { - float x = (spell->mData.mType == ESM::Spell::ST_Disease) ? - target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); + int requiredResistance = (spell->mData.mType == ESM::Spell::ST_Disease) ? + ESM::MagicEffect::ResistCommonDisease + : ESM::MagicEffect::ResistBlightDisease; + float x = target.getClass().getCreatureStats(target).getMagicEffects().get(requiredResistance).getMagnitude(); if (Misc::Rng::roll0to99() <= x) { diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 61a31e115d..112e7c77fc 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1159,10 +1159,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int ret = static_cast(currentValue); runtime.push(ret); @@ -1185,14 +1185,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); + effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; From c0d3804b4f3371d4498b771943121a1d249d4c62 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 21:50:58 +1200 Subject: [PATCH 0963/1812] Correctly handle disjoint pathgrid (Fixes #2871) Bugfix: When 1. Cell has multiple subgrids (i.e. path grid is disjoint) 2. Distance between destination and pathgrid point 0 is less than distance to points of subgrid closest to start point Then getClosestReachablePoint() returns pathgrid point 0 as the end point. This is invalid, this end point cannot be reached from the start point. --- apps/openmw/mwmechanics/pathfinding.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 798a0ea21c..9013d32699 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,7 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float distanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceReachable = closestDistanceBetween; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -61,17 +62,25 @@ namespace for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); - if(potentialDistBetween < distanceBetween) + if (potentialDistBetween < closestDistanceReachable) { // found a closer one - distanceBetween = potentialDistBetween; - closestIndex = counter; if (cell->isPointConnected(start, counter)) { + closestDistanceReachable = potentialDistBetween; closestReachableIndex = counter; } + if (potentialDistBetween < closestDistanceBetween) + { + closestDistanceBetween = potentialDistBetween; + closestIndex = counter; + } } } + + // invariant: start and endpoint must be connected + assert(cell->isPointConnected(start, closestReachableIndex)); + // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. From 3b231b85bb1c7ed8c00cf7f1a5a583299e23e3bc Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 06:55:54 +1200 Subject: [PATCH 0964/1812] removed incorrect optimization. Now it fixes #2871 --- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9013d32699..9c9c111060 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,13 +53,13 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); - float closestDistanceReachable = closestDistanceBetween; + float closestDistanceBetween = FLT_MAX; + float closestDistanceReachable = FLT_MAX; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help - for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) + for(unsigned int counter = 0; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); if (potentialDistBetween < closestDistanceReachable) From af3b0cd883f784d111d65b2ed33871ddeb260e18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 00:31:43 +0200 Subject: [PATCH 0965/1812] Improve some error messages --- apps/essimporter/converter.cpp | 2 +- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 4 ++-- apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2ef10ee34b..6267ef91ee 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -143,7 +143,7 @@ namespace ESSImport osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream); if (!result.success()) { - std::cerr << "can't write global map image: " << result.message() << std::endl; + std::cerr << "can't write global map image: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75fd..d0a993b730 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -425,7 +425,7 @@ void OMW::Engine::setWindowIcon() } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) - std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; + std::cerr << "Failed to read " << windowIcon << ": " << result.message() << " code " << result.status() << std::endl; else { osg::ref_ptr image = result.getImage(); @@ -602,7 +602,7 @@ public: osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream); if (!result.success()) { - std::cerr << "Can't write screenshot: " << result.message() << std::endl; + std::cerr << "Can't write screenshot: " << result.message() << " code " << result.status() << std::endl; } } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index be9ef21395..816fc0fa81 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -401,7 +401,7 @@ namespace MWGui osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); if (!result.success()) { - std::cerr << "Failed to read savegame screenshot: " << result.message() << std::endl; + std::cerr << "Failed to read savegame screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a2..f6fb83c944 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -361,7 +361,7 @@ namespace MWRender osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); if (!result.success()) { - std::cerr << "Can't write map overlay: " << result.message() << std::endl; + std::cerr << "Can't write map overlay: " << result.message() << " code " << result.status() << std::endl; return; } @@ -411,7 +411,7 @@ namespace MWRender osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); if (!result.success()) { - std::cerr << "Can't read map overlay: " << result.message() << std::endl; + std::cerr << "Can't read map overlay: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d307e990a1..02ca0cb4c6 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -645,7 +645,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in); if (!result.success()) { - std::cerr << "Failed to read fog: " << result.message() << std::endl; + std::cerr << "Failed to read fog: " << result.message() << " code " << result.status() << std::endl; return; } @@ -677,7 +677,7 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream); if (!result.success()) { - std::cerr << "Unable to write fog: " << result.message() << std::endl; + std::cerr << "Unable to write fog: " << result.message() << " code " << result.status() << std::endl; return; } mFogOfWarImage->flipVertical(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f23..df433ad6a2 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -606,7 +606,7 @@ void MWState::StateManager::writeScreenshot(std::vector &imageData) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream); if (!result.success()) { - std::cerr << "Unable to write screenshot: " << result.message() << std::endl; + std::cerr << "Unable to write screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d29aa28122..c2f76a527f 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -182,7 +182,7 @@ namespace Resource osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { - std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; return mWarningTexture; } From 85bc41dedb9db07da2c4609ea39be95b508bb5e2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 19:34:28 +1200 Subject: [PATCH 0966/1812] replaced FLT_MAX with numeric_limits. --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e4..7b846cb975 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -806,7 +806,7 @@ namespace MWMechanics void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { - float distanceToClosestNode = FLT_MAX; + float distanceToClosestNode = std::numeric_limits::max(); unsigned int index = 0; for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) { diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index e4b1438260..5dfe388a84 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -181,7 +181,7 @@ namespace MWMechanics void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) { - float minChance = FLT_MAX; + float minChance = std::numeric_limits::max(); const ESM::EffectList& effects = spell->mEffects; for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9c9c111060..f40624ae82 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,8 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = FLT_MAX; - float closestDistanceReachable = FLT_MAX; + float closestDistanceBetween = std::numeric_limits::max(); + float closestDistanceReachable = std::numeric_limits::max(); int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -78,7 +78,7 @@ namespace } } - // invariant: start and endpoint must be connected + // post-condition: start and endpoint must be connected assert(cell->isPointConnected(start, closestReachableIndex)); // AiWander has logic that depends on whether a path was created, deleting diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96f..59410001ff 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -92,7 +92,7 @@ namespace MWMechanics if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) return 0; - float y = FLT_MAX; + float y = std::numeric_limits::max(); float lowestSkill = 0; for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bac8fca6cb..1a1b04d181 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -383,7 +383,7 @@ namespace MWRender if (mFogDepth == 0.f) { mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(FLT_MAX); + mStateUpdater->setFogEnd(std::numeric_limits::max()); } else { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bde..36f275cf4a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2659,8 +2659,8 @@ namespace MWWorld MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); - float dist1 = FLT_MAX; - float dist2 = FLT_MAX; + float dist1 = std::numeric_limits::max(); + float dist2 = std::numeric_limits::max(); if (result1.mHit) dist1 = (origin - result1.mHitPos).length(); @@ -2853,7 +2853,7 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; + float closestDistance = std::numeric_limits::max(); std::vector markers; mCells.getExteriorPtrs(id, markers); From 77a1d947cc6796d3878f96af8d618a692957c381 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 21:12:39 +1200 Subject: [PATCH 0967/1812] extracted MWMechanics::getPlayer() --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 4 ++- apps/openmw/mwclass/npc.cpp | 15 +++++----- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwdialogue/filter.cpp | 13 +++++---- apps/openmw/mwgui/alchemywindow.cpp | 7 +++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++- apps/openmw/mwgui/charactercreation.cpp | 5 ++-- apps/openmw/mwgui/container.cpp | 7 +++-- apps/openmw/mwgui/dialogue.cpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 ++++--- apps/openmw/mwgui/hud.cpp | 7 +++-- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++----- apps/openmw/mwgui/jailscreen.cpp | 5 ++-- apps/openmw/mwgui/levelupdialog.cpp | 3 +- apps/openmw/mwgui/merchantrepair.cpp | 5 ++-- apps/openmw/mwgui/quickkeysmenu.cpp | 9 +++--- apps/openmw/mwgui/recharge.cpp | 5 ++-- apps/openmw/mwgui/referenceinterface.cpp | 4 ++- apps/openmw/mwgui/repair.cpp | 4 ++- apps/openmw/mwgui/scrollwindow.cpp | 4 ++- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +++--- apps/openmw/mwgui/spellcreationdialog.cpp | 7 +++-- apps/openmw/mwgui/spellicons.cpp | 3 +- apps/openmw/mwgui/spellwindow.cpp | 11 +++---- apps/openmw/mwgui/statswindow.cpp | 7 +++-- apps/openmw/mwgui/tooltips.cpp | 5 ++-- apps/openmw/mwgui/tradewindow.cpp | 5 ++-- apps/openmw/mwgui/trainingwindow.cpp | 3 +- apps/openmw/mwgui/travelwindow.cpp | 3 +- apps/openmw/mwgui/waitdialog.cpp | 5 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++-- apps/openmw/mwmechanics/actors.cpp | 23 ++++++++------- apps/openmw/mwmechanics/actorutil.cpp | 12 ++++++++ apps/openmw/mwmechanics/actorutil.hpp | 14 +++++++++ apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +- apps/openmw/mwmechanics/aipackage.cpp | 3 +- apps/openmw/mwmechanics/aisequence.cpp | 5 ++-- apps/openmw/mwmechanics/aiwander.cpp | 5 ++-- apps/openmw/mwmechanics/character.cpp | 21 +++++++------- apps/openmw/mwmechanics/combat.cpp | 13 +++++---- apps/openmw/mwmechanics/difficultyscaling.cpp | 4 ++- apps/openmw/mwmechanics/disease.hpp | 8 +++-- apps/openmw/mwmechanics/enchanting.cpp | 7 +++-- apps/openmw/mwmechanics/levelledlist.hpp | 5 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 29 ++++++++++--------- apps/openmw/mwmechanics/repair.cpp | 9 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 29 ++++++++++--------- apps/openmw/mwphysics/physicssystem.cpp | 3 +- apps/openmw/mwrender/characterpreview.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 4 ++- apps/openmw/mwscript/cellextensions.cpp | 22 +++++++------- apps/openmw/mwscript/containerextensions.cpp | 6 ++-- apps/openmw/mwscript/guiextensions.cpp | 4 ++- apps/openmw/mwscript/miscextensions.cpp | 7 +++-- apps/openmw/mwscript/statsextensions.cpp | 29 ++++++++++--------- .../mwscript/transformationextensions.cpp | 18 +++++++----- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++-- apps/openmw/mwworld/action.cpp | 4 ++- apps/openmw/mwworld/actionequip.cpp | 4 ++- apps/openmw/mwworld/containerstore.cpp | 5 ++-- apps/openmw/mwworld/failedaction.cpp | 3 +- apps/openmw/mwworld/inventorystore.cpp | 9 +++--- apps/openmw/mwworld/projectilemanager.cpp | 3 +- apps/openmw/mwworld/weather.cpp | 4 ++- 70 files changed, 327 insertions(+), 215 deletions(-) create mode 100644 apps/openmw/mwmechanics/actorutil.cpp create mode 100644 apps/openmw/mwmechanics/actorutil.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c33b711e68..a0f9e8e13c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -78,7 +78,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement + mechanicsmanagerimp stat creaturestats magiceffects movement actorutil drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 2ba8ba03bc..324dd32eef 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -20,6 +20,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/tooltips.hpp" @@ -244,7 +245,7 @@ namespace MWClass typeText = "#{sHeavy}"; text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, - MWBase::Environment::get().getWorld()->getPlayerPtr())); + MWMechanics::getPlayer())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5604aa783f..ff09282c1f 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/combat.hpp" +#include "../mwmechanics/actorutil.hpp" namespace { @@ -344,7 +345,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6749afa6bc..18c381e133 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -26,6 +26,8 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { struct DoorCustomData : public MWWorld::CustomData @@ -126,7 +128,7 @@ namespace MWClass if (needKey && hasKey) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e2b714a64f..5f166b3e32 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -24,6 +24,7 @@ #include "../mwmechanics/autocalcspell.hpp" #include "../mwmechanics/difficultyscaling.hpp" #include "../mwmechanics/character.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -503,7 +504,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -542,7 +543,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -608,7 +609,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -700,7 +701,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -716,7 +717,7 @@ namespace MWClass break; } } - else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + else if(ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -729,7 +730,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); @@ -783,7 +784,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f205eb8d..993dde6e45 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -41,6 +41,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "filter.hpp" #include "hypertextparser.hpp" @@ -532,7 +533,7 @@ namespace MWDialogue else if (curDisp + mTemporaryDispositionChange > 100) mTemporaryDispositionChange = 100 - curDisp; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); if (success) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5e6b83b507..e3a773b052 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/actorutil.hpp" #include "selectwrapper.hpp" @@ -97,7 +98,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const { - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); // check player faction if (!info.mPcFaction.empty()) @@ -219,7 +220,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcHealthPercent: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float ratio = player.getClass().getCreatureStats (player).getHealth().getCurrent() / player.getClass().getCreatureStats (player).getHealth().getModified(); @@ -229,7 +230,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcDynamicStat: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float value = player.getClass().getCreatureStats (player). getDynamic (select.getArgument()).getCurrent(); @@ -253,7 +254,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -429,7 +430,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -532,7 +533,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_ShouldAttack: return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); case SelectWrapper::Function_Werewolf: diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 768ad82e43..60bd70c04f 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/magiceffects.hpp" #include "../mwmechanics/alchemy.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -124,9 +125,9 @@ namespace MWGui void AlchemyWindow::open() { - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); - InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()); + InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); mSortModel = new SortFilterItemModel(model); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mItemView->setModel (mSortModel); @@ -136,7 +137,7 @@ namespace MWGui int index = 0; - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 44a9885232..f3cefb7874 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -123,7 +125,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 6585a0dd09..d2ce35509d 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/fallback.hpp" @@ -51,7 +52,7 @@ namespace void updatePlayerHealth() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); npcStats.updateHealth(); } @@ -228,7 +229,7 @@ namespace MWGui mReviewDialog->setBirthSign(mPlayerBirthSignId); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); mReviewDialog->setHealth ( stats.getHealth() ); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b2cc09b43a..5d71fc445d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" @@ -137,7 +138,7 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mModel = new PickpocketItemModel(player, new InventoryItemModel(container), !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); } @@ -183,7 +184,7 @@ namespace MWGui && !mPickpocketDetected ) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.finish()) { @@ -260,7 +261,7 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // TODO: move to ItemModels if (dynamic_cast(mModel) && !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ce33a74dda..a6000a739d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -21,6 +21,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "bookpage.hpp" @@ -89,7 +90,7 @@ namespace MWGui WindowModal::open(); center(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mBribe10Button->setEnabled (playerGold >= 10); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 61a935a6fb..c182a0a527 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -18,6 +18,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemselection.hpp" #include "itemwidget.hpp" @@ -160,7 +162,7 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); @@ -208,7 +210,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); } else @@ -263,7 +265,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); @@ -324,7 +326,7 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (mPtr != player && mEnchanting.getEnchantPrice() > playerGold) { diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1acbea6d7d..a93bb47e9d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "spellicons.hpp" @@ -259,7 +260,7 @@ namespace MWGui { // drop item into the gameworld MWBase::Environment::get().getWorld()->breakInvisibility( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); @@ -338,7 +339,7 @@ namespace MWGui void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); @@ -350,7 +351,7 @@ namespace MWGui void HUD::onMagicClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 580e583c95..f5a5f023f0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -29,6 +29,8 @@ #include "../mwscript/interpretercontext.hpp" #include "../mwrender/characterpreview.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -63,7 +65,7 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) - , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) { mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); @@ -333,7 +335,7 @@ namespace MWGui void InventoryWindow::open() { - mPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + mPtr = MWMechanics::getPlayer(); updateEncumbranceBar(); @@ -439,7 +441,7 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) @@ -549,7 +551,7 @@ namespace MWGui void InventoryWindow::updateEncumbranceBar() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); @@ -583,7 +585,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); dirtyPreview(); } @@ -614,7 +616,7 @@ namespace MWGui int count = object.getRefData().getCount(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); @@ -644,7 +646,7 @@ namespace MWGui { ItemModel::ModelIndex selected = -1; // not using mSortFilterModel as we only need sorting, not filtering - SortFilterItemModel model(new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + SortFilterItemModel model(new InventoryItemModel(MWMechanics::getPlayer())); model.setSortByType(false); model.update(); if (model.getItemCount() == 0) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index e4a3a31478..7eaf5eb303 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -8,6 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/store.hpp" @@ -57,7 +58,7 @@ namespace MWGui if (mFadeTimeRemaining <= 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); @@ -76,7 +77,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); for (int i=0; igetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); if (mSpentAttributes.size() < mCoinCount) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 862b719d48..481e1ceb47 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -13,6 +13,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -40,7 +41,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); @@ -125,7 +126,7 @@ void MerchantRepair::exit() void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int price = MyGUI::utility::parseInt(sender->getUserString("Price")); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2b..d251518168 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/inventorywindow.hpp" @@ -147,7 +148,7 @@ namespace MWGui mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyUsableItems); mAssignDialog->setVisible (false); @@ -262,7 +263,7 @@ namespace MWGui QuickKeyType type = mAssigned[index-1]; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); if (type == Type_Item || type == Type_MagicItem) @@ -473,7 +474,7 @@ namespace MWGui case Type_MagicItem: { // Find the item by id - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::Ptr item; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) @@ -543,7 +544,7 @@ namespace MWGui { WindowModal::open(); - mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 69c5c61c4f..1dac7138fb 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "itemwidget.hpp" @@ -92,7 +93,7 @@ void Recharge::updateView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) @@ -147,7 +148,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWWorld::Ptr item = *sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 2ea0db64ac..76bb4f53fa 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -3,6 +3,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWGui { ReferenceInterface::ReferenceInterface() @@ -16,7 +18,7 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 534226aebd..49d5735a46 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -9,6 +9,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -94,7 +96,7 @@ void Repair::updateRepairView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 01ce7767e3..ccc07174dc 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,6 +10,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -103,7 +105,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 61dd599e74..8c4520662d 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWGui { @@ -48,7 +49,7 @@ namespace MWGui int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // TODO: refactor to use MyGUI::ListBox @@ -125,7 +126,7 @@ namespace MWGui bool SpellBuyingWindow::playerHasSpell(const std::string &id) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); return player.getClass().getCreatureStats(player).getSpells().hasSpell(id); } @@ -133,7 +134,7 @@ namespace MWGui { int price = *_sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; @@ -158,7 +159,7 @@ namespace MWGui void SpellBuyingWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 57563be223..ff5a27abe2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" #include "class.hpp" @@ -376,7 +377,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold) @@ -474,7 +475,7 @@ namespace MWGui mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); - float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr()); + float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWMechanics::getPlayer()); mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); } @@ -507,7 +508,7 @@ namespace MWGui { // get the list of magic effects that are known to the player - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index db04536231..b2995af3c7 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -43,7 +44,7 @@ namespace MWGui { // TODO: Tracking add/remove/expire would be better than force updating every frame - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d2ea67ea96..68a6042561 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -15,6 +15,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" #include "inventorywindow.hpp" @@ -79,12 +80,12 @@ namespace MWGui { mSpellIcons->updateWidgets(mEffectBox, false); - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); // retrieve ContainerStoreIterator to the item @@ -159,7 +160,7 @@ namespace MWGui void SpellWindow::onSpellSelected(const std::string& spellId) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); @@ -169,7 +170,7 @@ namespace MWGui void SpellWindow::onDeleteSpellAccept() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); @@ -183,7 +184,7 @@ namespace MWGui void SpellWindow::cycle(bool next) { - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index cb1bf6f371..efbbeb29ae 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -234,7 +235,7 @@ namespace MWGui NoDrop::onFrame(dt); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); // level progress @@ -383,7 +384,7 @@ namespace MWGui int base = stat.getBase(); int modified = stat.getModified(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -493,7 +494,7 @@ namespace MWGui if (!mFactions.empty()) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); const std::set &expelled = PCstats.getExpelled(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index dbf27ad91d..7c7f951af1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -234,7 +235,7 @@ namespace MWGui } if (MWMechanics::spellIncreasesSkill(spell)) // display school of spells that contribute to skill progress { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int school = MWMechanics::getSpellSchool(spell, player); info.text = "#{sSchool}: " + sSchoolNames[school]; } @@ -355,7 +356,7 @@ namespace MWGui if(!mFocusObject.isEmpty()) { const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWWorld::Ptr victim; MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0ae661eb3c..6f45ed0053 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -20,6 +20,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" @@ -282,7 +283,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // check if the player can afford this @@ -490,7 +491,7 @@ namespace MWGui void TradeWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 6376ced574..30ad27e46e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -13,6 +13,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -68,7 +69,7 @@ namespace MWGui { mPtr = actor; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ea6301adf..8c55c37329 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -12,6 +12,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -144,7 +145,7 @@ namespace MWGui int price; iss >> price; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (playerGoldgetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); // trigger levelup if possible @@ -213,7 +214,7 @@ namespace MWGui void WaitDialog::setCanRest (bool canRest) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); bool full = (stats.getHealth().getCurrent() >= stats.getHealth().getModified()) && (stats.getMagicka().getCurrent() >= stats.getMagicka().getModified()); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db55937043..01bf2e7c61 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,6 +56,7 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/localmap.hpp" @@ -903,7 +904,7 @@ namespace MWGui if (!mLocalMapRender) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); @@ -1547,7 +1548,7 @@ namespace MWGui { mInventoryWindow->updatePlayer(); - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { setWerewolfOverlay(true); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2d767c6f57..74842e3e37 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -28,6 +28,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" using namespace ICS; @@ -1012,7 +1013,7 @@ namespace MWInput { if (!mControlSwitch["playercontrols"]) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form @@ -1029,7 +1030,7 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 584c4c320b..a323028c0e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -33,6 +33,7 @@ #include "actor.hpp" #include "summoning.hpp" #include "combat.hpp" +#include "actorutil.hpp" namespace { @@ -55,7 +56,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a action.execute(actor); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actor == MWMechanics::getPlayer() && rightHand != store.end() && newPtr == *rightHand) { MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); @@ -81,7 +82,7 @@ public: const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc()) || (key.mId == ESM::MagicEffect::CommandCreature && mActor.getTypeName() == typeid(ESM::Creature).name())) && casterActorId == player.getClass().getCreatureStats(player).getActorId() @@ -202,7 +203,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -400,7 +401,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -511,7 +512,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -559,7 +560,7 @@ namespace MWMechanics // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ActiveSpells::ActiveSpellParams& spell = it->second; @@ -726,7 +727,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool isPlayer = (ptr == getPlayer()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -823,7 +824,7 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); if (ptr != player && ptr.getClass().isNpc()) { // get stats of witness @@ -945,7 +946,7 @@ namespace MWMechanics if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); int hostilesCount = 0; // need to know this to play Battle music @@ -1042,7 +1043,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (iter->first == getPlayer()) { playerCharacter = iter->second->getCharacterController(); continue; @@ -1423,7 +1424,7 @@ namespace MWMechanics for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (ptr == getPlayer() || !isConscious(ptr) || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp new file mode 100644 index 0000000000..dc37705563 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -0,0 +1,12 @@ +#include "actorutil.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer() + { + return MWBase::Environment::get().getWorld()->getPlayerPtr(); + } +} diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp new file mode 100644 index 0000000000..95172b9f91 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -0,0 +1,14 @@ +#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H +#define OPENMW_MWMECHANICS_ACTORUTIL_H + +namespace MWWorld +{ + class Ptr; +} + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer(); +} + +#endif diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b3aa346cee..409f7b9c40 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -6,6 +6,7 @@ #include "../mwworld/class.hpp" #include "creaturestats.hpp" #include "movement.hpp" +#include "actorutil.hpp" #include "steering.hpp" @@ -63,7 +64,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont std::vector actors; MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player + if(*it != getPlayer()) { //Not the player MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1ab3264b7b..2c8c57c56b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -15,6 +15,7 @@ #include "../mwworld/action.hpp" #include "steering.hpp" +#include "actorutil.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -34,7 +35,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po /// Stops the actor when it gets too close to a unloaded cell const ESM::Cell *cell = actor.getCell()->getCell(); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); Movement &movement = actor.getClass().getMovementSettings(actor); //Ensure pursuer doesn't leave loaded cells diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index a750860ca9..a1c5ab14f0 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -12,6 +12,7 @@ #include "aiactivate.hpp" #include "aicombat.hpp" #include "aipursue.hpp" +#include "actorutil.hpp" #include @@ -150,7 +151,7 @@ bool AiSequence::isPackageDone() const void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor != getPlayer()) { if (!mPackages.empty()) { @@ -242,7 +243,7 @@ void AiSequence::clear() void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) { - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == getPlayer()) throw std::runtime_error("Can't add AI packages to player"); if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e4..f3f808a2ed 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -21,6 +21,7 @@ #include "steering.hpp" #include "movement.hpp" #include "coordinateconverter.hpp" +#include "actorutil.hpp" @@ -462,7 +463,7 @@ namespace MWMechanics if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); @@ -496,7 +497,7 @@ namespace MWMechanics helloDistance *= iGreetDistanceMultiplier; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); float playerDistSqr = (playerPos - actorPos).length2(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3959c413a6..3837e9a75e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,7 @@ #include "npcstats.hpp" #include "creaturestats.hpp" #include "security.hpp" +#include "actorutil.hpp" #include @@ -619,7 +620,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) void CharacterController::playRandomDeath(float startpoint) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { // The first-person animations do not include death, so we need to // force-switch to third person before playing the death animation. @@ -1167,7 +1168,7 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } @@ -1177,7 +1178,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1257,7 +1258,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if(isWeapon && mPtr == getPlayer() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1563,7 +1564,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mHasMovedInXY && mPtr == getPlayer()) { if(inwater) { @@ -1664,7 +1665,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1707,7 +1708,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1949,7 +1950,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == getPlayer() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1965,7 +1966,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mPtr == getPlayer()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -2006,7 +2007,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 2e20d0e1f2..f11e6bcfda 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -19,6 +19,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwbase/windowmanager.hpp" +#include "actorutil.hpp" namespace { @@ -137,7 +138,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (blocker == getPlayer()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -161,7 +162,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -178,7 +179,7 @@ namespace MWMechanics return; } - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; @@ -207,7 +208,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) @@ -222,7 +223,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory - if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (victim != getPlayer() && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); @@ -247,7 +248,7 @@ namespace MWMechanics { // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) - && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (attacker == getPlayer()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || victimStats.isParalyzed() diff --git a/apps/openmw/mwmechanics/difficultyscaling.cpp b/apps/openmw/mwmechanics/difficultyscaling.cpp index 05ab12ccd2..950fe33cf4 100644 --- a/apps/openmw/mwmechanics/difficultyscaling.cpp +++ b/apps/openmw/mwmechanics/difficultyscaling.cpp @@ -6,9 +6,11 @@ #include +#include "actorutil.hpp" + float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); // [-100, 100] int difficultySetting = Settings::Manager::getInt("difficulty", "Game"); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index cf21f3806b..27c19364f9 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -9,8 +9,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "spells.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" + namespace MWMechanics { @@ -20,7 +22,7 @@ namespace MWMechanics /// @param carrier The disease carrier. inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier) { - if (!carrier.getClass().isActor() || actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!carrier.getClass().isActor() || actor != getPlayer()) return; float fDiseaseXferChance = diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 2cb963e282..102e3787ad 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -11,6 +11,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" #include "spellcasting.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -54,7 +55,7 @@ namespace MWMechanics bool Enchanting::create() { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); @@ -217,7 +218,7 @@ namespace MWMechanics int Enchanting::getEffectiveCastCost() const { int baseCost = getBaseCastCost(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -291,7 +292,7 @@ namespace MWMechanics void Enchanting::payForEnchantment() const { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(MWWorld::ContainerStore::sGoldId, getEnchantPrice(), player); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index f2f0c7cabe..edfef53581 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -11,7 +11,8 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -21,7 +22,7 @@ namespace MWMechanics { const std::vector& items = levItem->mList; - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); failChance += levItem->mChanceNone; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 075747ffef..711ecdbd28 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -26,6 +26,7 @@ #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" +#include "actorutil.hpp" namespace { @@ -83,7 +84,7 @@ namespace MWMechanics { void MechanicsManager::buildPlayer() { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats (ptr); @@ -361,7 +362,7 @@ namespace MWMechanics { // Uses ingame time, but scaled to real time duration /= MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); player.getClass().getInventoryStore(player).rechargeItems(duration); } @@ -489,7 +490,7 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); mActors.removeActor(ptr); mActors.addActor(ptr, true); } @@ -586,7 +587,7 @@ namespace MWMechanics float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); MWWorld::LiveCellRef* player = playerPtr.get(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); @@ -663,7 +664,7 @@ namespace MWMechanics const MWMechanics::NpcStats &sellerStats = ptr.getClass().getNpcStats(ptr); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); // I suppose the temporary disposition change _has_ to be considered here, @@ -707,7 +708,7 @@ namespace MWMechanics MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); float npcRating1, npcRating2, npcRating3; @@ -1010,7 +1011,7 @@ namespace MWMechanics void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) return; MWWorld::Ptr victim; @@ -1067,7 +1068,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (player != getPlayer()) return false; // Find all the actors within the alarm radius @@ -1306,7 +1307,7 @@ namespace MWMechanics bool MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) { - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) return false; std::list followers = getActorsFollowing(attacker); @@ -1340,7 +1341,7 @@ namespace MWMechanics commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) - || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + || attacker == getPlayer()) && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. @@ -1353,7 +1354,7 @@ namespace MWMechanics void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) { - if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (attacker.isEmpty() || attacker != getPlayer()) return; if (victim == attacker) @@ -1450,7 +1451,7 @@ namespace MWMechanics if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target)) return; ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) @@ -1547,7 +1548,7 @@ namespace MWMechanics if (ptr.getClass().isNpc() && target.getClass().isNpc()) { if (target.getClass().getNpcStats(target).isWerewolf() || - (target == MWBase::Environment::get().getWorld()->getPlayerPtr() && + (target == getPlayer() && MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf"))) { const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().search("iWerewolfFightMod"); @@ -1560,7 +1561,7 @@ namespace MWMechanics void MechanicsManager::keepPlayerAlive() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); CreatureStats& stats = player.getClass().getCreatureStats(player); if (stats.isDead()) { diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index fa429bbeef..581ba3a841 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -14,15 +14,16 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" +#include "creaturestats.hpp" +#include "npcstats.hpp" +#include "actorutil.hpp" namespace MWMechanics { void Repair::repair(const MWWorld::Ptr &itemToRepair) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::LiveCellRef *ref = mTool.get(); @@ -82,7 +83,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) // tool used up? if (mTool.getCellRef().getCharge() == 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(mTool, 1, player); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 12ed044282..cbd0b8731d 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -26,6 +26,7 @@ #include "magiceffects.hpp" #include "npcstats.hpp" #include "summoning.hpp" +#include "actorutil.hpp" namespace { @@ -133,7 +134,7 @@ namespace MWMechanics int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == getPlayer()) castChance = 100; if (!cap) @@ -340,7 +341,7 @@ namespace MWMechanics if (Misc::Rng::roll0to99() <= x) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -358,7 +359,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool castByPlayer = (!caster.isEmpty() && caster == getPlayer()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -433,7 +434,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -569,7 +570,7 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } @@ -585,7 +586,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getClass().unlock(target); @@ -622,7 +623,7 @@ namespace MWMechanics return true; } - if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target != getPlayer()) return false; if (effectId == ESM::MagicEffect::DivineIntervention) @@ -701,7 +702,7 @@ namespace MWMechanics if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -725,14 +726,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -799,7 +800,7 @@ namespace MWMechanics float successChance = getSpellSuccessChance(spell, mCaster); if (Misc::Rng::roll0to99() >= successChance) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -817,7 +818,7 @@ namespace MWMechanics } } - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) + if (mCaster == getPlayer() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); @@ -962,7 +963,7 @@ namespace MWMechanics if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -1097,7 +1098,7 @@ namespace MWMechanics } - if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (receivedMagicDamage && actor == getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb2618514..77e2f6803a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -30,6 +30,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -1091,7 +1092,7 @@ namespace MWPhysics bool PhysicsSystem::toggleCollisionMode() { - ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr()); + ActorMap::iterator found = mActors.find(MWMechanics::getPlayer()); if (found != mActors.end()) { bool cmode = found->second->getCollisionMode(); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b4e1189f73..93afeda25b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -17,6 +17,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "npcanimation.hpp" #include "vismask.hpp" @@ -295,7 +297,7 @@ namespace MWRender // -------------------------------------------------------------------------------------------------- RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) - : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + : CharacterPreview(viewer, resourceSystem, MWMechanics::getPlayer(), 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c5a107837e..66a3d3ec61 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1039,7 +1040,7 @@ void NpcAnimation::setVampire(bool vampire) return; if ((mNpcType == Type_Vampire) != vampire) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == MWMechanics::getPlayer()) MWBase::Environment::get().getWorld()->reattachPlayerCamera(); else rebuild(); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index a3e96a5b15..a7637f2e1a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -22,6 +22,8 @@ #include "../mwworld/fallback.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) @@ -177,7 +179,7 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) { - if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (it->mPtr.getCell() == store && it->mPtr != MWMechanics::getPlayer()) { it = mEmitters.erase(it); } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 8af2e5ef36..5dd3cf4119 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -16,6 +16,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" namespace MWScript @@ -91,14 +93,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push (0); return; } bool interior = - !MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell()->isExterior(); + !MWMechanics::getPlayer().getCell()->getCell()->isExterior(); runtime.push (interior ? 1 : 0); } @@ -113,12 +115,12 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0); return; } - const MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + const MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); Misc::StringUtils::toLower(current); @@ -136,12 +138,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0.f); return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); else @@ -157,12 +159,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); @@ -180,12 +182,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 6749739780..20ca2b5800 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -26,6 +26,8 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -147,7 +149,7 @@ namespace MWScript // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) - && (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())) + && (ptr == MWMechanics::getPlayer())) { // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; @@ -192,7 +194,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f48360c047..397e0cac5a 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -53,7 +55,7 @@ namespace MWScript { MWWorld::Ptr bed = R()(runtime, false); - if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWBase::Environment::get().getWorld()->getPlayerPtr(), + if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index faf5749934..32d86f55ad 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -27,6 +27,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -156,7 +157,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); - context.executeActivation(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + context.executeActivation(ptr, MWMechanics::getPlayer()); } }; @@ -976,7 +977,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->confiscateStolenItems(player); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); @@ -988,7 +989,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 112e7c77fc..4debb24fed 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -25,6 +25,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -460,7 +461,7 @@ namespace MWScript MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if (ptr == MWMechanics::getPlayer() && id == wm->getSelectedSpell()) { wm->unsetSelectedSpell(); @@ -548,7 +549,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).joinFaction(factionID); } } @@ -580,7 +581,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end()) { player.getClass().getNpcStats(player).joinFaction(factionID); @@ -619,7 +620,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).lowerRank(factionID); } } @@ -648,7 +649,7 @@ namespace MWScript // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end()) @@ -757,7 +758,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); runtime.push ( player.getClass().getNpcStats (player).getFactionReputation (factionId)); } @@ -792,7 +793,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, value); } }; @@ -826,7 +827,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, player.getClass().getNpcStats (player).getFactionReputation (factionId)+ value); @@ -911,7 +912,7 @@ namespace MWScript factionID = ptr.getClass().getPrimaryFaction(ptr); } ::Misc::StringUtils::toLower(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { runtime.push(player.getClass().getNpcStats(player).getExpelled(factionID)); @@ -942,7 +943,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { player.getClass().getNpcStats(player).expell(factionID); @@ -969,7 +970,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") player.getClass().getNpcStats(player).clearExpelled(factionID); } @@ -988,7 +989,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1011,7 +1012,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1120,7 +1121,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 0f9faa11a5..679a8d2dea 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -20,6 +20,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -214,7 +216,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -289,7 +291,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -333,7 +335,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); @@ -354,7 +356,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -372,7 +374,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); @@ -389,7 +391,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -469,7 +471,7 @@ namespace MWScript Interpreter::Type_Float zRot = runtime[0].mFloat; runtime.pop(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::CellStore* store = NULL; if (player.getCell()->isExterior()) { @@ -501,7 +503,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc - ? MWBase::Environment::get().getWorld()->getPlayerPtr() + ? MWMechanics::getPlayer() : R()(runtime); std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1f73fc1fc9..bc97f16016 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -15,6 +15,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "sound_output.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -490,7 +492,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && + snditer->second.first != MWMechanics::getPlayer() && snditer->second.first.getCell() == cell) { snditer->first->stop(); @@ -735,7 +737,7 @@ namespace MWSound mListenerUp = up; MWWorld::Ptr player = - MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWMechanics::getPlayer(); const MWWorld::CellStore *cell = player.getCell(); mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f23..6995e24bef 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwscript/globalscripts.hpp" @@ -472,7 +473,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); @@ -519,7 +520,7 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); std::string name = player.get()->mBase->mName; return mCharacterManager.getCurrentCharacter (create, name); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index fb2059de92..6361b34048 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -5,6 +5,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + const MWWorld::Ptr& MWWorld::Action::getTarget() const { return mTarget; @@ -19,7 +21,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 87a4c63084..147f229638 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -4,6 +4,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include #include "inventorystore.hpp" @@ -24,7 +26,7 @@ namespace MWWorld std::pair result = object.getClass().canBeEquipped (object, actor); // display error message if the player tried to equip something - if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!result.second.empty() && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(result.second); switch(result.first) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05ae4f134e..8c6f7d2595 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwmechanics/actorutil.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -209,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actorPtr != MWMechanics::getPlayer()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); @@ -224,7 +225,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr // HACK: Set owner on the original item, then reset it after we have copied it // If we set the owner on the copied item, it would not stack correctly... std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway + if (!setOwner || actorPtr == MWMechanics::getPlayer()) // No point in setting owner to the player - NPCs will not respect this anyway { itemPtr.getCellRef().setOwner(""); } diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index cf5a2a5c2f..49ca9dae07 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -13,7 +14,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) + if(actor == MWMechanics::getPlayer() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2dbc222349..0755c1555e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -16,6 +16,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "esmstore.hpp" @@ -136,7 +137,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actorPtr != MWMechanics::getPlayer() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -508,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWMechanics::getPlayer()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -540,7 +541,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); @@ -595,7 +596,7 @@ void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) // if player, update inventory window /* - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6295ed159c..3e9f172786 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -20,6 +20,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" @@ -187,7 +188,7 @@ namespace MWWorld } // Explodes when hitting water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), newPos)) + if (MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos)) hit = true; if (hit) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 99193de672..cc5b726afe 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -12,6 +12,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwsound/sound.hpp" #include "../mwrender/renderingmanager.hpp" @@ -798,7 +800,7 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.isInCell()) { std::string playerRegion = player.getCell()->getCell()->mRegion; From 3fa5c6a0e781e7cd4f659694f56a71d2671bf06b Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:00:08 +1200 Subject: [PATCH 0968/1812] fixed travis build failure --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1a1b04d181..f4b8aa451e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,6 +1,7 @@ #include "renderingmanager.hpp" #include +#include #include #include From 5dd0ad684123f9e9fcee602c37ed30f8747f9ecf Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:41:31 +1200 Subject: [PATCH 0969/1812] Fixed rest of travis errors. --- apps/openmw/mwmechanics/autocalcspell.cpp | 1 + apps/openmw/mwmechanics/pathfinding.cpp | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 5dfe388a84..b798ff5dce 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -1,6 +1,7 @@ #include "autocalcspell.hpp" #include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f40624ae82..f53badbf46 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,4 +1,5 @@ #include "pathfinding.hpp" +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 59410001ff..99625e90a3 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1,6 +1,7 @@ #include "spellcasting.hpp" #include +#include #include From 3902513e65206908c0f0f54db213a7c9ea7f2fd0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 21 Aug 2015 14:02:32 +0200 Subject: [PATCH 0970/1812] merge id collections --- apps/opencs/model/tools/mergeoperation.cpp | 23 ++++++++++ apps/opencs/model/tools/mergestages.hpp | 53 +++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e5fb27456..4a85eca798 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -10,6 +10,29 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getClasses)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFactions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRaces)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSounds)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getScripts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRegions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBirthsigns)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSpells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopics)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getCells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFilters)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getEnchantments)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBodyParts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getDebugProfiles)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + + /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9844feaca3..749fab18c7 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -5,10 +5,12 @@ #include "../doc/stage.hpp" +#include "../world/data.hpp" + +#include "mergestate.hpp" + namespace CSMTools { - struct MergeState; - class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; @@ -24,6 +26,53 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + template + class MergeIdCollectionStage : public CSMDoc::Stage + { + typedef typename CSMWorld::IdCollection Collection; + + MergeState& mState; + Collection& (CSMWorld::Data::*mAccessor)(); + + public: + + MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + : mState (state), mAccessor (accessor) + {} + + template + int MergeIdCollectionStage::setup() + { + return 1; + } + + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + { + const Collection& source = (mState.mSource.getData().*mAccessor)(); + Collection& target = (mState.mTarget->getData().*mAccessor)(); + + int size = source.getSize(); + + for (int i=0; i& record = source.getRecord (i); + + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + } + } } #endif From 52d8bc555c10b1ef8ac263856ff2e8d4131c7160 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 14:24:34 +0200 Subject: [PATCH 0971/1812] Add missing checks to see if spell still exists when loading a savegame (Bug #2883) --- apps/openmw/mwgui/quickkeysmenu.cpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2b..89e6e59be8 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -467,7 +467,8 @@ namespace MWGui switch (keyType) { case Type_Magic: - onAssignMagic(id); + if (MWBase::Environment::get().getWorld()->getStore().get().search(id)) + onAssignMagic(id); break; case Type_Item: case Type_MagicItem: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db55937043..7f9302bf2b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1686,7 +1686,9 @@ namespace MWGui else if (type == ESM::REC_ASPL) { reader.getSubNameIs("ID__"); - mSelectedSpell = reader.getHString(); + std::string spell = reader.getHString(); + if (MWBase::Environment::get().getWorld()->getStore().get().search(spell)) + mSelectedSpell = spell; } else if (type == ESM::REC_MARK) { From ba8e4c22aa51efa5f689dfecfe0673b96c56a57a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 20:17:42 +0200 Subject: [PATCH 0972/1812] Avoid using loops to wrap angle values (Fixes #2882) --- apps/openmw/mwworld/worldimp.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bde..aa444cb144 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1213,7 +1213,6 @@ namespace MWWorld void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) { const float pi = static_cast(osg::PI); - const float two_pi = pi*2.f; ESM::Position pos = ptr.getRefData().getPosition(); float *objRot = pos.rot; @@ -1243,15 +1242,11 @@ namespace MWWorld } else { - while(objRot[0] < -pi) objRot[0] += two_pi; - while(objRot[0] > pi) objRot[0] -= two_pi; + wrap(objRot[0]); } - while(objRot[1] < -pi) objRot[1] += two_pi; - while(objRot[1] > pi) objRot[1] -= two_pi; - - while(objRot[2] < -pi) objRot[2] += two_pi; - while(objRot[2] > pi) objRot[2] -= two_pi; + wrap(objRot[1]); + wrap(objRot[2]); ptr.getRefData().setPosition(pos); From d038ac2da092629e7b08379ae938f2666073b574 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:38:28 +0300 Subject: [PATCH 0973/1812] Sort tables by ID in the ascending order initially --- apps/opencs/view/world/table.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 72e0c82d03..73bef7b26b 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -273,12 +273,16 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, horizontalHeader()->setResizeMode (QHeaderView::Interactive); #endif verticalHeader()->hide(); - setSortingEnabled (sorting); setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); - int columns = mModel->columnCount(); + setSortingEnabled (sorting); + if (sorting) + { + sortByColumn (mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id), Qt::AscendingOrder); + } + int columns = mModel->columnCount(); for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); From e14aedc7cde788e3a9d67c555a749fd319a2e656 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:47:29 +0300 Subject: [PATCH 0974/1812] ModifyCommand uses a proper name of a modified nested value --- apps/opencs/model/world/commands.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7673e6bc96..d510cd1038 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -21,12 +21,17 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI // Replace proxy with actual model mIndex = proxy->mapToSource (index); mModel = proxy->sourceModel(); + } + if (mIndex.parent().isValid()) + { setText ("Modify " + dynamic_cast(mModel)->nestedHeaderData ( mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } else + { setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + } // Remember record state before the modification if (CSMWorld::IdTable *table = dynamic_cast(mModel)) From aeb1acca514d86e8cb4fcc41c1045f4b1f1886a0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:05:40 +0300 Subject: [PATCH 0975/1812] Remove enum names for AiWanderRepeat column --- apps/opencs/model/world/columns.cpp | 6 ------ apps/opencs/view/doc/viewmanager.cpp | 1 - 2 files changed, 7 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1fcf0ae41f..045438befe 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -536,11 +536,6 @@ namespace "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 }; - static const char *sAiWanderRepeat[] = - { - "No", "Yes", 0 - }; - static const char *sInfoCondFunc[] = { " ", "Function", "Global", "Local", "Journal", @@ -580,7 +575,6 @@ namespace case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; - case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; case CSMWorld::Columns::ColumnId_InfoCondFunc: return sInfoCondFunc; // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7c9686277f..3e832bdcf3 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -102,7 +102,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, From b7295e263210ce0a6c1f46c61189b44c1d188951 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:36:53 +0300 Subject: [PATCH 0976/1812] Columns with Display_Boolean use Combobox editor even for non-boolean values --- apps/opencs/view/world/util.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 2654644c49..b87d6b4f48 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" @@ -172,7 +173,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO // TODO: Find a better solution? if (display == CSMWorld::ColumnBase::Display_Boolean) { - return QStyledItemDelegate::createEditor(parent, option, index); + return QItemEditorFactory::defaultFactory()->createEditor(QVariant::Bool, parent); } // For tables the pop-up of the color editor should appear immediately after the editor creation // (the third parameter of ColorEditor's constructor) From 031d64d0d34f6ac72520ffcdf5634454e34f475a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 12:57:39 +0200 Subject: [PATCH 0977/1812] Adjust OpenCS saving stages order to stop vanilla MW complaining about missing records --- apps/opencs/model/doc/saving.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 25372f1a6e..95a2feaf24 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -80,22 +80,25 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getStartScripts(), mState)); - appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); - - appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); - appendStage (new WriteRefIdCollectionStage (mDocument, mState)); appendStage (new CollectionReferencesStage (mDocument, mState)); appendStage (new WriteCellCollectionStage (mDocument, mState)); + // Dialogue can reference objects and cells so must be written after these records for vanilla-compatible files + + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); + + appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); + appendStage (new WritePathgridCollectionStage (mDocument, mState)); - appendStage (new WriteLandCollectionStage (mDocument, mState)); - appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // references Land Textures + appendStage (new WriteLandCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); From 32ad8c86bf6c3414651c899d6859ed2463e4afca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 13:10:54 +0200 Subject: [PATCH 0978/1812] Fix the ESM::LandTexture NAME being discarded on loading --- apps/opencs/model/doc/savingstages.cpp | 2 ++ apps/opencs/model/world/landtexture.cpp | 8 +------- apps/opencs/model/world/landtexture.hpp | 7 ++----- apps/opencs/view/render/terrainstorage.cpp | 14 +++++++++++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index ef3b23ec88..01d260d681 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -454,6 +454,8 @@ void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& mess mState.getWriter().startRecord (record.sRecordId); + mState.getWriter().writeHNString("NAME", record.mId); + record.save (mState.getWriter()); mState.getWriter().endRecord (record.sRecordId); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4725866a56..e7772129cd 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -9,13 +9,7 @@ namespace CSMWorld { ESM::LandTexture::load(esm); - int plugin = esm.getIndex(); - - std::ostringstream stream; - - stream << mIndex << "_" << plugin; - - mId = stream.str(); + mPluginIndex = esm.getIndex(); } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index b13903186b..c0b6eeba9c 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -7,13 +7,10 @@ namespace CSMWorld { - /// \brief Wrapper for LandTexture record. Encodes mIndex and the plugin index (obtained from ESMReader) - /// in the ID. - /// - /// \attention The mId field of the ESM::LandTexture struct is not used. + /// \brief Wrapper for LandTexture record, providing info which plugin the LandTexture was loaded from. struct LandTexture : public ESM::LandTexture { - std::string mId; + int mPluginIndex; void load (ESM::ESMReader &esm); }; diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef14..3d9d1ee97a 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -29,10 +29,18 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - std::ostringstream stream; - stream << index << "_" << plugin; + int numRecords = mData.getLandTextures().getSize(); - return &mData.getLandTextures().getRecord(stream.str()).get(); + for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) + return ltex; + } + + std::stringstream error; + error << "Can't find LandTexture " << index << " from plugin " << plugin; + throw std::runtime_error(error.str()); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) From 6d81ca07b5d765fcf479480896f8bc2d2eb6cfd4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:55:58 +0300 Subject: [PATCH 0979/1812] Convert AiWanderRepeat to bool in ActorAiRefIdAdapter::getNestedData() --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4066b5646f..5ceb3325ae 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1566,7 +1566,7 @@ namespace CSMWorld return QVariant(); case 5: // wander repeat if (content.mType == ESM::AI_Wander) - return content.mWander.mShouldRepeat; + return content.mWander.mShouldRepeat != 0; else return QVariant(); case 6: // activate name From 4d24eff859aec2b8f5c901b35bae11e0e30c068c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 00:01:27 +0300 Subject: [PATCH 0980/1812] Show race only when mesh type is Skin (in BodyParts table) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnimp.cpp | 28 +++++++++++++++++++++++++++ apps/opencs/model/world/columnimp.hpp | 19 +++++++++++++++--- apps/opencs/model/world/data.cpp | 7 +++++-- 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/model/world/columnimp.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b1953ee975..9dd7e8c8e0 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -23,7 +23,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid record commands columnbase scriptcontext cell refidcollection + universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection idcompletionmanager metadata diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp new file mode 100644 index 0000000000..dc3d39edb2 --- /dev/null +++ b/apps/opencs/model/world/columnimp.cpp @@ -0,0 +1,28 @@ +#include "columnimp.hpp" + +CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) +{} + +QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +{ + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); +} + +void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) +{ + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); +} + +bool CSMWorld::BodyPartRaceColumn::isEditable() const +{ + return true; +} diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 15dd2c15b0..824196c88c 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -9,6 +9,8 @@ #include +#include + #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" @@ -1911,8 +1913,8 @@ namespace CSMWorld template struct MeshTypeColumn : public Column { - MeshTypeColumn() - : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType) + MeshTypeColumn(int flags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) + : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType, flags) {} virtual QVariant get (const Record& record) const @@ -2379,7 +2381,18 @@ namespace CSMWorld { return true; } - }; + }; + + struct BodyPartRaceColumn : public RaceColumn + { + const MeshTypeColumn *mMeshType; + + BodyPartRaceColumn(const MeshTypeColumn *meshType); + + virtual QVariant get(const Record &record) const; + virtual void set(Record &record, const QVariant &data); + virtual bool isEditable() const; + }; } #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 12ff1a38cc..94312ae7dc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -351,9 +351,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); - mBodyParts.addColumn (new MeshTypeColumn); + + int meshTypeFlags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh; + MeshTypeColumn *meshTypeColumn = new MeshTypeColumn(meshTypeFlags); + mBodyParts.addColumn (meshTypeColumn); mBodyParts.addColumn (new ModelColumn); - mBodyParts.addColumn (new RaceColumn); + mBodyParts.addColumn (new BodyPartRaceColumn(meshTypeColumn)); mSoundGens.addColumn (new StringIdColumn); mSoundGens.addColumn (new RecordStateColumn); From 720aca8f3dae258cc23ae7c28307ef5ab47637d1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 13:38:38 +0300 Subject: [PATCH 0981/1812] Inform about State change (not a whole row) when modifying a table value --- apps/opencs/model/world/idtable.cpp | 11 +++++++---- apps/opencs/model/world/idtree.cpp | 13 +++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bdbc5e0c45..bd1179cea2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -76,12 +76,15 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); + emit dataChanged(index, index); // Modifying a value can also change the Modified status of a record. - // To track this, we inform about the change of a whole row. - QModelIndex rowStart = this->index(index.row(), 0); - QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); - emit dataChanged(rowStart, rowEnd); + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 0b027cdab6..124a94e8ca 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -95,14 +95,15 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, const std::pair& parentAddress(unfoldIndexAddress(index.internalId())); mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged(index, index); - // Modifying a value can also change the Modified status of a record (located in the parent row). - // To track this, we inform about the change of a whole parent row. - QModelIndex parentRowStart = this->index(index.parent().row(), 0); - QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); - emit dataChanged(parentRowStart, parentRowEnd); + // Modifying a value can also change the Modified status of a record. + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.parent().row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } From ba4b7df99dc2d0e1b3f6189158c5c4f1aaab57ee Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 14:34:05 +0300 Subject: [PATCH 0982/1812] Add missing includes to columnimp.hpp --- apps/opencs/model/world/columnimp.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 824196c88c..4e608dbbde 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include "columnbase.hpp" #include "columns.hpp" From 542c648e6986160c7590703a6c1811ec06e34c8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 22:53:06 +0200 Subject: [PATCH 0983/1812] Fix incorrect assignment of PcRace, need to sort race IDs (Fixes #2884) --- apps/openmw/mwworld/store.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 3cbd8d3ac9..47c87f742d 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -170,6 +170,7 @@ namespace MWWorld size_t getSize() const; int getDynamicSize() const; + /// @note The record identifiers are listed in the order that the records were defined by the content files. void listIdentifier(std::vector &list) const; T *insert(const T &item); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b2624f4cf..8b53d16759 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1496,6 +1496,8 @@ namespace MWWorld std::vector ids; getStore().get().listIdentifier(ids); + std::sort(ids.begin(), ids.end()); + unsigned int i=0; for (; i Date: Sun, 23 Aug 2015 12:37:45 +0200 Subject: [PATCH 0984/1812] flag newly merged documents as dirty (triggering an 'are you sure' dialogue when closing without saving first) --- apps/opencs/model/doc/document.cpp | 12 ++++++++++-- apps/opencs/model/doc/document.hpp | 3 +++ apps/opencs/model/tools/tools.cpp | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8d5580bcf7..2cff893891 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData) + mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2325,7 +2325,7 @@ int CSMDoc::Document::getState() const { int state = 0; - if (!mUndoStack.isClean()) + if (!mUndoStack.isClean() || mDirty) state |= State_Modified; if (mSaving.isRunning()) @@ -2417,6 +2417,9 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type) void CSMDoc::Document::operationDone (int type, bool failed) { + if (type==CSMDoc::State_Saving && !failed) + mDirty = false; + emit stateChanged (getState(), this); } @@ -2493,3 +2496,8 @@ CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() { return mIdCompletionManager; } + +void CSMDoc::Document::flagAsDirty() +{ + mDirty = true; +} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 3eaa5bb148..0e8ae6d454 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -68,6 +68,7 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; + bool mDirty; CSMWorld::IdCompletionManager mIdCompletionManager; @@ -152,6 +153,8 @@ namespace CSMDoc CSMWorld::IdCompletionManager &getIdCompletionManager(); + void flagAsDirty(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c4ff6868bf..cabd539372 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -207,6 +207,8 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) this, SIGNAL (mergeDone (CSMDoc::Document*))); } + target->flagAsDirty(); + mMergeOperation->setTarget (target); mMerge.start(); From 103073150e87d62582649ea6943fdc510eb5ca59 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 12:58:49 +0200 Subject: [PATCH 0985/1812] added info tables and pathgrid table to merge operation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.hpp | 16 +++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 4a85eca798..d010e343b7 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -31,8 +31,11 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); - /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids + /// \todo Referencables, References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 749fab18c7..f9d29420bc 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -27,11 +27,9 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template + template > class MergeIdCollectionStage : public CSMDoc::Stage { - typedef typename CSMWorld::IdCollection Collection; - MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); @@ -46,19 +44,19 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template - MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) : mState (state), mAccessor (accessor) {} - template - int MergeIdCollectionStage::setup() + template + int MergeIdCollectionStage::setup() { return 1; } - template - void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) { const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); From 16dda281cee3fb1bab7276cc21448b754d5db3c5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 13:04:42 +0200 Subject: [PATCH 0986/1812] made merge operation more fluent --- apps/opencs/model/tools/mergestages.hpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f9d29420bc..af7f06d606 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include #include "../doc/stage.hpp" @@ -33,6 +35,8 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); + static const int stepSize = 1000; + public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -52,7 +56,16 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - return 1; + const Collection& source = (mState.mSource.getData().*mAccessor)(); + + int size = source.getSize(); + + int steps = size / stepSize; + + if (size % stepSize) + ++steps; + + return steps; } template @@ -61,9 +74,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int size = source.getSize(); + int begin = stage * stepSize; + int end = std::min ((stage+1) * stepSize, source.getSize()); - for (int i=0; i& record = source.getRecord (i); From b509a18065959b0e65bceb737655d5968d9fa3da Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Aug 2015 14:05:46 +0200 Subject: [PATCH 0987/1812] Remove code setting PcRace (Fixes #2886) This is already handled by the RaceCheck script. --- apps/openmw/mwworld/worldimp.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cdaa..7d4ab0c95d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -216,7 +216,6 @@ namespace MWWorld { // set new game mark mGlobalVariables["chargenstate"].setInteger (1); - mGlobalVariables["pcrace"].setInteger (3); } else mGlobalVariables["chargenstate"].setInteger (-1); @@ -1493,19 +1492,6 @@ namespace MWWorld if (Misc::StringUtils::ciEqual(record.mId, "player")) { - std::vector ids; - getStore().get().listIdentifier(ids); - - std::sort(ids.begin(), ids.end()); - - unsigned int i=0; - - for (; igetPlayer().get()->mBase; From bb54bbd2736d8440e639066bc459ec56173786de Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 24 Aug 2015 19:54:02 +1200 Subject: [PATCH 0988/1812] Pulled duplicated functions into common base class --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/creature.cpp | 70 ------------------------- apps/openmw/mwclass/creature.hpp | 22 +------- apps/openmw/mwclass/mobile.cpp | 87 ++++++++++++++++++++++++++++++++ apps/openmw/mwclass/mobile.hpp | 47 +++++++++++++++++ apps/openmw/mwclass/npc.cpp | 66 +----------------------- apps/openmw/mwclass/npc.hpp | 18 +------ 7 files changed, 140 insertions(+), 172 deletions(-) create mode 100644 apps/openmw/mwclass/mobile.cpp create mode 100644 apps/openmw/mwclass/mobile.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a0f9e8e13c..9054e53c90 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ff09282c1f..e14d9f8ba4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -156,11 +156,6 @@ namespace MWClass return ref->mBase->mId; } - void Creature::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -169,17 +164,6 @@ namespace MWClass objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } - void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - if(!model.empty()) - { - physics.addActor(ptr, model); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - MWBase::Environment::get().getMechanicsManager()->add(ptr); - } - std::string Creature::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = @@ -408,30 +392,6 @@ namespace MWClass } } - void Creature::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -499,11 +459,6 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } - bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - float Creature::getSpeed(const MWWorld::Ptr &ptr) const { MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -562,16 +517,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Creature::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - movement.mRotation[0] = 0.0f; - movement.mRotation[1] = 0.0f; - movement.mRotation[2] = 0.0f; - return vec; - } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -600,21 +545,6 @@ namespace MWClass return static_cast(stats.getAttribute(0).getModified() * 5); } - float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const - { - float weight = getContainerStore (ptr).getWeight(); - - const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); - weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); - weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); - - if (weight<0) - weight = 0; - - return weight; - } - - int Creature::getServices(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index b2a333beb3..3881c1d406 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public MWWorld::Class + class Creature : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -47,19 +47,10 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -68,8 +59,6 @@ namespace MWClass virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, @@ -92,10 +81,6 @@ namespace MWClass ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. - virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; - ///< 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 float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor @@ -111,9 +96,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - float getSpeed (const MWWorld::Ptr& ptr) const; static void registerSelf(); diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/mobile.cpp new file mode 100644 index 0000000000..9cd5510e2f --- /dev/null +++ b/apps/openmw/mwclass/mobile.cpp @@ -0,0 +1,87 @@ +#include "mobile.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" +#include "../mwmechanics/magiceffects.hpp" + +#include "../mwphysics/physicssystem.hpp" + +#include "../mwworld/inventorystore.hpp" + +namespace MWClass +{ + Mobile::Mobile() {} + + Mobile::~Mobile() {} + + void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); + } + + void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + { + if (!model.empty()) + { + physics.addActor(ptr, model); + if (getCreatureStats(ptr).isDead()) + MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); + } + MWBase::Environment::get().getMechanicsManager()->add(ptr); + } + + void Mobile::block(const MWWorld::Ptr &ptr) const + { + MWWorld::InventoryStore& inv = getInventoryStore(ptr); + MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if (shield == inv.end()) + return; + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + switch (shield->getClass().getEquipmentSkill(*shield)) + { + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; + } + } + + bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + { + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); + } + + osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; + } + + float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + { + float weight = getContainerStore(ptr).getWeight(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).getMagnitude(); + weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude(); + return (weight < 0) ? 0.0f : weight; + } +} diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/mobile.hpp new file mode 100644 index 0000000000..5b1eeae9d2 --- /dev/null +++ b/apps/openmw/mwclass/mobile.hpp @@ -0,0 +1,47 @@ +#ifndef GAME_MWCLASS_MOBILE_H +#define GAME_MWCLASS_MOBILE_H + +#include "../mwworld/class.hpp" + +namespace ESM +{ + struct GameSetting; +} + +namespace MWClass +{ + /// \brief Class holding functionality common to Creature and NPC + class Mobile : public MWWorld::Class + { + protected: + + Mobile(); + + public: + ~Mobile(); + + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; + ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying + + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + + virtual void block(const MWWorld::Ptr &ptr) const; + + virtual bool hasToolTip(const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + + virtual float getEncumbrance(const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + + // not implemented + Mobile(const Mobile&); + Mobile& operator= (const Mobile&); + }; +} + +#endif diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5f166b3e32..bd1579d9e6 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -402,24 +402,11 @@ namespace MWClass return ref->mBase->mId; } - void Npc::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getObjects().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - physics.addActor(ptr, model); - MWBase::Environment::get().getMechanicsManager()->add(ptr); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - bool Npc::isPersistent(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); @@ -756,30 +743,6 @@ namespace MWClass } } - void Npc::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -937,16 +900,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Npc::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - movement.mRotation[0] = 0.0f; - movement.mRotation[1] = 0.0f; - movement.mRotation[2] = 0.0f; - return vec; - } - bool Npc::isEssential (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -961,11 +914,6 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } - bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -996,21 +944,9 @@ namespace MWClass float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const { - const MWMechanics::NpcStats &stats = getNpcStats(ptr); - // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - float weight = 0.0f; - if(!stats.isWerewolf()) - { - weight = getContainerStore(ptr).getWeight(); - weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).getMagnitude(); - weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).getMagnitude(); - if(weight < 0.0f) - weight = 0.0f; - } - - return weight; + return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b12b7b13fb..16dd4f8bd3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public MWWorld::Class + class Npc : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -51,12 +51,6 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -70,9 +64,6 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -85,8 +76,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation @@ -103,9 +92,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. From cd5bef958f5fc163fd6609661a4e251e1ffb315c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 17 Aug 2015 20:32:23 -0500 Subject: [PATCH 0989/1812] Remove dead code from alchemywindow. Also align some braces. --- apps/openmw/mwgui/alchemywindow.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 60bd70c04f..d12c22e06d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,5 @@ #include "alchemywindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -67,9 +65,6 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - std::string name = mNameEdit->getCaption(); - boost::algorithm::trim(name); - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); if (result == MWMechanics::Alchemy::Result_NoName) @@ -118,7 +113,7 @@ namespace MWGui MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); if (ingred.getRefData().getCount() == 0) removeIngredient(mIngredients[i]); - } + } update(); } @@ -136,9 +131,6 @@ namespace MWGui mNameEdit->setCaption(""); int index = 0; - - mAlchemy->setAlchemist (MWMechanics::getPlayer()); - for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) { From 541d7fb4fb9db72ed30bdbebd9d59aa1b810886b Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 25 Aug 2015 18:19:16 +1200 Subject: [PATCH 0990/1812] Fixed assorted issues * destructor is virtual * renamed class to Actor * corrected indentation of case statement --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/{mobile.cpp => actor.cpp} | 40 +++++++++---------- apps/openmw/mwclass/{mobile.hpp => actor.hpp} | 10 ++--- apps/openmw/mwclass/creature.hpp | 4 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 4 +- 6 files changed, 31 insertions(+), 31 deletions(-) rename apps/openmw/mwclass/{mobile.cpp => actor.cpp} (68%) rename apps/openmw/mwclass/{mobile.hpp => actor.hpp} (89%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9054e53c90..2dd16a4e6c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/actor.cpp similarity index 68% rename from apps/openmw/mwclass/mobile.cpp rename to apps/openmw/mwclass/actor.cpp index 9cd5510e2f..d58047d06f 100644 --- a/apps/openmw/mwclass/mobile.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -1,4 +1,4 @@ -#include "mobile.hpp" +#include "actor.hpp" #include @@ -17,16 +17,16 @@ namespace MWClass { - Mobile::Mobile() {} + Actor::Actor() {} - Mobile::~Mobile() {} + Actor::~Actor() {} - void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + void Actor::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if (!model.empty()) { @@ -37,7 +37,7 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - void Mobile::block(const MWWorld::Ptr &ptr) const + void Actor::block(const MWWorld::Ptr &ptr) const { MWWorld::InventoryStore& inv = getInventoryStore(ptr); MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); @@ -47,26 +47,26 @@ namespace MWClass MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); switch (shield->getClass().getEquipmentSkill(*shield)) { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; } } - bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + bool Actor::hasToolTip(const MWWorld::Ptr& ptr) const { return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); } - osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); @@ -76,7 +76,7 @@ namespace MWClass return vec; } - float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + float Actor::getEncumbrance(const MWWorld::Ptr& ptr) const { float weight = getContainerStore(ptr).getWeight(); const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/actor.hpp similarity index 89% rename from apps/openmw/mwclass/mobile.hpp rename to apps/openmw/mwclass/actor.hpp index 5b1eeae9d2..3f795dff9d 100644 --- a/apps/openmw/mwclass/mobile.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -11,14 +11,14 @@ namespace ESM namespace MWClass { /// \brief Class holding functionality common to Creature and NPC - class Mobile : public MWWorld::Class + class Actor : public MWWorld::Class { protected: - Mobile(); + Actor(); public: - ~Mobile(); + virtual ~Actor(); virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load @@ -39,8 +39,8 @@ namespace MWClass /// effects). Throws an exception, if the object can't hold other objects. // not implemented - Mobile(const Mobile&); - Mobile& operator= (const Mobile&); + Actor(const Actor&); + Actor& operator= (const Actor&); }; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 3881c1d406..c4ea09255e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public Mobile + class Creature : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bd1579d9e6..9fa2cc6037 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -946,7 +946,7 @@ namespace MWClass { // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); + return getNpcStats(ptr).isWerewolf() ? 0.0f : Actor::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 16dd4f8bd3..d919131db9 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public Mobile + class Npc : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; From 40753aa9a3759e247b1fc907f5ef61af2656d533 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 08:43:03 +0200 Subject: [PATCH 0991/1812] simplifying merge stage --- apps/opencs/model/tools/mergestages.hpp | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index af7f06d606..c0ed167876 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -35,8 +35,6 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); - static const int stepSize = 1000; - public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -56,16 +54,7 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - const Collection& source = (mState.mSource.getData().*mAccessor)(); - - int size = source.getSize(); - - int steps = size / stepSize; - - if (size % stepSize) - ++steps; - - return steps; + return (mState.mSource.getData().*mAccessor)().getSize(); } template @@ -74,16 +63,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int begin = stage * stepSize; - int end = std::min ((stage+1) * stepSize, source.getSize()); + const CSMWorld::Record& record = source.getRecord (stage); - for (int i=begin; i& record = source.getRecord (i); - - if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); - } + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } } From 9cf793c0b519143fd7d3ac3cfb7beb82f65b72f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:39:43 +0200 Subject: [PATCH 0992/1812] silenced a warning --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2cff893891..0e2d4e7d1a 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) + mRunner (mProjectPath), mDirty (false), mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); From f95950e8d815997da34eb9939b81cd27afb62dbb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:54:16 +0200 Subject: [PATCH 0993/1812] merge referenceables table --- apps/opencs/model/tools/mergeoperation.cpp | 3 ++- apps/opencs/model/tools/mergestages.cpp | 14 ++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 ++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 5 +++++ apps/opencs/model/world/refidcollection.hpp | 1 + apps/opencs/model/world/refiddata.cpp | 11 +++++++++++ apps/opencs/model/world/refiddata.hpp | 6 ++---- 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index d010e343b7..0f128e86e9 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -34,8 +34,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); + appendStage (new MergeRefIdsStage (mState)); - /// \todo Referencables, References, Land, LandTextures + /// \todo References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 776808b269..d8bd93824c 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -39,3 +39,17 @@ void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& mState.mCompleted = true; } + + +CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeRefIdsStage::setup() +{ + return mState.mSource.getData().getReferenceables().getSize(); +} + +void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mSource.getData().getReferenceables().copyTo ( + stage, mState.mTarget->getData().getReferenceables()); +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index c0ed167876..308ebe1c35 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -68,6 +68,22 @@ namespace CSMTools if (!record.isDeleted()) target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } + + + class MergeRefIdsStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeRefIdsStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b46..c50f8c1f1f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -914,3 +914,8 @@ const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdap } throw std::runtime_error("No such column in the nestedadapters"); } + +void CSMWorld::RefIdCollection::copyTo (int index, RefIdCollection& target) const +{ + mData.copyTo (index, target.mData); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 4d511d12da..de5a709c6e 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -138,6 +138,7 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( + void copyTo (int index, RefIdCollection& target) const; }; } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f368..70d968efbd 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -358,3 +358,14 @@ void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::U mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), LocalIndex (iter->second->getSize()-1, type))); } + +void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const +{ + LocalIndex localIndex = globalToLocalIndex (index); + + RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second; + + std::string id = source->getId (localIndex.first); + + target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); +} diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 85d16a6eb2..4507f6028d 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -252,11 +252,9 @@ namespace CSMWorld const RefIdDataContainer& getProbes() const; const RefIdDataContainer& getRepairs() const; const RefIdDataContainer& getStatics() const; + + void copyTo (int index, RefIdData& target) const; }; } #endif - - - - From 845cafd61c12142a353119a6304845370037d7a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 12:40:40 +0200 Subject: [PATCH 0994/1812] fixed record state issues after merge --- apps/opencs/model/tools/mergestages.hpp | 2 +- apps/opencs/model/world/refiddata.cpp | 7 +++++-- apps/opencs/model/world/refiddata.hpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 308ebe1c35..5c2243d438 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -66,7 +66,7 @@ namespace CSMTools const CSMWorld::Record& record = source.getRecord (stage); if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 70d968efbd..14f580d39b 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -2,6 +2,7 @@ #include "refiddata.hpp" #include +#include #include @@ -345,7 +346,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati return mStatics; } -void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) +void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) { std::map::iterator iter = mRecordContainers.find (type); @@ -367,5 +368,7 @@ void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const std::string id = source->getId (localIndex.first); - target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); + std::auto_ptr newRecord (source->getRecord (localIndex.first).modifiedCopy()); + + target.insertRecord (*newRecord, localIndex.second, id); } diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 4507f6028d..8909ae4fb0 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -210,7 +210,8 @@ namespace CSMWorld void erase (int index, int count); - void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id); + void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, + const std::string& id); const RecordBase& getRecord (const LocalIndex& index) const; From a97a632aa76c3b7499ae170b689676d2f32b8550 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Aug 2015 17:21:24 +0200 Subject: [PATCH 0995/1812] merge references tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 34 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 18 +++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 0f128e86e9..f9a89aaa16 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -35,8 +35,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); + appendStage (new MergeReferencesStage (mState)); - /// \todo References, Land, LandTextures + /// \todo Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index d8bd93824c..80f16ec146 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include "mergestate.hpp" #include "../doc/document.hpp" @@ -53,3 +55,35 @@ void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) mState.mSource.getData().getReferenceables().copyTo ( stage, mState.mTarget->getData().getReferenceables()); } + + +CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state) +: mState (state) +{} + +int CSMTools::MergeReferencesStage::setup() +{ + mIndex.clear(); + return mState.mSource.getData().getReferences().getSize(); +} + +void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getReferences().getRecord (stage); + + if (!record.isDeleted()) + { + CSMWorld::CellRef ref = record.get(); + + ref.mOriginalCell = ref.mCell; + + ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++; + ref.mRefNum.mContentFile = 0; + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref); + + mState.mTarget->getData().getReferences().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 5c2243d438..e1cc17a3e6 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTAGES_H #include +#include #include @@ -69,7 +70,6 @@ namespace CSMTools target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } - class MergeRefIdsStage : public CSMDoc::Stage { MergeState& mState; @@ -84,6 +84,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeReferencesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map mIndex; + + public: + + MergeReferencesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From 54fa5273dc2d95f79368a82f815519b1c6d53fde Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 22:59:21 -0500 Subject: [PATCH 0996/1812] Refactor weather transitions to act more like MW Fixed several issues: * Waiting/jail time/training all now properly skip remaining transitions * ChangeWeather no longer permanently sets the region's weather * ChangeWeather being called during a transition now correctly queues up another transition * Corrected transition delta and factor calculations * ModRegion settings are now saved --- apps/essimporter/converter.hpp | 64 +- apps/openmw/engine.cpp | 3 +- apps/openmw/mwbase/world.hpp | 3 + apps/openmw/mwworld/weather.cpp | 1152 +++++++++++++++++------------- apps/openmw/mwworld/weather.hpp | 151 ++-- apps/openmw/mwworld/worldimp.cpp | 39 +- apps/openmw/mwworld/worldimp.hpp | 3 + components/esm/weatherstate.cpp | 131 ++-- components/esm/weatherstate.hpp | 63 +- 9 files changed, 890 insertions(+), 719 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index fb8fb8c9fd..4bad5e23b6 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -507,60 +507,40 @@ class ConvertGAME : public Converter public: ConvertGAME() : mHasGame(false) {} - std::string toString(int weatherId) - { - switch (weatherId) - { - case 0: - return "clear"; - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - case -1: - return ""; - default: - { - std::stringstream error; - error << "unknown weather id: " << weatherId; - throw std::runtime_error(error.str()); - } - } - } - virtual void read(ESM::ESMReader &esm) { mGame.load(esm); mHasGame = true; } + int validateWeatherID(int weatherID) + { + if(weatherID >= -1 && weatherID < 10) + { + return weatherID; + } + else + { + std::stringstream error; + error << "Invalid weather ID:" << weatherID << std::endl; + throw std::runtime_error(error.str()); + } + } + virtual void write(ESM::ESMWriter &esm) { if (!mHasGame) return; esm.startRecord(ESM::REC_WTHR); ESM::WeatherState weather; - weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); - weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); - weather.mHour = mContext->mHour; - weather.mWindSpeed = 0.f; - weather.mTimePassed = 0.0; - weather.mFirstUpdate = false; + weather.mTimePassed = 0.0f; + weather.mFastForward = false; + weather.mWeatherUpdateTime = mGame.mGMDT.mTimeOfNextTransition - mContext->mHour; + weather.mTransitionFactor = 1 - (mGame.mGMDT.mWeatherTransition / 100.0f); + weather.mCurrentWeather = validateWeatherID(mGame.mGMDT.mCurrentWeather); + weather.mNextWeather = validateWeatherID(mGame.mGMDT.mNextWeather); + weather.mQueuedWeather = -1; + // TODO: Determine how ModRegion modifiers are saved in Morrowind. weather.save(esm); esm.endRecord(ESM::REC_WTHR); } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e183107ec0..6c95700b37 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,8 +128,7 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTime( - frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTimeByFrame(frametime); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d345cdf7e2..6363703425 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -188,6 +188,9 @@ namespace MWBase virtual void advanceTime (double hours) = 0; ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime) = 0; + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cc5b726afe..8799ae57cc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -28,6 +28,8 @@ using namespace MWWorld; namespace { + static const int invalidWeatherID = -1; + float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; @@ -87,12 +89,11 @@ Max Raindrops=650 ? */ } -float Weather::transitionSeconds() const +float Weather::transitionDelta() const { - // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds - // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. - static const float deltasPerHour = 0.00835; - return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; + // Transition Delta describes how quickly transitioning to the weather in question will take, in Hz. Note that the + // measurement is in real time, not in-game time. + return mTransitionDelta; } float Weather::cloudBlendFactor(float transitionRatio) const @@ -101,6 +102,89 @@ float Weather::cloudBlendFactor(float transitionRatio) const return transitionRatio / mCloudsMaximumPercent; } +RegionWeather::RegionWeather(const ESM::Region& region) + : mWeather(invalidWeatherID) + , mChances() +{ + mChances.reserve(10); + mChances.push_back(region.mData.mClear); + mChances.push_back(region.mData.mCloudy); + mChances.push_back(region.mData.mFoggy); + mChances.push_back(region.mData.mOvercast); + mChances.push_back(region.mData.mRain); + mChances.push_back(region.mData.mThunder); + mChances.push_back(region.mData.mAsh); + mChances.push_back(region.mData.mBlight); + mChances.push_back(region.mData.mA); + mChances.push_back(region.mData.mB); +} + +RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) + : mWeather(state.mWeather) + , mChances(state.mChances) +{ +} + +RegionWeather::operator ESM::RegionWeatherState() const +{ + return ESM::RegionWeatherState { mWeather, mChances }; +} + +void RegionWeather::setChances(const std::vector& chances) +{ + if(mChances.size() < chances.size()) + { + mChances.reserve(chances.size()); + } + + std::vector::const_iterator it = chances.begin(); + for(size_t i = 0; it != chances.end(); ++it, ++i) + { + mChances[i] = *it; + } + + // Regional weather no longer supports the current type, select a new weather pattern. + if((static_cast(mWeather) >= mChances.size()) || (mChances[mWeather] == 0)) + { + chooseNewWeather(); + } +} + +void RegionWeather::setWeather(int weatherID) +{ + mWeather = weatherID; +} + +int RegionWeather::getWeather() +{ + // If the region weather was already set (by ChangeWeather, or by a previous call) then just return that value. + // Note that the region weather will be expired periodically when the weather update timer expires. + if(mWeather == invalidWeatherID) + { + chooseNewWeather(); + } + + return mWeather; +} + +void RegionWeather::chooseNewWeather() +{ + // All probabilities must add to 100 (responsibility of the user). + // If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30 + // and 70% will be greater than 30 (in theory). + int chance = Misc::Rng::rollDice(100) + 1; // 1..100 + int sum = 0; + int i = 0; + for(; static_cast(i) < mChances.size(); ++i) + { + sum += mChances[i]; + if(chance <= sum) + break; + } + + mWeather = i; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -118,22 +202,22 @@ MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const +MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const { - float rotationFromHorizon = angle(daysPassed, gameHour); + float rotationFromHorizon = angle(gameTime); MWRender::MoonState state = - { - rotationFromHorizon, - mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed, gameHour)), - shadowBlend(rotationFromHorizon), - earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) - }; + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(gameTime)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameTime.getHour()) + }; return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const +inline float MoonModel::angle(const TimeStamp& gameTime) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -142,25 +226,25 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const // 1. Moon rises and then sets in one day. // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). // 3. Moon sets and then rises in one day. - float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseHourToday = moonRiseHour(gameTime.getDay()); float moonRiseAngleToday = 0; - if(gameHour < moonRiseHourToday) + if(gameTime.getHour() < moonRiseHourToday) { - float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + float moonRiseHourYesterday = moonRiseHour(gameTime.getDay() - 1); if(moonRiseHourYesterday < 24) { float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); if(moonRiseAngleYesterday < 180) { // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. - moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + moonRiseAngleToday = rotation(gameTime.getHour()) + moonRiseAngleYesterday; } } } else { - moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + moonRiseAngleToday = rotation(gameTime.getHour() - moonRiseHourToday); } if(moonRiseAngleToday >= 180) @@ -194,17 +278,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const +inline unsigned int MoonModel::phase(const TimeStamp& gameTime) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). // If the moon didn't rise yet today, use yesterday's moon phase. - if(gameHour < moonRiseHour(daysPassed)) - return (daysPassed / 3) % 8; + if(gameTime.getHour() < moonRiseHour(gameTime.getDay())) + return (gameTime.getDay() / 3) % 8; else - return ((daysPassed + 1) / 3) % 8; + return ((gameTime.getDay() + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -270,51 +354,68 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), - mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), - mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), - mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) +WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWorld::Fallback& fallback, MWWorld::ESMStore& store) + : mStore(store) + , mRendering(rendering) + , mSunriseTime(fallback.getFallbackFloat("Weather_Sunrise_Time")) + , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) + , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) + , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mNightStart(mSunsetTime + mSunsetDuration) + , mNightEnd(mSunriseTime - 0.5f) + , mDayStart(mSunriseTime + mSunriseDuration) + , mDayEnd(mSunsetTime) + , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) + , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mWeatherSettings() + , mMasser("Masser", fallback) + , mSecunda("Secunda", fallback) + , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) + , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) + , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) + , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) + , mWindSpeed(0.f) + , mIsStorm(false) + , mStormDirection(0,1,0) + , mThunderSoundDelay(0.25) + , mThunderFlash(0) + , mThunderChance(0) + , mThunderChanceNeeded(50) + , mCurrentRegion() + , mTimePassed(0) + , mFastForward(false) + , mWeatherUpdateTime(mHoursBetweenWeatherChanges) + , mTransitionFactor(0) + , mCurrentWeather(0) + , mNextWeather(0) + , mQueuedWeather(0) + , mRegions() + , mResult() + , mAmbientSound() + , mPlayingSoundID() { - //Globals - mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; + mWeatherSettings.reserve(10); + addWeather("Clear", fallback); + addWeather("Cloudy", fallback); + addWeather("Foggy", fallback); + addWeather("Overcast", fallback); + addWeather("Rain", fallback, "rain"); + addWeather("Thunderstorm", fallback, "rain heavy"); + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); - mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); + Store::iterator it = store.get().begin(); + for(; it != store.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } - //Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ - mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5f; - mDayStart = mSunriseTime + mSunriseDuration; - mDayEnd = mSunsetTime; - - addWeather("Clear", *fallback); - addWeather("Cloudy", *fallback); - addWeather("Foggy", *fallback); - addWeather("Overcast", *fallback); - addWeather("Rain", *fallback, "rain"); - addWeather("Thunderstorm", *fallback, "rain heavy"); - addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", *fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); + forceWeather(0); } WeatherManager::~WeatherManager() @@ -322,250 +423,127 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const std::string& weather, bool instant) +void WeatherManager::changeWeather(const std::string& regionID, const unsigned int weatherID) { - if (weather == mCurrentWeather && mNextWeather == "") - { - mFirstUpdate = false; - return; - } + // In Morrowind, this seems to have the following behavior, when applied to the current region: + // - When there is no transition in progress, start transitioning to the new weather. + // - If there is a transition in progress, queue up the transition and process it when the current one completes. + // - If there is a transition in progress, and a queued transition, overwrite the queued transition. + // - If multiple calls to ChangeWeather are made while paused (console up), only the last call will be used, + // meaning that if there was no transition in progress, only the last ChangeWeather will be processed. + // If the region isn't current, Morrowind will store the new weather for the region in question. - if (instant || mFirstUpdate) + if(weatherID < mWeatherSettings.size()) { - mNextWeather = ""; - mCurrentWeather = weather; - } - else - { - if (mNextWeather != "") + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - // transition more than 50% finished? - if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) - mCurrentWeather = mNextWeather; - } - - mNextWeather = weather; - mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); - } - mFirstUpdate = false; -} - -void WeatherManager::setResult(const std::string& weatherType) -{ - const Weather& current = findWeather(weatherType); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mCloudBlendFactor = 0; - mResult.mWindSpeed = current.mWindSpeed; - mResult.mCloudSpeed = current.mCloudSpeed; - mResult.mGlareView = current.mGlareView; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - mResult.mAmbientSoundVolume = 1.f; - mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; - - mResult.mIsStorm = current.mIsStorm; - - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - - mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); - - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - - // night - if (mHour <= mNightEnd || mHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (mHour >= mNightEnd && mHour <= mDayStart + 1) - { - if (mHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - mHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (mHour >= 6) - { - // fade out - float advance = mHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); - } - } - - // day - else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (mHour >= mDayEnd - 1 && mHour <= mNightStart + 1) - { - if (mHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - mHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (mHour >= 19) - { - // fade out - float advance = mHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; + it->second.setWeather(weatherID); + regionalWeatherChanged(it->first, it->second); } } } -void WeatherManager::transition(float factor) +void WeatherManager::modRegion(const std::string& regionID, const std::vector& chances) { - setResult(mCurrentWeather); - const MWRender::WeatherResult current = mResult; - setResult(mNextWeather); - const MWRender::WeatherResult other = mResult; + // Sets the region's probability for various weather patterns. Note that this appears to be saved permanently. + // In Morrowind, this seems to have the following behavior when applied to the current region: + // - If the region supports the current weather, no change in current weather occurs. + // - If the region no longer supports the current weather, and there is no transition in progress, begin to + // transition to a new supported weather type. + // - If the region no longer supports the current weather, and there is a transition in progress, queue a + // transition to a new supported weather type. - const Weather& nextWeather = findWeather(mNextWeather); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); - - mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); - mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); - mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - - mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); - mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); - mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); - mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); - mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); - mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); - - mResult.mNight = current.mNight; - - if (factor < 0.5) + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - mResult.mIsStorm = current.mIsStorm; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - mResult.mAmbientSoundVolume = 1-(factor*2); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + it->second.setChances(chances); + regionalWeatherChanged(it->first, it->second); } - else +} + +void WeatherManager::playerTeleported() +{ + // If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to + // be changed immediately, and any transitions for the previous region discarded. + MWBase::World* world = MWBase::Environment::get().getWorld(); + if(world->isCellExterior() || world->isCellQuasiExterior()) { - mResult.mIsStorm = other.mIsStorm; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainEffect = other.mRainEffect; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainSpeed = other.mRainSpeed; - mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5f); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); + std::map::iterator it = mRegions.find(playerRegion); + if(it != mRegions.end() && playerRegion != mCurrentRegion) + { + mCurrentRegion = playerRegion; + forceWeather(it->second.getWeather()); + } } } void WeatherManager::update(float duration, bool paused) { - float timePassed = static_cast(mTimePassed); - mTimePassed = 0; + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::World& world = *MWBase::Environment::get().getWorld(); + TimeStamp time = world.getTimeStamp(); - mWeatherUpdateTime -= timePassed; - - MWBase::World* world = MWBase::Environment::get().getWorld(); - const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); - if (!exterior) + if(!paused) { - mRendering->setSkyEnabled(false); + // Add new transitions when either the player's current external region changes. + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(updateWeatherTime() || updateWeatherRegion(playerRegion)) + { + std::map::iterator it = mRegions.find(mCurrentRegion); + if(it != mRegions.end()) + { + addWeatherTransition(it->second.getWeather()); + } + } + + updateWeatherTransitions(duration); + } + + const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior()); + if(!exterior) + { + mRendering.setSkyEnabled(false); //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - switchToNextWeather(false); - - if (mNextWeather != "") - { - mRemainingTransitionTime -= timePassed; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); - else - setResult(mCurrentWeather); + calculateWeatherResult(time.getHour()); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; if (mIsStorm) { - MWWorld::Ptr player = world->getPlayerPtr(); osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); osg::Vec3f redMountainPos (19950, 72032, 27831); mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; mStormDirection.normalize(); - mRendering->getSkyManager()->setStormDirection(mStormDirection); + mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); + if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + mRendering.getSkyManager()->sunDisable(); else - mRendering->getSkyManager()->sunEnable(); + mRendering.getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart // mark when the sun is level with the horizon. { // Shift times into a 24-hour window beginning at mSunriseTime... - float adjustedHour = mHour; + float adjustedHour = time.getHour(); float adjustedNightStart = mNightStart; - if ( mHour < mSunriseTime ) + if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; if ( mNightStart < mSunriseTime ) adjustedNightStart += 24.f; @@ -585,16 +563,15 @@ void WeatherManager::update(float duration, bool paused) static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final * -1 ); + mRendering.setSunDirection( final * -1 ); } - TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); - mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); - mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); + mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); if (!paused) { - if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + if(mCurrentWeather == 5 && !inTransition()) { if (mThunderFlash > 0) { @@ -641,12 +618,11 @@ void WeatherManager::update(float duration, bool paused) //else //mRendering->getSkyManager()->setLightningStrength(0.f); } - - mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->setSunColour(mResult.mSunColor); + mRendering.setAmbientColour(mResult.mAmbientColor); + mRendering.setSunColour(mResult.mSunColor); - mRendering->getSkyManager()->setWeather(mResult); + mRendering.getSkyManager()->setWeather(mResult); // Play sounds if (mPlayingSoundID != mResult.mAmbientLoopSoundID) @@ -671,250 +647,11 @@ void WeatherManager::stopSounds() } } -std::string WeatherManager::nextWeather(const ESM::Region* region) const -{ - std::vector probability; - - RegionModMap::const_iterator iter = mRegionMods.find(Misc::StringUtils::lowerCase(region->mId)); - if(iter != mRegionMods.end()) - probability = iter->second; - else - { - probability.reserve(10); - probability.push_back(region->mData.mClear); - probability.push_back(region->mData.mCloudy); - probability.push_back(region->mData.mFoggy); - probability.push_back(region->mData.mOvercast); - probability.push_back(region->mData.mRain); - probability.push_back(region->mData.mThunder); - probability.push_back(region->mData.mAsh); - probability.push_back(region->mData.mBlight); - probability.push_back(region->mData.mA); - probability.push_back(region->mData.mB); - } - - /* - * All probabilities must add to 100 (responsibility of the user). - * If chances A and B has values 30 and 70 then by generating - * 100 numbers 1..100, 30% will be lesser or equal 30 and - * 70% will be greater than 30 (in theory). - */ - - int chance = Misc::Rng::rollDice(100) + 1; // 1..100 - int sum = 0; - unsigned int i = 0; - for (; i < probability.size(); ++i) - { - sum += probability[i]; - if (chance < sum) - break; - } - - switch (i) - { - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - default: // case 0 - return "clear"; - } -} - -void WeatherManager::setHour(const float hour) -{ - mHour = hour; -} - -unsigned int WeatherManager::getWeatherID() const -{ - // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather - - if (mCurrentWeather == "clear") - return 0; - else if (mCurrentWeather == "cloudy") - return 1; - else if (mCurrentWeather == "foggy") - return 2; - else if (mCurrentWeather == "overcast") - return 3; - else if (mCurrentWeather == "rain") - return 4; - else if (mCurrentWeather == "thunderstorm") - return 5; - else if (mCurrentWeather == "ashstorm") - return 6; - else if (mCurrentWeather == "blight") - return 7; - else if (mCurrentWeather == "snow") - return 8; - else if (mCurrentWeather == "blizzard") - return 9; - - else - return 0; -} - -void WeatherManager::changeWeather(const std::string& region, const unsigned int id) -{ - // make sure this region exists - MWBase::Environment::get().getWorld()->getStore().get().find(region); - - std::string weather; - if (id==0) - weather = "clear"; - else if (id==1) - weather = "cloudy"; - else if (id==2) - weather = "foggy"; - else if (id==3) - weather = "overcast"; - else if (id==4) - weather = "rain"; - else if (id==5) - weather = "thunderstorm"; - else if (id==6) - weather = "ashstorm"; - else if (id==7) - weather = "blight"; - else if (id==8) - weather = "snow"; - else if (id==9) - weather = "blizzard"; - else - weather = "clear"; - - mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; - - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.isInCell()) - { - std::string playerRegion = player.getCell()->getCell()->mRegion; - if (Misc::StringUtils::ciEqual(region, playerRegion)) - setWeather(weather); - } -} - -void WeatherManager::modRegion(const std::string ®ionid, const std::vector &chances) -{ - mRegionMods[Misc::StringUtils::lowerCase(regionid)] = chances; - // Start transitioning right away if the region no longer supports the current weather type - unsigned int current = getWeatherID(); - if(current >= chances.size() || chances[current] == 0) - mWeatherUpdateTime = 0.0f; -} - float WeatherManager::getWindSpeed() const { return mWindSpeed; } -bool WeatherManager::isDark() const -{ - bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() - || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1); -} - -void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) -{ - ESM::WeatherState state; - state.mHour = mHour; - state.mWindSpeed = mWindSpeed; - state.mCurrentWeather = mCurrentWeather; - state.mNextWeather = mNextWeather; - state.mCurrentRegion = mCurrentRegion; - state.mFirstUpdate = mFirstUpdate; - state.mRemainingTransitionTime = mRemainingTransitionTime; - state.mTimePassed = mTimePassed; - - writer.startRecord(ESM::REC_WTHR); - state.save(writer); - writer.endRecord(ESM::REC_WTHR); -} - -bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) -{ - if(ESM::REC_WTHR == type) - { - // load first so that if it fails, we haven't accidentally reset the state below - ESM::WeatherState state; - state.load(reader); - - // swap in the loaded values now that we can't fail - mHour = state.mHour; - mWindSpeed = state.mWindSpeed; - mCurrentWeather.swap(state.mCurrentWeather); - mNextWeather.swap(state.mNextWeather); - mCurrentRegion.swap(state.mCurrentRegion); - mFirstUpdate = state.mFirstUpdate; - mRemainingTransitionTime = state.mRemainingTransitionTime; - mTimePassed = state.mTimePassed; - - return true; - } - - return false; -} - -void WeatherManager::clear() -{ - stopSounds(); - mRegionOverrides.clear(); - mRegionMods.clear(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; -} - -void WeatherManager::switchToNextWeather(bool instantly) -{ - MWBase::World* world = MWBase::Environment::get().getWorld(); - if (world->isCellExterior() || world->isCellQuasiExterior()) - { - std::string regionstr = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - - std::string weatherType = "clear"; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - { - weatherType = mRegionOverrides[regionstr]; - } - else - { - // get weather probabilities for the current region - const ESM::Region *region = world->getStore().get().search (regionstr); - - if (region != 0) - { - weatherType = nextWeather(region); - } - } - - setWeather(weatherType, instantly); - } - } -} - bool WeatherManager::isInStorm() const { return mIsStorm; @@ -927,7 +664,106 @@ osg::Vec3f WeatherManager::getStormDirection() const void WeatherManager::advanceTime(double hours) { - mTimePassed += hours*3600; + // This is called when the player sleeps/waits, serves jail time, travels, or trains. + // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of + // whatever transition time might have been remaining. + mTimePassed += hours; + mFastForward = true; +} + +void WeatherManager::advanceTimeByFrame(double hours) +{ + // Called when time is advanced by an incremental update for each frame. + mTimePassed += hours; +} + +unsigned int WeatherManager::getWeatherID() const +{ + return mCurrentWeather; +} + +bool WeatherManager::isDark() const +{ + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() + || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); +} + +void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) +{ + ESM::WeatherState state; + state.mCurrentRegion = mCurrentRegion; + state.mTimePassed = mTimePassed; + state.mFastForward = mFastForward; + state.mWeatherUpdateTime = mWeatherUpdateTime; + state.mTransitionFactor = mTransitionFactor; + state.mCurrentWeather = mCurrentWeather; + state.mNextWeather = mNextWeather; + state.mQueuedWeather = mQueuedWeather; + + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + } + + writer.startRecord(ESM::REC_WTHR); + state.save(writer); + writer.endRecord(ESM::REC_WTHR); +} + +bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) +{ + if(ESM::REC_WTHR == type) + { + ESM::WeatherState state; + state.load(reader); + + mCurrentRegion.swap(state.mCurrentRegion); + mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) + { + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } + } + + return true; + } + + return false; +} + +void WeatherManager::clear() +{ + stopSounds(); + + mThunderFlash = 0.0; + mThunderChance = 0.0; + mThunderChanceNeeded = 50.0; + + mCurrentRegion = ""; + mTimePassed = 0.0f; + mWeatherUpdateTime = 0.0f; + forceWeather(0); + mRegions.clear(); + importRegions(); } inline void WeatherManager::addWeather(const std::string& name, @@ -935,17 +771,301 @@ inline void WeatherManager::addWeather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) { - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); - std::string lower = name; - lower[0] = tolower(lower[0]); - mWeatherSettings.insert(std::make_pair(lower, weather)); + mWeatherSettings.push_back(weather); } -inline Weather& WeatherManager::findWeather(const std::string& name) +inline void WeatherManager::importRegions() { - return mWeatherSettings.at(name); + Store::iterator it = mStore.get().begin(); + for(; it != mStore.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } +} + +inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region) +{ + // If the region is current, then add a weather transition for it. + MWWorld::Ptr player = MWMechanics::getPlayer(); + if(player.isInCell()) + { + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(!playerRegion.empty() && (playerRegion == regionID)) + { + addWeatherTransition(region.getWeather()); + } + } +} + +inline bool WeatherManager::updateWeatherTime() +{ + mWeatherUpdateTime -= mTimePassed; + mTimePassed = 0.0f; + if(mWeatherUpdateTime <= 0.0f) + { + // Expire all regional weather, so that any call to getWeather() will return a new weather ID. + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + it->second.setWeather(invalidWeatherID); + } + + mWeatherUpdateTime += mHoursBetweenWeatherChanges; + + return true; + } + + return false; +} + +inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion) +{ + if(!playerRegion.empty() && playerRegion != mCurrentRegion) + { + mCurrentRegion = playerRegion; + + return true; + } + + return false; +} + +inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeconds) +{ + // When a player chooses to train, wait, or serves jail time, any transitions will be fast forwarded to the last + // weather type set, regardless of the remaining transition time. + if(!mFastForward && inTransition()) + { + const float delta = mWeatherSettings[mNextWeather].transitionDelta(); + mTransitionFactor -= elapsedRealSeconds * delta; + if(mTransitionFactor <= 0.0f) + { + mCurrentWeather = mNextWeather; + mNextWeather = mQueuedWeather; + mQueuedWeather = invalidWeatherID; + + // We may have begun processing the queued transition, so we need to apply the remaining time towards it. + if(inTransition()) + { + const float newDelta = mWeatherSettings[mNextWeather].transitionDelta(); + const float remainingSeconds = -(mTransitionFactor / delta); + mTransitionFactor = 1.0f - (remainingSeconds * newDelta); + } + else + { + mTransitionFactor = 0.0f; + } + } + } + else + { + if(mQueuedWeather != invalidWeatherID) + { + mCurrentWeather = mQueuedWeather; + } + else if(mNextWeather != invalidWeatherID) + { + mCurrentWeather = mNextWeather; + } + + mFastForward = false; + } +} + +inline void WeatherManager::forceWeather(const int weatherID) +{ + mTransitionFactor = 0.0f; + mCurrentWeather = weatherID; + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; +} + +inline bool WeatherManager::inTransition() +{ + return mNextWeather != invalidWeatherID; +} + +inline void WeatherManager::addWeatherTransition(const int weatherID) +{ + // In order to work like ChangeWeather expects, this method begins transitioning to the new weather immediately if + // no transition is in progress, otherwise it queues it to be transitioned. + + assert(weatherID >= 0 && static_cast(weatherID) < mWeatherSettings.size()); + + if(!inTransition() && (weatherID != mCurrentWeather)) + { + mNextWeather = weatherID; + mTransitionFactor = 1.0f; + } + else if(inTransition() && (weatherID != mNextWeather)) + { + mQueuedWeather = weatherID; + } +} + +inline void WeatherManager::calculateWeatherResult(const float gameHour) +{ + if(!inTransition()) + { + calculateResult(mCurrentWeather, gameHour); + } + else + { + calculateTransitionResult(1 - mTransitionFactor, gameHour); + } +} + +inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) +{ + const Weather& current = mWeatherSettings[weatherID]; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mCloudBlendFactor = 0; + mResult.mWindSpeed = current.mWindSpeed; + mResult.mCloudSpeed = current.mCloudSpeed; + mResult.mGlareView = current.mGlareView; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mAmbientSoundVolume = 1.f; + mResult.mEffectFade = 1.f; + mResult.mSunColor = current.mSunDiscSunsetColor; + + mResult.mIsStorm = current.mIsStorm; + + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + + mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + + mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + { + mResult.mFogColor = current.mFogNightColor; + mResult.mAmbientColor = current.mAmbientNightColor; + mResult.mSunColor = current.mSunNightColor; + mResult.mSkyColor = current.mSkyNightColor; + mResult.mNightFade = 1.f; + } + + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + } + } + + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + { + mResult.mFogColor = current.mFogDayColor; + mResult.mAmbientColor = current.mAmbientDayColor; + mResult.mSunColor = current.mSunDayColor; + mResult.mSkyColor = current.mSkyDayColor; + } + + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + } +} + +inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) +{ + calculateResult(mCurrentWeather, gameHour); + const MWRender::WeatherResult current = mResult; + calculateResult(mNextWeather, gameHour); + const MWRender::WeatherResult other = mResult; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mNextCloudTexture = other.mCloudTexture; + mResult.mCloudBlendFactor = mWeatherSettings[mNextWeather].cloudBlendFactor(factor); + + mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); + + mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); + + mResult.mNight = current.mNight; + + if(factor < 0.5) + { + mResult.mIsStorm = current.mIsStorm; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + mResult.mAmbientSoundVolume = 1-(factor*2); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + } + else + { + mResult.mIsStorm = other.mIsStorm; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainEffect = other.mRainEffect; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainSpeed = other.mRainSpeed; + mResult.mRainFrequency = other.mRainFrequency; + mResult.mAmbientSoundVolume = 2*(factor-0.5f); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 710e45d9b6..d07e7e1e40 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -14,6 +14,7 @@ namespace ESM { struct Region; + struct RegionWeatherState; class ESMWriter; class ESMReader; } @@ -31,6 +32,7 @@ namespace Loading namespace MWWorld { class Fallback; + class TimeStamp; /// Defines a single weather setting (according to INI) class Weather @@ -110,7 +112,7 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - float transitionSeconds() const; + float transitionDelta() const; float cloudBlendFactor(float transitionRatio) const; private: @@ -118,12 +120,35 @@ namespace MWWorld float mCloudsMaximumPercent; }; + /// A class for storing a region's weather. + class RegionWeather + { + public: + explicit RegionWeather(const ESM::Region& region); + explicit RegionWeather(const ESM::RegionWeatherState& state); + + explicit operator ESM::RegionWeatherState() const; + + void setChances(const std::vector& chances); + + void setWeather(int weatherID); + + int getWeather(); + + private: + int mWeather; + std::vector mChances; + + void chooseNewWeather(); + }; + + /// A class that acts as a model for the moons. class MoonModel { public: MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; + MWRender::MoonState calculateState(const TimeStamp& gameTime) const; private: float mFadeInStart; @@ -137,23 +162,23 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour) const; + float angle(const TimeStamp& gameTime) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed, float gameHour) const; + unsigned int phase(const TimeStamp& gameTime) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; }; - /// /// Interface for weather settings - /// class WeatherManager { public: // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time - WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); + WeatherManager(MWRender::RenderingManager& rendering, + const MWWorld::Fallback& fallback, + MWWorld::ESMStore& store); ~WeatherManager(); /** @@ -161,8 +186,9 @@ namespace MWWorld * @param region that should be changed * @param ID of the weather setting to shift to */ - void changeWeather(const std::string& region, const unsigned int id); - void switchToNextWeather(bool instantly = true); + void changeWeather(const std::string& regionID, const unsigned int weatherID); + void modRegion(const std::string& regionID, const std::vector& chances); + void playerTeleported(); /** * Per-frame update @@ -173,8 +199,6 @@ namespace MWWorld void stopSounds(); - void setHour(const float hour); - float getWindSpeed() const; /// Are we in an ash or blight storm? @@ -183,11 +207,10 @@ namespace MWWorld osg::Vec3f getStormDirection() const; void advanceTime(double hours); + void advanceTimeByFrame(double hours); unsigned int getWeatherID() const; - void modRegion(const std::string ®ionid, const std::vector &chances); - /// @see World::isDark bool isDark() const; @@ -198,73 +221,77 @@ namespace MWWorld void clear(); private: - float mHour; - float mWindSpeed; - bool mIsStorm; - osg::Vec3f mStormDirection; - - MWBase::SoundPtr mAmbientSound; - std::string mPlayingSoundID; - - MWWorld::ESMStore* mStore; - MWRender::RenderingManager* mRendering; - - std::map mWeatherSettings; - - std::map mRegionOverrides; - - std::string mCurrentWeather; - std::string mNextWeather; - - std::string mCurrentRegion; - - bool mFirstUpdate; - - float mRemainingTransitionTime; - - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - - double mTimePassed; // time passed since last update - - void transition(const float factor); - void setResult(const std::string& weatherType); - - void setWeather(const std::string& weatherType, bool instant=false); - std::string nextWeather(const ESM::Region* region) const; - MWRender::WeatherResult mResult; - - typedef std::map > RegionModMap; - RegionModMap mRegionMods; - - float mRainSpeed; + MWWorld::ESMStore& mStore; + MWRender::RenderingManager& mRendering; float mSunriseTime; float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - float mWeatherUpdateTime; - float mHoursBetweenWeatherChanges; - float mThunderFrequency; - float mThunderThreshold; - float mThunderSoundDelay; + // Some useful values + /* TODO: Use pre-sunrise_time, pre-sunset_time, + * post-sunrise_time, and post-sunset_time to better + * describe sunrise/sunset time. + * These values are fallbacks attached to weather. + */ float mNightStart; float mNightEnd; float mDayStart; float mDayEnd; + float mHoursBetweenWeatherChanges; + float mRainSpeed; + std::vector mWeatherSettings; + MoonModel mMasser; + MoonModel mSecunda; + + float mThunderFrequency; + float mThunderThreshold; std::string mThunderSoundID0; std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; - MoonModel mMasser; - MoonModel mSecunda; + + float mWindSpeed; + bool mIsStorm; + osg::Vec3f mStormDirection; + + float mThunderSoundDelay; + float mThunderFlash; + float mThunderChance; + float mThunderChanceNeeded; + + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + MWRender::WeatherResult mResult; + + MWBase::SoundPtr mAmbientSound; + std::string mPlayingSoundID; void addWeather(const std::string& name, const MWWorld::Fallback& fallback, const std::string& ambientLoopSoundID = "", const std::string& particleEffect = ""); - Weather& findWeather(const std::string& name); + void importRegions(); + + void regionalWeatherChanged(const std::string& regionID, RegionWeather& region); + bool updateWeatherTime(); + bool updateWeatherRegion(const std::string& playerRegion); + void updateWeatherTransitions(const float elapsedRealSeconds); + void forceWeather(const int weatherID); + + bool inTransition(); + void addWeatherTransition(const int weatherID); + + void calculateWeatherResult(const float gameHour); + void calculateResult(const int weatherID, const float gameHour); + void calculateTransitionResult(const float factor, const float gameHour); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cdaa..56c7415a2d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -193,7 +193,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); mWorldScene = new Scene(*mRendering, mPhysics); } @@ -212,6 +212,11 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->updatePlayer(); + // we don't want old weather to persist on a new game + // Note that if reset later, the initial ChangeWeather that the chargen script calls will be lost. + delete mWeatherManager; + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); + if (!bypass) { // set new game mark @@ -265,11 +270,6 @@ namespace MWWorld if (!mPhysics->toggleCollisionMode()) mPhysics->toggleCollisionMode(); - // we don't want old weather to persist on a new game - delete mWeatherManager; - mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); - if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); } @@ -804,6 +804,25 @@ namespace MWWorld days + mGlobalVariables["dayspassed"].getInteger()); } + void World::advanceTimeByFrame (double frametime) + { + double hours = (frametime * getTimeScaleFactor()) / 3600.0; + + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); + + mWeatherManager->advanceTimeByFrame (hours); + + hours += mGlobalVariables["gamehour"].getFloat(); + + setHour (hours); + + int days = static_cast(hours / 24); + + if (days>0) + mGlobalVariables["dayspassed"].setInteger ( + days + mGlobalVariables["dayspassed"].getInteger()); + } + void World::setHour (double hour) { if (hour<0) @@ -815,8 +834,6 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - mWeatherManager->setHour(static_cast(hour)); - if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); } @@ -2888,15 +2905,15 @@ namespace MWWorld MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); } - + void World::updateWeather(float duration, bool paused) { if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->switchToNextWeather(true); + mWeatherManager->playerTeleported(); } - + mWeatherManager->update(duration, paused); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 35e4335492..80fe6d850b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -277,6 +277,9 @@ namespace MWWorld virtual void advanceTime (double hours); ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime); + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour); ///< Set in-game time hour. diff --git a/components/esm/weatherstate.cpp b/components/esm/weatherstate.cpp index 48cf55a600..ff2528e58f 100644 --- a/components/esm/weatherstate.cpp +++ b/components/esm/weatherstate.cpp @@ -1,59 +1,72 @@ -#include "weatherstate.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace -{ - const char* hourRecord = "HOUR"; - const char* windSpeedRecord = "WNSP"; - const char* currentWeatherRecord = "CWTH"; - const char* nextWeatherRecord = "NWTH"; - const char* currentRegionRecord = "CREG"; - const char* firstUpdateRecord = "FUPD"; - const char* remainingTransitionTimeRecord = "RTTM"; - const char* timePassedRecord = "TMPS"; -} - -namespace ESM -{ - void WeatherState::load(ESMReader& esm) - { - // store values locally so that a failed load can't leave the state half set - float newHour = 0.0; - esm.getHNT(newHour, hourRecord); - float newWindSpeed = 0.0; - esm.getHNT(newWindSpeed, windSpeedRecord); - std::string newCurrentWeather = esm.getHNString(currentWeatherRecord); - std::string newNextWeather = esm.getHNString(nextWeatherRecord); - std::string newCurrentRegion = esm.getHNString(currentRegionRecord); - bool newFirstUpdate = false; - esm.getHNT(newFirstUpdate, firstUpdateRecord); - float newRemainingTransitionTime = 0.0; - esm.getHNT(newRemainingTransitionTime, remainingTransitionTimeRecord); - double newTimePassed = 0.0; - esm.getHNT(newTimePassed, timePassedRecord); - - // swap values now that it is safe to do so - mHour = newHour; - mWindSpeed = newWindSpeed; - mCurrentWeather.swap(newCurrentWeather); - mNextWeather.swap(newNextWeather); - mCurrentRegion.swap(newCurrentRegion); - mFirstUpdate = newFirstUpdate; - mRemainingTransitionTime = newRemainingTransitionTime; - mTimePassed = newTimePassed; - } - - void WeatherState::save(ESMWriter& esm) const - { - esm.writeHNT(hourRecord, mHour); - esm.writeHNT(windSpeedRecord, mWindSpeed); - esm.writeHNCString(currentWeatherRecord, mCurrentWeather.c_str()); - esm.writeHNCString(nextWeatherRecord, mNextWeather.c_str()); - esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); - esm.writeHNT(firstUpdateRecord, mFirstUpdate); - esm.writeHNT(remainingTransitionTimeRecord, mRemainingTransitionTime); - esm.writeHNT(timePassedRecord, mTimePassed); - } -} +#include "weatherstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace +{ + const char* currentRegionRecord = "CREG"; + const char* timePassedRecord = "TMPS"; + const char* fastForwardRecord = "FAST"; + const char* weatherUpdateTimeRecord = "WUPD"; + const char* transitionFactorRecord = "TRFC"; + const char* currentWeatherRecord = "CWTH"; + const char* nextWeatherRecord = "NWTH"; + const char* queuedWeatherRecord = "QWTH"; + const char* regionNameRecord = "RGNN"; + const char* regionWeatherRecord = "RGNW"; + const char* regionChanceRecord = "RGNC"; +} + +namespace ESM +{ + void WeatherState::load(ESMReader& esm) + { + mCurrentRegion = esm.getHNString(currentRegionRecord); + esm.getHNT(mTimePassed, timePassedRecord); + esm.getHNT(mFastForward, fastForwardRecord); + esm.getHNT(mWeatherUpdateTime, weatherUpdateTimeRecord); + esm.getHNT(mTransitionFactor, transitionFactorRecord); + esm.getHNT(mCurrentWeather, currentWeatherRecord); + esm.getHNT(mNextWeather, nextWeatherRecord); + esm.getHNT(mQueuedWeather, queuedWeatherRecord); + + while(esm.peekNextSub(regionNameRecord)) + { + std::string regionID = esm.getHNString(regionNameRecord); + RegionWeatherState region; + esm.getHNT(region.mWeather, regionWeatherRecord); + while(esm.peekNextSub(regionChanceRecord)) + { + char chance; + esm.getHNT(chance, regionChanceRecord); + region.mChances.push_back(chance); + } + + mRegions.insert(std::make_pair(regionID, region)); + } + } + + void WeatherState::save(ESMWriter& esm) const + { + esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); + esm.writeHNT(timePassedRecord, mTimePassed); + esm.writeHNT(fastForwardRecord, mFastForward); + esm.writeHNT(weatherUpdateTimeRecord, mWeatherUpdateTime); + esm.writeHNT(transitionFactorRecord, mTransitionFactor); + esm.writeHNT(currentWeatherRecord, mCurrentWeather); + esm.writeHNT(nextWeatherRecord, mNextWeather); + esm.writeHNT(queuedWeatherRecord, mQueuedWeather); + + std::map::const_iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + esm.writeHNCString(regionNameRecord, it->first.c_str()); + esm.writeHNT(regionWeatherRecord, it->second.mWeather); + for(size_t i = 0; i < it->second.mChances.size(); ++i) + { + esm.writeHNT(regionChanceRecord, it->second.mChances[i]); + } + } + } +} diff --git a/components/esm/weatherstate.hpp b/components/esm/weatherstate.hpp index d0cd59c160..532a056ac0 100644 --- a/components/esm/weatherstate.hpp +++ b/components/esm/weatherstate.hpp @@ -1,27 +1,36 @@ -#ifndef OPENMW_ESM_WEATHERSTATE_H -#define OPENMW_ESM_WEATHERSTATE_H - -#include - -namespace ESM -{ - class ESMReader; - class ESMWriter; - - struct WeatherState - { - float mHour; - float mWindSpeed; - std::string mCurrentWeather; - std::string mNextWeather; - std::string mCurrentRegion; - bool mFirstUpdate; - float mRemainingTransitionTime; - double mTimePassed; - - void load(ESMReader& esm); - void save(ESMWriter& esm) const; - }; -} - -#endif +#ifndef OPENMW_ESM_WEATHERSTATE_H +#define OPENMW_ESM_WEATHERSTATE_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct RegionWeatherState + { + int mWeather; + std::vector mChances; + }; + + struct WeatherState + { + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + + void load(ESMReader& esm); + void save(ESMWriter& esm) const; + }; +} + +#endif From c907ed517d05861db942b4555f0d3883e6c8814a Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 23:34:15 -0500 Subject: [PATCH 0997/1812] Remove C++11 explicit on conversion operator --- apps/openmw/mwworld/weather.cpp | 14 ++++++++++---- apps/openmw/mwworld/weather.hpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8799ae57cc..744cae28bc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -127,7 +127,13 @@ RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) RegionWeather::operator ESM::RegionWeatherState() const { - return ESM::RegionWeatherState { mWeather, mChances }; + ESM::RegionWeatherState state = + { + mWeather, + mChances + }; + + return state; } void RegionWeather::setChances(const std::vector& chances) @@ -370,12 +376,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) @@ -705,7 +711,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) std::map::iterator it = mRegions.begin(); for(; it != mRegions.end(); ++it) { - state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + state.mRegions.insert(std::make_pair(it->first, it->second)); } writer.startRecord(ESM::REC_WTHR); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d07e7e1e40..cdbe14dfab 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -127,7 +127,7 @@ namespace MWWorld explicit RegionWeather(const ESM::Region& region); explicit RegionWeather(const ESM::RegionWeatherState& state); - explicit operator ESM::RegionWeatherState() const; + operator ESM::RegionWeatherState() const; void setChances(const std::vector& chances); From 95d2d82abf75c533fe9fbec2446d7038696094e7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 27 Aug 2015 18:36:46 +1200 Subject: [PATCH 0998/1812] extracted isFlagBitSet() --- apps/openmw/mwclass/creature.cpp | 60 ++++++++++++-------------------- apps/openmw/mwclass/creature.hpp | 7 ++++ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e14d9f8ba4..80934f8858 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -129,7 +129,8 @@ namespace MWClass } // inventory - if (ref->mBase->mFlags & ESM::Creature::Weapon) + bool hasInventory = hasInventoryStore(ptr); + if (hasInventory) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -143,7 +144,7 @@ namespace MWClass getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); } } @@ -158,10 +159,8 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = ptr.get(); - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const @@ -422,9 +421,7 @@ namespace MWClass MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) return dynamic_cast(getContainerStore(ptr)); else throw std::runtime_error("this creature has no inventory store"); @@ -432,9 +429,7 @@ namespace MWClass bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; + return isFlagBitSet(ptr, ESM::Creature::Weapon); } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -446,10 +441,7 @@ namespace MWClass bool Creature::isEssential (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; + return isFlagBitSet(ptr, ESM::Creature::Essential); } void Creature::registerSelf() @@ -601,34 +593,22 @@ namespace MWClass bool Creature::isBipedal(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, ESM::Creature::Bipedal); } bool Creature::canFly(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; + return isFlagBitSet(ptr, ESM::Creature::Flies); } bool Creature::canSwim(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Swims || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Swims | ESM::Creature::Bipedal)); } bool Creature::canWalk(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Walks || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Walks | ESM::Creature::Bipedal)); } int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) @@ -691,11 +671,11 @@ namespace MWClass int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + int flags = ptr.get()->mBase->mFlags; - if (ref->mBase->mFlags & ESM::Creature::Skeleton) + if (flags & ESM::Creature::Skeleton) return 1; - if (ref->mBase->mFlags & ESM::Creature::Metal) + if (flags & ESM::Creature::Metal) return 2; return 0; } @@ -715,9 +695,7 @@ namespace MWClass // Create a CustomData, but don't fill it from ESM records (not needed) std::auto_ptr data (new CreatureCustomData); - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -760,7 +738,7 @@ namespace MWClass void Creature::respawn(const MWWorld::Ptr &ptr) const { - if (ptr.get()->mBase->mFlags & ESM::Creature::Respawn) + if (isFlagBitSet(ptr, ESM::Creature::Respawn)) { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. @@ -796,4 +774,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } + + bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + return (ref->mBase->mFlags & bitMask) != 0; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255e..1a29d03183 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H +#include + #include "actor.hpp" namespace ESM @@ -134,6 +136,11 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + + private: + + /// \return true if any of the indicated bits in Creature's mFlags is set + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From 7817c52cbb6e7f67d4cc49a8b07a89f3d26d5407 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 09:57:32 -0500 Subject: [PATCH 0999/1812] Discard old save game weather records --- apps/openmw/mwworld/weather.cpp | 49 ++++++++++++++++++++------------- components/esm/savedgame.cpp | 2 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 744cae28bc..43b2a0dffe 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,7 +5,9 @@ #include +#include #include +#include #include #include "../mwbase/environment.hpp" @@ -723,30 +725,39 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - ESM::WeatherState state; - state.load(reader); - - mCurrentRegion.swap(state.mCurrentRegion); - mTimePassed = state.mTimePassed; - mFastForward = state.mFastForward; - mWeatherUpdateTime = state.mWeatherUpdateTime; - mTransitionFactor = state.mTransitionFactor; - mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; - mQueuedWeather = state.mQueuedWeather; - - mRegions.clear(); - std::map::iterator it = state.mRegions.begin(); - if(it == state.mRegions.end()) + if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) { - // When loading an imported save, the region modifiers aren't currently being set, so just reset them. - importRegions(); + // Weather state isn't really all that important, so to preserve older save games, we'll just discard the + // older weather records, rather than fail to handle the record. + reader.skipRecord(); } else { - for(; it != state.mRegions.end(); ++it) + ESM::WeatherState state; + state.load(reader); + + mCurrentRegion.swap(state.mCurrentRegion); + mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) { - mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } } } diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 2e5509b7a5..cf9f68c9a8 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 1; +int ESM::SavedGame::sCurrentFormat = 2; void ESM::SavedGame::load (ESMReader &esm) { From cd8ec5c11e48def47b69373a1f5f779da84a3e43 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 10:34:35 -0500 Subject: [PATCH 1000/1812] Improve checking for older weather records --- apps/openmw/mwworld/weather.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 43b2a0dffe..5c2a81c091 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -725,7 +725,8 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) + static const int oldestCompatibleSaveFormat = 2; + if(reader.getFormat() < oldestCompatibleSaveFormat) { // Weather state isn't really all that important, so to preserve older save games, we'll just discard the // older weather records, rather than fail to handle the record. From 4fd00a75d5814a495f150b302570e7779bb48132 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 14:20:45 -0500 Subject: [PATCH 1001/1812] Merge advanceTime and advanceTimeByFrame --- apps/openmw/engine.cpp | 5 ++++- apps/openmw/mwbase/world.hpp | 5 +---- apps/openmw/mwworld/weather.cpp | 15 ++++----------- apps/openmw/mwworld/weather.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 23 ++--------------------- apps/openmw/mwworld/worldimp.hpp | 5 +---- 6 files changed, 13 insertions(+), 43 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6c95700b37..32ff20ba70 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,7 +128,10 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTimeByFrame(frametime); + { + double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; + mEnvironment.getWorld()->advanceTime(hours, true); + } } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6363703425..a3d293d953 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -185,12 +185,9 @@ namespace MWBase virtual void disable (const MWWorld::Ptr& ptr) = 0; - virtual void advanceTime (double hours) = 0; + virtual void advanceTime (double hours, bool incremental = false) = 0; ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime) = 0; - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5c2a81c091..52609f21a7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -670,19 +670,12 @@ osg::Vec3f WeatherManager::getStormDirection() const return mStormDirection; } -void WeatherManager::advanceTime(double hours) +void WeatherManager::advanceTime(double hours, bool incremental) { - // This is called when the player sleeps/waits, serves jail time, travels, or trains. - // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of - // whatever transition time might have been remaining. - mTimePassed += hours; - mFastForward = true; -} - -void WeatherManager::advanceTimeByFrame(double hours) -{ - // Called when time is advanced by an incremental update for each frame. + // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are + // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; + mFastForward = (!mFastForward && !incremental) ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index cdbe14dfab..c808b029b9 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -206,8 +206,7 @@ namespace MWWorld osg::Vec3f getStormDirection() const; - void advanceTime(double hours); - void advanceTimeByFrame(double hours); + void advanceTime(double hours, bool incremental); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 56c7415a2d..5f9c8f8d3d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -787,30 +787,11 @@ namespace MWWorld } } - void World::advanceTime (double hours) + void World::advanceTime (double hours, bool incremental) { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - mWeatherManager->advanceTime (hours); - - hours += mGlobalVariables["gamehour"].getFloat(); - - setHour (hours); - - int days = static_cast(hours / 24); - - if (days>0) - mGlobalVariables["dayspassed"].setInteger ( - days + mGlobalVariables["dayspassed"].getInteger()); - } - - void World::advanceTimeByFrame (double frametime) - { - double hours = (frametime * getTimeScaleFactor()) / 3600.0; - - MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - - mWeatherManager->advanceTimeByFrame (hours); + mWeatherManager->advanceTime (hours, incremental); hours += mGlobalVariables["gamehour"].getFloat(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 80fe6d850b..241dacc8aa 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -274,12 +274,9 @@ namespace MWWorld virtual void disable (const Ptr& ptr); - virtual void advanceTime (double hours); + virtual void advanceTime (double hours, bool incremental = false); ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime); - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour); ///< Set in-game time hour. From 300c48329d447ec6a43b67a597005a4ce2fcd7fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 28 Aug 2015 18:38:05 +1200 Subject: [PATCH 1002/1812] Creature::isFlagBitSet() changed to free function. --- apps/openmw/mwclass/creature.cpp | 11 +++++------ apps/openmw/mwclass/creature.hpp | 7 ------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 80934f8858..450889eb2a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -58,6 +58,11 @@ namespace cloned->mContainerStore = mContainerStore->clone(); return cloned; } + + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + { + return (ptr.get()->mBase->mFlags & bitMask) != 0; + } } namespace MWClass @@ -774,10 +779,4 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } - - bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const - { - MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & bitMask) != 0; - } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 1a29d03183..c4ea09255e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include - #include "actor.hpp" namespace ESM @@ -136,11 +134,6 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; - - private: - - /// \return true if any of the indicated bits in Creature's mFlags is set - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From d9a7986b3a654847be77826626d68bc5ba1b22c2 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 18:04:22 -0500 Subject: [PATCH 1003/1812] Remove redundant fast forward check --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 52609f21a7..da1f2f7e60 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -675,7 +675,7 @@ void WeatherManager::advanceTime(double hours, bool incremental) // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; - mFastForward = (!mFastForward && !incremental) ? true : mFastForward; + mFastForward = !incremental ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const From 2b48a20b76ef0ca85311bfce201477ea799b30d6 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 23:12:39 -0500 Subject: [PATCH 1004/1812] Fix weather transition bugs --- apps/openmw/mwworld/weather.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index da1f2f7e60..e7c67d2e1d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -736,7 +736,7 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) mWeatherUpdateTime = state.mWeatherUpdateTime; mTransitionFactor = state.mTransitionFactor; mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; + mNextWeather = state.mNextWeather; mQueuedWeather = state.mQueuedWeather; mRegions.clear(); @@ -884,6 +884,8 @@ inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeco mCurrentWeather = mNextWeather; } + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; mFastForward = false; } } From 067779983986e91b226e9a3c8932094b2330d377 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:21:18 +1200 Subject: [PATCH 1005/1812] movement logic in AiPackage uses ObstacleCheck. --- apps/openmw/mwmechanics/aipackage.cpp | 27 ++++++++++----------------- apps/openmw/mwmechanics/aipackage.hpp | 2 -- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 2c8c57c56b..c18ee5ceb3 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -19,7 +19,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } @@ -28,7 +28,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { //Update various Timers mTimer += duration; //Update timer - mStuckTimer += duration; //Update stuck timer ESM::Position pos = actor.getRefData().getPosition(); //position of the actor @@ -91,11 +90,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; - else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something + else { -/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason - //if(mObstacleCheck.check(actor, duration)) { - if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < actor.getClass().getSpeed(actor)*0.05 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if(mObstacleCheck.check(actor, duration)) + { // first check if we're walking into a door MWWorld::Ptr door = getNearbyDoor(actor); if(door != MWWorld::Ptr()) // NOTE: checks interior cells only @@ -106,24 +107,16 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po } else // probably walking into another NPC { - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; // change the angle a bit, too zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things - mStuckTimer = 0; - mStuckPos = pos; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward + movement.mPosition[1] = 1; //Just run forward } } - else { - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time - } - - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - return false; } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index d73833b948..00cab2d083 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -83,9 +83,7 @@ namespace MWMechanics ObstacleCheck mObstacleCheck; float mTimer; - float mStuckTimer; - ESM::Position mStuckPos; ESM::Pathgrid::Point mPrevDest; }; } From f59e918a3b697e119a224b86c7ac2edd591e978f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:34:33 +1200 Subject: [PATCH 1006/1812] removed useless code. zTurn ignores turns < 0.0087 radians. --- apps/openmw/mwmechanics/aipackage.cpp | 2 -- apps/openmw/mwmechanics/aiwander.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c18ee5ceb3..36843663e9 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -109,8 +109,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { movement.mPosition[0] = 1; movement.mPosition[1] = 1; - // change the angle a bit, too - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8f27a2048a..01d8125b3c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -437,9 +437,6 @@ namespace MWMechanics // but doesn't seem to do that? actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } From 31d82b6b0c09a9e1cf2296fc46a2c40bdaf10627 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 08:32:47 +1200 Subject: [PATCH 1007/1812] Unifiy evadeObstacles() logic between AiWander and AiPackage Can't use same code, but logic is now same. --- apps/openmw/mwmechanics/aipackage.cpp | 49 +++++++++++++++------------ apps/openmw/mwmechanics/aipackage.hpp | 4 +++ apps/openmw/mwmechanics/aiwander.cpp | 20 ++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 36843663e9..097cc40425 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -92,32 +92,37 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return true; else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - - MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); - if(mObstacleCheck.check(actor, duration)) - { - // first check if we're walking into a door - MWWorld::Ptr door = getNearbyDoor(actor); - if(door != MWWorld::Ptr()) // NOTE: checks interior cells only - { - if(!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped - MWBase::Environment::get().getWorld()->activateDoor(door, 1); - } - } - else // probably walking into another NPC - { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; - } - } - else { //Not stuck, so reset things - movement.mPosition[1] = 1; //Just run forward - } + evadeObstacles(actor, duration, pos); } return false; } +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +{ + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + MWWorld::Ptr door = getNearbyDoor(actor); + if (door != MWWorld::Ptr()) // NOTE: checks interior cells only + { + if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + MWBase::Environment::get().getWorld()->activateDoor(door, 1); + } + } + else // probably walking into another NPC + { + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; + } + } + else { //Not stuck, so reset things + movement.mPosition[1] = 1; //Just run forward + } +} + bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { return distance(mPrevDest, dest) > 10; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 00cab2d083..4f919edbc6 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -85,6 +85,10 @@ namespace MWMechanics float mTimer; ESM::Pathgrid::Point mPrevDest; + + private: + void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 01d8125b3c..ce70fee772 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -381,11 +381,7 @@ namespace MWMechanics else { // have not yet reached the destination - //... turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); + evadeObstacles(actor, storage, duration, pos); } } @@ -417,8 +413,12 @@ namespace MWMechanics storage.mState = Wander_IdleNow; } - void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { + // turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); if (mObstacleCheck.check(actor, duration)) { // first check if we're walking into a door @@ -435,11 +435,15 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + movement.mPosition[0] = 1; + movement.mPosition[1] = 0.1f; } mStuckCount++; // TODO: maybe no longer needed } + else + { + movement.mPosition[1] = 1; + } //#if 0 // TODO: maybe no longer needed if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 27e6fe9fb6..b0fabfce3b 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,7 +83,7 @@ namespace MWMechanics short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); From f2c9b9351f702d18e8ca3e2fcb97d640780fa8bf Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 10:06:09 +1200 Subject: [PATCH 1008/1812] Try going right and left to "unstick" actor. --- apps/openmw/mwmechanics/aipackage.cpp | 3 +-- apps/openmw/mwmechanics/aiwander.cpp | 3 +-- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++++++ apps/openmw/mwmechanics/obstacle.hpp | 8 ++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 097cc40425..b6b2408338 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -114,8 +114,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } else // probably walking into another NPC { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; + mObstacleCheck.takeEvasiveAction(movement); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ce70fee772..67a9f766cf 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -435,8 +435,7 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - movement.mPosition[0] = 1; - movement.mPosition[1] = 0.1f; + mObstacleCheck.takeEvasiveAction(movement); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 25bd06301f..fe3d68a583 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -6,6 +6,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "movement.hpp" + namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking @@ -67,6 +69,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time + , mEvadeDirection(1.0f) { } @@ -155,6 +158,7 @@ namespace MWMechanics /* FALL THROUGH */ case State_Evade: { + chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -169,4 +173,20 @@ namespace MWMechanics } return false; // no obstacles to evade (yet) } + + void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) + { + actorMovement.mPosition[0] = mEvadeDirection; + actorMovement.mPosition[1] = 0; + } + + void ObstacleCheck::chooseEvasionDirection(bool samePosition) + { + // change direction if attempt didn't work + if (samePosition && (0 < mEvadeDuration)) + { + mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + } + } + } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e0ae9203d7..ef3e29e8b0 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -8,6 +8,8 @@ namespace MWWorld namespace MWMechanics { + struct Movement; + /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; @@ -36,6 +38,9 @@ namespace MWMechanics // should be taken bool check(const MWWorld::Ptr& actor, float duration); + // change direction to try to fix "stuck" actor + void takeEvasiveAction(MWMechanics::Movement& actorMovement); + private: // for checking if we're stuck (ignoring Z axis) @@ -53,6 +58,9 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed + float mEvadeDirection; + + void chooseEvasionDirection(bool samePosition); }; } From 39c2ba8efe98aa4d9f29f06450a62f2081d372c9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:12:51 +1200 Subject: [PATCH 1009/1812] Pathfinding bugfix. Observed at Ebonheart (coe 1, -13). Especially at the western tower. Guards try to walk though tower door. Cause: buildPath() adds destination (even when unreachable) when only using single node from pathgrid. --- apps/openmw/mwmechanics/pathfinding.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f53badbf46..daab321367 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -225,19 +225,16 @@ namespace MWMechanics ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); converter.ToWorld(temp); mPath.push_back(temp); - - mPath.push_back(endPoint); - return; } - - mPath = mCell->aStarSearch(startNode, endNode.first); - if (mPath.empty()) - return; - - // convert supplied path to world co-ordinates - for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + else { - converter.ToWorld(*iter); + mPath = mCell->aStarSearch(startNode, endNode.first); + + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } } // If endNode found is NOT the closest PathGrid point to the endPoint, @@ -254,8 +251,6 @@ namespace MWMechanics // The AI routines will have to deal with such situations. if(endNode.second) mPath.push_back(endPoint); - - return; } float PathFinder::getZAngleToNext(float x, float y) const From 1dfe438a5d37401b75bd2de491a2524cc92ffd21 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:43:35 +1200 Subject: [PATCH 1010/1812] reduce "reset if stuck" AiWander timeout. Now is about 14 seconds, instead of 300. --- apps/openmw/mwmechanics/aiwander.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 67a9f766cf..b789c44286 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -27,7 +27,7 @@ namespace MWMechanics { - static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed + static const int COUNT_BEFORE_RESET = 10; static const float DOOR_CHECK_INTERVAL = 1.5f; static const float REACTION_INTERVAL = 0.25f; static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player @@ -443,8 +443,8 @@ namespace MWMechanics { movement.mPosition[1] = 1; } -//#if 0 - // TODO: maybe no longer needed + + // if stuck for sufficiently long, act like current location was the destination if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset { //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; @@ -454,7 +454,6 @@ namespace MWMechanics storage.mState = Wander_ChooseAction; mStuckCount = 0; } -//#endif } void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) From b7983d08ba3f238f0cddad467049c87b17a3745f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 11:08:56 +0200 Subject: [PATCH 1011/1812] fixed merge stage order; added proper initialisation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.cpp | 17 +++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 15 +++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 2 ++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index f9a89aaa16..89f22ef1a6 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -9,7 +9,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new StartMergeStage (mState)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); @@ -37,6 +38,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); + /// \todo Land, LandTextures } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 80f16ec146..349cc29259 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,6 +8,23 @@ #include "../doc/document.hpp" #include "../world/data.hpp" + +CSMTools::StartMergeStage::StartMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::StartMergeStage::setup() +{ + return 1; +} + +void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = false; + mState.mTextureIndices.clear(); +} + + CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) : mState (state), mEncoder (encoding) {} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index e1cc17a3e6..7d62058f00 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -14,6 +14,21 @@ namespace CSMTools { + class StartMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + StartMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 4482ba6f4a..077edc9d9d 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTATE_H #include +#include #include "../doc/document.hpp" @@ -12,6 +13,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; From 890bbb6b119bab1b9a7b5724ab3e6a769ede761a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 14:27:22 +0200 Subject: [PATCH 1012/1812] merge land texture tables --- apps/opencs/model/tools/mergeoperation.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 79 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 31 +++++++++ apps/opencs/model/tools/mergestate.hpp | 4 +- apps/opencs/model/world/data.cpp | 5 ++ apps/opencs/model/world/data.hpp | 2 + 6 files changed, 124 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 89f22ef1a6..9e791683cc 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -37,10 +37,13 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new MergeReferencesStage (mState)); + appendStage (new ListLandTexturesMergeStage (mState)); + appendStage (new MergeLandTexturesStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - /// \todo Land, LandTextures + /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 349cc29259..f34ba8eb41 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include #include "mergestate.hpp" @@ -104,3 +106,80 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa mState.mTarget->getData().getReferences().appendRecord (newRecord); } } + + +CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::ListLandTexturesMergeStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + ESM::Land& land = *record.get().mLand; + + // make sure record is loaded + land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + if (land.mLandData) + { + // list texture indices + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + + mState.mTextureIndices[key] = -1; + } + } + } +} + + +CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) +: mState (state), mNext (mState.mTextureIndices.end()) +{} + +int CSMTools::MergeLandTexturesStage::setup() +{ + mNext = mState.mTextureIndices.begin(); + return mState.mTextureIndices.size(); +} + +void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +{ + mNext->second = stage; + + std::ostringstream stream; + stream << mNext->first.first << "_" << mNext->first.second; + + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); + + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); + + texture.mIndex = mNext->second; + texture.mId = stream.str(); + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + } + /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) + + ++mNext; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 7d62058f00..f0ae99842c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -115,6 +115,37 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class ListLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + ListLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + class MergeLandTexturesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map, int>::iterator mNext; + + public: + + MergeLandTexturesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 077edc9d9d..29e1bbda72 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTATE_H #define CSM_TOOLS_MERGESTATE_H +#include + #include #include @@ -13,7 +15,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; - std::map, int> mTextureIndices; // (texture, content file) -> new texture + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d8999d950b..c12827b530 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -778,6 +778,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLandText return mLandTextures; } +CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() +{ + return mLandTextures; +} + const CSMWorld::IdCollection& CSMWorld::Data::getSoundGens() const { return mSoundGens; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 5706b005b7..9a41ead421 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -234,6 +234,8 @@ namespace CSMWorld const IdCollection& getLandTextures() const; + IdCollection& getLandTextures(); + const IdCollection& getSoundGens() const; IdCollection& getSoundGens(); From 8aaba0af6fac116f09092bbc1f88241988b7706e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 17:38:21 +0200 Subject: [PATCH 1013/1812] Fix journal page navigation bug introduced by 7dd09dd637c317d3d94 (Fixes #2899) --- apps/openmw/mwgui/journalwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8238f6585c..b6f72a04cb 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -356,6 +356,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyTopicSelected (const std::string& topic, int id) @@ -383,6 +385,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyOptions(MyGUI::Widget* _sender) From cda8a88f0d9a9fb5f12e3a39f683b2a874e4e9e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:00:37 +0200 Subject: [PATCH 1014/1812] Use DEEP_COPY_PRIMITIVES to work around problem in osg::Geometry copy constructor (Bug #2754) --- components/sceneutil/clone.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 36c5c02a16..74eae0b6be 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -52,6 +52,32 @@ namespace SceneUtil { osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); + + /* + + Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: + + if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) + { + if (_useVertexBufferObjects) + { + // copying of arrays doesn't set up buffer objects so we'll need to force + // Geometry to assign these, we'll do this by switching off VBO's then renabling them. + setUseVertexBufferObjects(false); + setUseVertexBufferObjects(true); + } + } + + In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, + causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. + + TODO: report/fix in upstream OSG + + */ + + copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); + + osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); From e9acd135a6a405f88f2f3ab896cdac7eade31f04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:43:39 +0200 Subject: [PATCH 1015/1812] Update todo comment --- components/sceneutil/clone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 74eae0b6be..e4b4f63bb1 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -71,7 +71,7 @@ namespace SceneUtil In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - TODO: report/fix in upstream OSG + Possible fix submitted to osg-submissions ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). */ From b0641934d4a34b4e462932aa715cc0ca9d854cae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:06:32 +0200 Subject: [PATCH 1016/1812] added copy constructor and assignment operator for Land record struct --- components/esm/loadland.cpp | 27 +++++++++++++++++++++++++++ components/esm/loadland.hpp | 8 ++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b0897ec67d..baeca34de1 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -1,5 +1,7 @@ #include "loadland.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -215,4 +217,29 @@ bool Land::isDataLoaded(int flags) const return (mDataLoaded & flags) == (flags & mDataTypes); } + Land::Land (const Land& land) + : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), + mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes), + mDataLoaded (land.mDataLoaded), + mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) + {} + + Land& Land::operator= (Land land) + { + swap (land); + return *this; + } + + void Land::swap (Land& land) + { + std::swap (mFlags, land.mFlags); + std::swap (mX, land.mX); + std::swap (mY, land.mY); + std::swap (mPlugin, land.mPlugin); + std::swap (mEsm, land.mEsm); + std::swap (mContext, land.mContext); + std::swap (mDataTypes, land.mDataTypes); + std::swap (mDataLoaded, land.mDataLoaded); + std::swap (mLandData, land.mLandData); + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 61ce4855eb..e010b170c3 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -116,9 +116,13 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + Land (const Land& land); + + Land& operator= (Land land); + + void swap (Land& land); + private: - Land(const Land& land); - Land& operator=(const Land& land); /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise From 69045d7ec9d293f2bb5626b2ac4a8517a0cf67e4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:10:58 +0200 Subject: [PATCH 1017/1812] additional safety check for land texture listing merge stage --- apps/opencs/model/tools/mergestages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f34ba8eb41..a4072e4bce 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData) + if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) { // list texture indices std::pair key; From febf611c827a257a4d4000b601f9ef413f2f8012 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 14:17:11 +0200 Subject: [PATCH 1018/1812] made return type of ESMTerrain::Storage::getLand const --- apps/opencs/view/render/terrainstorage.cpp | 2 +- apps/opencs/view/render/terrainstorage.hpp | 2 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- apps/openmw/mwrender/terrainstorage.hpp | 2 +- components/esmterrain/storage.cpp | 10 +++++----- components/esmterrain/storage.hpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef14..a60678f889 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -9,7 +9,7 @@ namespace CSVRender { } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { std::ostringstream stream; stream << "#" << cellX << " " << cellY; diff --git a/apps/opencs/view/render/terrainstorage.hpp b/apps/opencs/view/render/terrainstorage.hpp index 97782ad17e..16b0f3ec7a 100644 --- a/apps/opencs/view/render/terrainstorage.hpp +++ b/apps/opencs/view/render/terrainstorage.hpp @@ -18,7 +18,7 @@ namespace CSVRender private: const CSMWorld::Data& mData; - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 269e7f99fc..f9a9083f01 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -51,7 +51,7 @@ namespace MWRender maxY += 1; } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index 93531a5523..a12ffd540f 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -10,7 +10,7 @@ namespace MWRender class TerrainStorage : public ESMTerrain::Storage { private: - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); public: diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 10b75bb741..5bc56a4307 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -74,7 +74,7 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; @@ -109,7 +109,7 @@ namespace ESMTerrain ++cellX; row = 0; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; @@ -158,7 +158,7 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) land = NULL; @@ -262,7 +262,7 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) { int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; @@ -368,7 +368,7 @@ namespace ESMTerrain int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 8f4a3aa921..debbc59b9d 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,7 +21,7 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY) = 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: From b3fdf92d2b1b37a8c118ee5bdc1a2f6d6437a667 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:08:19 +0200 Subject: [PATCH 1019/1812] more const-ness fixes --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb2618514..23b3f051c5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -460,7 +460,7 @@ namespace MWPhysics class HeightField { public: - HeightField(float* heights, int x, int y, float triSize, float sqrtVerts) + HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts) { // find the minimum and maximum heights (needed for bullet) float minh = heights[0]; @@ -927,7 +927,7 @@ namespace MWPhysics return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight); } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts) { HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); mHeightFields[std::make_pair(x,y)] = heightfield; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index c3b22c3854..ee9378ea49 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -71,7 +71,7 @@ namespace MWPhysics void updatePosition (const MWWorld::Ptr& ptr); - void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); + void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts); void removeHeightField (int x, int y); From 69b9eadb52cf24398d64b6399341d9e6b5d40bdf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:13:26 +0200 Subject: [PATCH 1020/1812] refactored loading of land data --- apps/esmtool/record.cpp | 14 ++-- apps/opencs/model/doc/savingstages.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 8 ++- apps/openmw/mwworld/scene.cpp | 6 +- components/esm/loadland.cpp | 22 ++++-- components/esm/loadland.hpp | 23 ++++-- components/esmterrain/storage.cpp | 93 ++++++++++++++----------- components/esmterrain/storage.hpp | 7 +- 9 files changed, 108 insertions(+), 74 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bbf..76c14e728d 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -841,19 +841,13 @@ void Record::print() std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl; std::cout << " DataTypes: " << mData.mDataTypes << std::endl; - // Seems like this should done with reference counting in the - // loader to me. But I'm not really knowledgable about this - // record type yet. --Cory - bool wasLoaded = (mData.mDataLoaded != 0); - if (mData.mDataTypes) mData.loadData(mData.mDataTypes); - if (mData.mDataLoaded) + if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes)) { - std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl; + std::cout << " Height Offset: " << data->mHeightOffset << std::endl; // Lots of missing members. - std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl; - std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; + std::cout << " Unknown1: " << data->mUnk1 << std::endl; + std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); } template<> diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd6..a21a28c997 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -421,8 +421,9 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); + + if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + data->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index a4072e4bce..5bf0241ac2 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) + if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) { // list texture indices std::pair key; @@ -138,7 +138,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& for (int i=0; imTextures[i]; + key.first = data->mTextures[i]; mState.mTextureIndices[key] = -1; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a2..97a27ebbc4 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -156,6 +156,9 @@ namespace MWRender land->loadData(mask); } + const ESM::Land::LandData *landData = + land ? land->getLandData (ESM::Land::DATA_WNAM) : 0; + for (int cellY=0; cellY(float(cellX)/float(mCellSize) * 9); int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); - int texelX = (x-mMinX) * mCellSize + cellX; int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); unsigned char r,g,b; float y = 0; - if (land && land->mDataTypes & ESM::Land::DATA_WNAM) - y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + if (landData) + y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; else y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 48e346c145..459b3b6ca0 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -250,9 +250,9 @@ namespace MWWorld // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(flags)) - land->loadData(flags); - mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + + const ESM::Land::LandData *data = land->getLandData (flags); + mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index baeca34de1..770830fddb 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -10,7 +10,7 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) +void Land::LandData::save(ESMWriter &esm) const { if (mDataTypes & Land::DATA_VNML) { esm.writeHNT("VNML", mNormals, sizeof(mNormals)); @@ -55,7 +55,7 @@ void Land::LandData::save(ESMWriter &esm) } } -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) +void Land::LandData::transposeTextureData(const uint16_t *in, uint16_t *out) { int readPos = 0; //bit ugly, but it works for ( int y1 = 0; y1 < 4; y1++ ) @@ -139,7 +139,7 @@ void Land::save(ESMWriter &esm) const esm.writeHNT("DATA", mFlags); } -void Land::loadData(int flags) +void Land::loadData(int flags) const { // Try to load only available data flags = flags & mDataTypes; @@ -201,7 +201,7 @@ void Land::unloadData() } } -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) +bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { mEsm->getHExact(ptr, size); @@ -242,4 +242,18 @@ bool Land::isDataLoaded(int flags) const std::swap (mDataLoaded, land.mDataLoaded); std::swap (mLandData, land.mLandData); } + + const Land::LandData *Land::getLandData (int flags) const + { + if (!(flags & mDataTypes)) + return 0; + + loadData (flags); + return mLandData; + } + + const Land::LandData *Land::getLandData() const + { + return mLandData; + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e010b170c3..64d131ecb9 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -35,7 +35,6 @@ struct Land ESM_Context mContext; int mDataTypes; - int mDataLoaded; enum { @@ -91,12 +90,10 @@ struct Land short mUnk1; uint8_t mUnk2; - void save(ESMWriter &esm); - static void transposeTextureData(uint16_t *in, uint16_t *out); + void save(ESMWriter &esm) const; + static void transposeTextureData(const uint16_t *in, uint16_t *out); }; - LandData *mLandData; - void load(ESMReader &esm); void save(ESMWriter &esm) const; @@ -105,7 +102,7 @@ struct Land /** * Actually loads data */ - void loadData(int flags); + void loadData(int flags) const; /** * Frees memory allocated for land data @@ -122,12 +119,24 @@ struct Land void swap (Land& land); + /// Return land data with at least the data types specified in \a flags loaded (if they + /// are available). Will return a 0-pointer if there is no data for any of the + /// specified types. + const LandData *getLandData (int flags) const; + + /// Return land data without loading first anything. Can return a 0-pointer. + const LandData *getLandData() const; + private: /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise /// including the case when data is already loaded - bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size); + bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; + + mutable int mDataLoaded; + + mutable LandData *mLandData; }; } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5bc56a4307..ccfe6d9ee5 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -18,6 +18,14 @@ namespace ESMTerrain { } + const ESM::Land::LandData *Storage::getLandData (int cellX, int cellY, int flags) + { + if (const ESM::Land *land = getLand (cellX, cellY)) + return land->getLandData (flags); + + return 0; + } + bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); @@ -32,24 +40,25 @@ namespace ESMTerrain int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); - const ESM::Land* land = getLand(cellX, cellY); - if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return false; - - min = std::numeric_limits::max(); - max = -std::numeric_limits::max(); - for (int row=0; row::max(); + max = -std::numeric_limits::max(); + for (int row=0; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - if (h > max) - max = h; - if (h < min) - min = h; + for (int col=0; colmHeights[col*ESM::Land::LAND_SIZE+row]; + if (h > max) + max = h; + if (h < min) + min = h; + } } + return true; } - return true; + + return false; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -74,12 +83,12 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML)) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; normal.normalize(); } else @@ -109,12 +118,12 @@ namespace ESMTerrain ++cellX; row = 0; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR)) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { @@ -158,9 +167,9 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - const ESM::Land* land = getLand(cellX, cellY); - if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) - land = NULL; + const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); + const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); + const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR); int rowStart = 0; int colStart = 0; @@ -177,20 +186,22 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + if (heightData) + height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, (vertY / float(numVerts - 1) - 0.5f) * size * 8192, height); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + if (normalData) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + for (int i=0; i<3; ++i) + normal[i] = normalData->mNormals[arrayIndex+i]; + normal.normalize(); } else @@ -208,11 +219,10 @@ namespace ESMTerrain (*normals)[static_cast(vertX*numVerts + vertY)] = normal; - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + if (colourData) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + for (int i=0; i<3; ++i) + color[i] = colourData->mColours[arrayIndex+i] / 255.f; } else { @@ -262,13 +272,12 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX)) { - int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; if (tex == 0) return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin - return std::make_pair(tex, land->mPlugin); + return std::make_pair(tex, getLand (cellX, cellY)->mPlugin); } else return std::make_pair(0,0); @@ -447,7 +456,7 @@ namespace ESMTerrain { assert(x < ESM::Land::LAND_SIZE); assert(y < ESM::Land::LAND_SIZE); - return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; + return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x]; } Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index debbc59b9d..5b8ca953d4 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,12 +21,17 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual const ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY)= 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: Storage(const VFS::Manager* vfs); + /// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for + /// any of the data types specified via \a flags. Will also return a 0-pointer if there + /// is no land record for the coordinates \a cellX / \a cellY. + const ESM::Land::LandData *getLandData (int cellX, int cellY, int flags); + // Not implemented in this class, because we need different Store implementations for game and editor /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0; From 85f6bb892b7f61b95d297efcf67cfccaee134e54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 18:13:27 +0200 Subject: [PATCH 1021/1812] removed indirection in OpenMW-CS land record --- apps/opencs/model/doc/savingstages.cpp | 10 +++++----- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/world/data.cpp | 7 ++++++- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/land.cpp | 16 ++-------------- apps/opencs/model/world/land.hpp | 10 ++-------- apps/opencs/view/render/cell.cpp | 15 ++++++++------- apps/opencs/view/render/terrainstorage.cpp | 7 +++---- 8 files changed, 29 insertions(+), 40 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index a21a28c997..894c479a4f 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -416,16 +416,16 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) if (land.mState==CSMWorld::RecordBase::State_Modified || land.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - CSMWorld::Land record = land.get(); + const CSMWorld::Land& record = land.get(); - mState.getWriter().startRecord (record.mLand->sRecordId); + mState.getWriter().startRecord (record.sRecordId); - record.mLand->save (mState.getWriter()); + record.save (mState.getWriter()); - if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes)) data->save (mState.getWriter()); - mState.getWriter().endRecord (record.mLand->sRecordId); + mState.getWriter().endRecord (record.sRecordId); } else if (land.mState==CSMWorld::RecordBase::State_Deleted) { diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 5bf0241ac2..c624ff548e 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - ESM::Land& land = *record.get().mLand; + const ESM::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c12827b530..fe6d6ccbbd 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -773,6 +773,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLand() const return mLand; } +CSMWorld::IdCollection& CSMWorld::Data::getLand() +{ + return mLand; +} + const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const { return mLandTextures; @@ -951,7 +956,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) int index = mLand.load(*mReader, mBase); if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.mLand->loadData ( + mLand.getRecord (index).mModified.loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 9a41ead421..c6623279a6 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -232,6 +232,8 @@ namespace CSMWorld const IdCollection& getLand() const; + IdCollection& getLand(); + const IdCollection& getLandTextures() const; IdCollection& getLandTextures(); diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 119e187616..222f9bc023 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -4,25 +4,13 @@ namespace CSMWorld { - - Land::Land() - { - mLand.reset(new ESM::Land()); - } - void Land::load(ESM::ESMReader &esm) { - mLand->load(esm); + ESM::Land::load(esm); std::ostringstream stream; - stream << "#" << mLand->mX << " " << mLand->mY; + stream << "#" << mX << " " << mY; mId = stream.str(); } - - void Land::blank() - { - /// \todo - } - } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd8..22cedb56db 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -2,7 +2,7 @@ #define CSM_WORLD_LAND_H #include -#include + #include namespace CSMWorld @@ -11,18 +11,12 @@ namespace CSMWorld /// /// \todo Add worldspace support to the Land record. /// \todo Add a proper copy constructor (currently worked around using shared_ptr) - struct Land + struct Land : public ESM::Land { - Land(); - - boost::shared_ptr mLand; - std::string mId; /// Loads the metadata and ID void load (ESM::ESMReader &esm); - - void blank(); }; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab0666..4425c193ff 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -32,7 +32,7 @@ bool CSVRender::Cell::addObjects (int start, int end) bool modified = false; const CSMWorld::RefCollection& collection = mData.getReferences(); - + for (int i=start; i<=end; ++i) { std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); @@ -68,15 +68,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st int landIndex = land.searchId(mId); if (landIndex != -1) { - const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand->mX, - esmLand->mY); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); - mX = esmLand->mX; - mY = esmLand->mY; + mX = esmLand.mX; + mY = esmLand.mY; } } } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index a60678f889..b5b144fe45 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -20,11 +20,10 @@ namespace CSVRender if (index == -1) return NULL; - ESM::Land* land = mData.getLand().getRecord(index).get().mLand.get(); + const ESM::Land& land = mData.getLand().getRecord(index).get(); int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(mask)) - land->loadData(mask); - return land; + land.loadData (mask); + return &land; } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) From a8dc1c119859abd0ad4cf16765abbf1f70fe6013 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Sep 2015 16:15:00 +0200 Subject: [PATCH 1022/1812] merge land tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 64 +++++++++++++++++++++- apps/opencs/model/tools/mergestages.hpp | 15 +++++ components/esm/loadland.cpp | 26 +++++++++ components/esm/loadland.hpp | 11 ++++ 5 files changed, 115 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e791683cc..907d742edf 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -40,10 +40,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeReferencesStage (mState)); appendStage (new ListLandTexturesMergeStage (mState)); appendStage (new MergeLandTexturesStage (mState)); + appendStage (new MergeLandStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - - /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index c624ff548e..f4cb42aa4c 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -153,12 +153,20 @@ CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) int CSMTools::MergeLandTexturesStage::setup() { - mNext = mState.mTextureIndices.begin(); - return mState.mTextureIndices.size(); + // Should use the size of mState.mTextureIndices instead, but that is not available at this + // point. Unless there are any errors in the land and land texture records this will not + // make a difference. + return mState.mSource.getData().getLandTextures().getSize(); } void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) { + if (stage==0) + mNext = mState.mTextureIndices.begin(); + + if (mNext==mState.mTextureIndices.end()) + return; + mNext->second = stage; std::ostringstream stream; @@ -183,3 +191,55 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes ++mNext; } + + +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeLandStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + const CSMWorld::Land& land = record.get(); + + land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + CSMWorld::Land newLand (land); + + newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway, + // because record is already fully loaded) + newLand.mPlugin = 0; + + // adjust land texture references + if (ESM::Land::LandData *data = newLand.getLandData()) + { + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } + } + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + + mState.mTarget->getData().getLand().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f0ae99842c..f88f5be9f6 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -146,6 +146,21 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeLandStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeLandStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 770830fddb..784cfd4078 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -256,4 +256,30 @@ bool Land::isDataLoaded(int flags) const { return mLandData; } + + Land::LandData *Land::getLandData() + { + return mLandData; + } + + void Land::add (int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mDataLoaded |= flags; + } + + void Land::remove (int flags) + { + mDataTypes &= ~flags; + mDataLoaded &= ~flags; + + if (!mDataLoaded) + { + delete mLandData; + mLandData = 0; + } + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 64d131ecb9..56267a28c0 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -127,6 +127,17 @@ struct Land /// Return land data without loading first anything. Can return a 0-pointer. const LandData *getLandData() const; + /// Return land data without loading first anything. Can return a 0-pointer. + LandData *getLandData(); + + /// \attention Must not be called on objects that aren't fully loaded. + /// + /// \note Added data fields will be uninitialised + void add (int flags); + + /// \attention Must not be called on objects that aren't fully loaded. + void remove (int flags); + private: /// Loads data and marks it as loaded From d11952c48a7f2055b1bba79bd06c5180d15411d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 03:44:14 +0200 Subject: [PATCH 1023/1812] Stop rendering when the window is minimized --- apps/openmw/engine.cpp | 22 +++++++++++++++------- apps/openmw/mwbase/inputmanager.hpp | 2 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 32ff20ba70..6801363b18 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -92,10 +92,11 @@ void OMW::Engine::frame(float frametime) // update input mEnvironment.getInputManager()->update(frametime, false); - // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. - // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. - //if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) - // return true; + // When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug. + // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), + // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) + if (!mEnvironment.getInputManager()->isWindowVisible()) + return; // sound if (mUseSound) @@ -689,9 +690,16 @@ void OMW::Engine::go() frame(dt); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + if (!mEnvironment.getInputManager()->isWindowVisible()) + { + OpenThreads::Thread::microSleep(5000); + } + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } } // Save user settings diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 79477d883f..75c55e0289 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -25,6 +25,8 @@ namespace MWBase virtual ~InputManager() {} + virtual bool isWindowVisible() = 0; + virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74842e3e37..bd94d60c64 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -41,6 +41,7 @@ namespace MWInput const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) : mWindow(window) + , mWindowVisible(true) , mViewer(viewer) , mJoystickLastUsed(false) , mPlayer(NULL) @@ -156,6 +157,11 @@ namespace MWInput delete mVideoWrapper; } + bool InputManager::isWindowVisible() + { + return mWindowVisible; + } + void InputManager::setPlayerControlsEnabled(bool enabled) { int nPlayerChannels = 17; @@ -850,7 +856,7 @@ namespace MWInput void InputManager::windowVisibilityChange(bool visible) { - //TODO: Pause game? + mWindowVisible = visible; } void InputManager::windowResized(int x, int y) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index aec6407360..62d0f413ba 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -83,6 +83,8 @@ namespace MWInput virtual ~InputManager(); + virtual bool isWindowVisible(); + /// Clear all savegame-specific data virtual void clear(); @@ -153,6 +155,7 @@ namespace MWInput private: SDL_Window* mWindow; + bool mWindowVisible; osg::ref_ptr mViewer; bool mJoystickLastUsed; From acbea2461b0eb6596a86154f584759d0dc18a842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 23:27:33 +0200 Subject: [PATCH 1024/1812] Fix a typo --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 788aaca62a..f50991e24f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3156,7 +3156,7 @@ namespace MWWorld // Spawn the explosion orb effect const ESM::Static* areaStatic; - if (!effect->mCasting.empty()) + if (!effect->mArea.empty()) areaStatic = getStore().get().find (effect->mArea); else areaStatic = getStore().get().find ("VFX_DefaultArea"); From 96e3933ee9cdfbd17492ed2f2559b22e02b26909 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 6 Sep 2015 17:39:48 +1200 Subject: [PATCH 1025/1812] Fixed bug in smoothTurn() Now correctly handles changing direction from 178 to -178 degrees. --- apps/openmw/mwmechanics/steering.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 219a236554..1ef46e1aef 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -14,14 +14,16 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f { float currentAngle (actor.getRefData().getPosition().rot[axis]); float diff (targetAngleRadians - currentAngle); - if (diff >= osg::DegreesToRadians(180.f)) + if (std::abs(diff) >= osg::DegreesToRadians(180.f)) { - // Turning the other way would be a better idea - diff = diff-osg::DegreesToRadians(360.f); - } - else if (diff <= osg::DegreesToRadians(-180.f)) - { - diff = osg::DegreesToRadians(360.f)-diff; + if (diff >= 0) + { + diff = diff - osg::DegreesToRadians(360.f); + } + else + { + diff = osg::DegreesToRadians(360.f) + diff; + } } float absDiff = std::abs(diff); From b68f64ed97aff7c48d6878241ecd64d6acaba2f5 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Sun, 6 Sep 2015 21:46:05 +0200 Subject: [PATCH 1026/1812] adjust FindMyGUI.cmake to correctly handle REQUIRED and QUIETLY --- cmake/FindMyGUI.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index f85b6ba523..6e93a92ce6 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -146,11 +146,12 @@ IF (MYGUI_FOUND) IF (NOT MYGUI_FIND_QUIETLY) MESSAGE(STATUS "MyGUI version: ${MYGUI_VERSION}") ENDIF (NOT MYGUI_FIND_QUIETLY) - -ELSE (MYGUI_FOUND) - IF (MYGUI_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find MYGUI") - ENDIF (MYGUI_FIND_REQUIRED) ENDIF (MYGUI_FOUND) +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyGUI DEFAULT_MSG + MYGUI_INCLUDE_DIRS + FREETYPE_LIBRARIES + MYGUI_LIBRARIES) + CMAKE_POLICY(POP) From 481f23d955a8802b36cf7cc13ecb35c6c574b551 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 16:05:51 +0200 Subject: [PATCH 1027/1812] Implement framerate limit setting The framerate limit can be used to reduce strain on the CPU and GPU, in a way similar to VSync, but without the increased input lag that is typical with VSync. --- apps/openmw/engine.cpp | 12 ++++++++++++ files/settings-default.cfg | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6801363b18..79c8c4cc98 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -676,6 +676,7 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; + float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video"); while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); @@ -693,6 +694,7 @@ void OMW::Engine::go() if (!mEnvironment.getInputManager()->isWindowVisible()) { OpenThreads::Thread::microSleep(5000); + continue; } else { @@ -700,6 +702,16 @@ void OMW::Engine::go() mViewer->updateTraversal(); mViewer->renderingTraversals(); } + + if (framerateLimit > 0.f) + { + double thisFrameTime = frameTimer.time_s(); + double minFrameTime = 1.0 / framerateLimit; + if (thisFrameTime < minFrameTime) + { + OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); + } + } } // Save user settings diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f2b6aa34f7..c793225c22 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -20,6 +20,9 @@ vsync = false gamma = 1.00 contrast = 1.00 +# Maximum framerate in frames per second, 0 = unlimited +framerate limit = 0 + [GUI] scaling factor = 1.0 From 76fb68a9c0fceb2f7fc047ede26214ff18c5ea56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:07:09 +0200 Subject: [PATCH 1028/1812] Handle particle systems that don't have emitters Fixes a crash in the Magic Diversity mod. --- components/nifosg/nifloader.cpp | 47 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c980083943..54a02c9508 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -825,30 +825,33 @@ namespace NifOsg partsys->setFreezeOnCull(true); - osg::ref_ptr emitter = handleParticleEmitter(partctrl); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - - // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. - // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. - // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - - FindRecIndexVisitor find (partctrl->emitter->recIndex); - rootNode->accept(find); - if (!find.mFound) + if (!partctrl->emitter.empty()) { - std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; - return; + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + + FindRecIndexVisitor find (partctrl->emitter->recIndex); + rootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; + + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! + emitterNode->addChild(emitter); + + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); } - osg::Group* emitterNode = find.mFound; - - // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node - // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! - emitterNode->addChild(emitter); - - osg::ref_ptr callback(new ParticleSystemController(partctrl)); - setupController(partctrl, callback, animflags); - emitter->setUpdateCallback(callback); // affectors must be attached *after* the emitter in the scene graph for correct update order // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct From fd48c1d6f4312ca96a401f1cc6341835133a50d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 21:32:28 +0200 Subject: [PATCH 1029/1812] Make the Equip script function "use" items (drink potion, use alchemy, etc) --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++---- apps/openmw/mwgui/spellwindow.cpp | 3 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwscript/containerextensions.cpp | 12 +++++++----- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2d..fb7eca4a35 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -148,6 +148,9 @@ namespace MWBase virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item) = 0; + virtual void updateSpellWindow() = 0; virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f1e474a2f5..f2ae8dd837 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -21,8 +21,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "../mwgui/inventorywindow.hpp" - #include "itemselection.hpp" #include "spellview.hpp" #include "itemwidget.hpp" @@ -311,7 +309,7 @@ namespace MWGui else if (type == Type_Item) { MWWorld::Ptr item = *button->getUserData(); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand if (rightHand != store.end() && item == *rightHand) @@ -337,7 +335,7 @@ namespace MWGui // equip, if it can be equipped if (!item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 68a6042561..8422bb33fb 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -18,7 +18,6 @@ #include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" -#include "inventorywindow.hpp" #include "confirmationdialog.hpp" #include "spellview.hpp" @@ -104,7 +103,7 @@ namespace MWGui if (!alreadyEquipped && !item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 365f2c7a1e..90a5f74817 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1327,6 +1327,12 @@ namespace MWGui MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + void WindowManager::useItem(const MWWorld::Ptr &item) + { + if (mInventoryWindow) + mInventoryWindow->useItem(item); + } + bool WindowManager::isAllowed (GuiWindow wnd) const { return (mAllowed & wnd) != 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 336a2a19a6..a1f76683e5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -173,6 +173,9 @@ namespace MWGui virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item); + virtual void updateSpellWindow(); virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 20ca2b5800..ec14add9aa 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -191,11 +191,13 @@ namespace MWScript if (it == invStore.end()) throw std::runtime_error("Item to equip not found"); - MWWorld::ActionEquip action (*it); - action.execute(ptr); - - if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) - ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->useItem(*it); + else + { + boost::shared_ptr action = it->getClass().use(*it); + action->execute(ptr); + } } }; From e5d54fb539e92ec2bf9754e4b06cceee9f90f1da Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:13:20 +0200 Subject: [PATCH 1030/1812] Check for actor being the player in various actions --- apps/openmw/mwworld/actionalchemy.cpp | 3 +++ apps/openmw/mwworld/actionapply.cpp | 2 +- apps/openmw/mwworld/actioneat.cpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 +++ apps/openmw/mwworld/actionrepair.cpp | 3 +++ apps/openmw/mwworld/actionsoulgem.cpp | 3 +++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bbba1081c3..f413f1aed8 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -10,6 +10,9 @@ namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 00c9628cec..42757a41a1 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -32,7 +32,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index d9ca4aaf58..5339a113e5 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -19,7 +19,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor)) + if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index cd0471a0ea..d77ca73fda 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -18,6 +18,9 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + //Ensure we're not in combat if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 699440a01c..993f32cdeb 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -14,6 +14,9 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index 7237fd3342..f87c16482f 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -16,6 +16,9 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; From 5aa33fde4300b8e165905d41534d37d85d915ac1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:16:15 +0200 Subject: [PATCH 1031/1812] Include cleanup --- apps/openmw/mwscript/containerextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ec14add9aa..e33c7580fb 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -23,7 +23,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/actorutil.hpp" From 0442bc98f3e0a6fd52fdf9f7bd1a59cf3e87bddc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:31:11 +0200 Subject: [PATCH 1032/1812] Update sleep interruption formula according to wiki, thanks Hrnchamd --- apps/openmw/mwgui/waitdialog.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 733fdd132b..e8ac63bf6b 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -158,11 +158,15 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < static_cast(fSleepRandMod * hoursToWait)) + if (x < fSleepRandMod * hoursToWait) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); - mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); - mInterruptCreatureList = region->mSleepList; + int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait); + if (interruptAtHoursRemaining != 0) + { + mInterruptAt = hoursToWait - interruptAtHoursRemaining; + mInterruptCreatureList = region->mSleepList; + } } } } From b98a0760557c712bc1987b2646890027b6f185cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 23:27:14 +0200 Subject: [PATCH 1033/1812] Add documentation for ACTN ess-record (activation flags) --- apps/essimporter/importacdt.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9d881515dd..a5f9d6eb3b 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -10,7 +10,21 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { if (esm.isNextSub("ACTN")) + { + /* + Activation flags: + ActivationFlag_UseEnabled = 1 + ActivationFlag_OnActivate = 2 + ActivationFlag_OnDeath = 10h + ActivationFlag_OnKnockout = 20h + ActivationFlag_OnMurder = 40h + ActivationFlag_DoorOpening = 100h + ActivationFlag_DoorClosing = 200h + ActivationFlag_DoorJammedOpening = 400h + ActivationFlag_DoorJammedClosing = 800h + */ esm.skipHSub(); + } if (esm.isNextSub("STPR")) esm.skipHSub(); From 73f6efddcc1b6f5816f9f775418c6317cf74ee20 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 15:33:15 +0200 Subject: [PATCH 1034/1812] fixed a texture indexing bug (only affects the editor) --- apps/opencs/model/tools/mergestages.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f4cb42aa4c..e24d1f9118 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -179,6 +179,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes CSMWorld::LandTexture texture = mState.mSource.getData().getLandTextures().getRecord (index).get(); + std::ostringstream stream; + stream << mNext->second << "_0"; + texture.mIndex = mNext->second; texture.mId = stream.str(); From 09ec60fe2a7b2cce91ee5f2271db4479b97ae228 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 16:01:34 +0200 Subject: [PATCH 1035/1812] handle missing land texture records properly during merge --- apps/opencs/model/tools/mergestages.cpp | 49 ++++++++++++++----------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index e24d1f9118..fab5fae71f 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -164,35 +164,42 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (stage==0) mNext = mState.mTextureIndices.begin(); - if (mNext==mState.mTextureIndices.end()) - return; + bool found = false; - mNext->second = stage; - - std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; - - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - - if (index!=-1) + do { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); + if (mNext==mState.mTextureIndices.end()) + return; + + mNext->second = stage; std::ostringstream stream; - stream << mNext->second << "_0"; + stream << mNext->first.first << "_" << mNext->first.second; - texture.mIndex = mNext->second; - texture.mId = stream.str(); + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + std::ostringstream stream; + stream << mNext->second << "_0"; + + texture.mIndex = mNext->second; + texture.mId = stream.str(); + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + + found = true; + } + + ++mNext; } - /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) - - ++mNext; + while (!found); } From 29d74f024910c36ad6a474dbca4ccffe7db2e073 Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 8 Sep 2015 22:05:33 -0500 Subject: [PATCH 1036/1812] Improve thunderstorm support. Reversed settings for thunderstorms. Added thunder support to all weather types. Implemented a simple lightning flash effect similar to MW. --- apps/openmw/mwrender/sky.cpp | 14 --- apps/openmw/mwrender/sky.hpp | 2 - apps/openmw/mwworld/weather.cpp | 169 +++++++++++++++++--------------- apps/openmw/mwworld/weather.hpp | 32 +++--- 4 files changed, 109 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 138365ae4f..dba2e5b0eb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1181,20 +1181,6 @@ void SkyManager::setSecundaState(const MoonState& state) mSecunda->setState(state); } -void SkyManager::setLightningStrength(const float factor) -{ - if (!mCreated) return; - /* - if (factor > 0.f) - { - mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); - mLightning->setVisible(true); - } - else - mLightning->setVisible(false); - */ -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 3855136a98..de27cf4479 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,6 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setLightningStrength(const float factor); - void setGlare(const float glare); void setGlareEnabled(bool enabled); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index e7c67d2e1d..cdd0a8d79b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -80,15 +80,24 @@ Weather::Weather(const std::string& name, , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Threshold")) + , mThunderSoundID() + , mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement")) + , mFlashBrightness(0.0f) { -/* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ + mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0"); + mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); + mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); + mThunderSoundID[3] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_3"); + /* + Unhandled: + Rain Diameter=600 ? + Rain Height Min=200 ? + Rain Height Max=700 ? + Rain Threshold=0.6 ? + Max Raindrops=650 ? + */ } float Weather::transitionDelta() const @@ -98,12 +107,66 @@ float Weather::transitionDelta() const return mTransitionDelta; } -float Weather::cloudBlendFactor(float transitionRatio) const +float Weather::cloudBlendFactor(const float transitionRatio) const { // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. return transitionRatio / mCloudsMaximumPercent; } +float Weather::calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused) +{ + // When paused, the flash brightness remains the same and no new strikes can occur. + if(!isPaused) + { + // Morrowind doesn't appear to do any calculations unless the transition ratio is higher than the Thunder Threshold. + if(transitionRatio >= mThunderThreshold && mThunderFrequency > 0.0f) + { + flashDecrement(elapsedSeconds); + + if(Misc::Rng::rollProbability() <= thunderChance(transitionRatio, elapsedSeconds)) + { + lightningAndThunder(); + } + } + else + { + mFlashBrightness = 0.0f; + } + } + + return mFlashBrightness; +} + +inline void Weather::flashDecrement(const float elapsedSeconds) +{ + // The Flash Decrement is measured in whole units per second. This means that if the flash brightness was + // currently 1.0, then it should take approximately 0.25 seconds to decay to 0.0 (the minimum). + float decrement = mFlashDecrement * elapsedSeconds; + mFlashBrightness = decrement > mFlashBrightness ? 0.0f : mFlashBrightness - decrement; +} + +inline float Weather::thunderChance(const float transitionRatio, const float elapsedSeconds) const +{ + // This formula is reversed from the observation that with Thunder Frequency set to 1, there are roughly 10 strikes + // per minute. It doesn't appear to be tied to in game time as Timescale doesn't affect it. Various values of + // Thunder Frequency seem to change the average number of strikes in a linear fashion.. During a transition, it appears to + // scaled based on how far past it is past the Thunder Threshold. + float scaleFactor = (transitionRatio - mThunderThreshold) / (1.0f - mThunderThreshold); + return ((mThunderFrequency * 10.0f) / 60.0f) * elapsedSeconds * scaleFactor; +} + +inline void Weather::lightningAndThunder(void) +{ + // Morrowind seems to vary the intensity of the brightness based on which of the four sound IDs it selects. + // They appear to go from 0 (brightest, closest) to 3 (faintest, farthest). The value of 0.25 per distance + // was derived by setting the Flash Decrement to 0.1 and measuring how long each value took to decay to 0. + // TODO: Determine the distribution of each distance to see if it's evenly weighted. + unsigned int distance = Misc::Rng::rollDice(4); + // Flash brightness appears additive, since if multiple strikes occur, it takes longer for it to decay to 0. + mFlashBrightness += 1 - (distance * 0.25f); + MWBase::Environment::get().getSoundManager()->playSound(mThunderSoundID[distance], 1.0, 1.0); +} + RegionWeather::RegionWeather(const ESM::Region& region) : mWeather(invalidWeatherID) , mChances() @@ -378,19 +441,9 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) - , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) - , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) - , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) - , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) - , mThunderSoundDelay(0.25) - , mThunderFlash(0) - , mThunderChance(0) - , mThunderChanceNeeded(50) , mCurrentRegion() , mTimePassed(0) , mFastForward(false) @@ -515,12 +568,11 @@ void WeatherManager::update(float duration, bool paused) if(!exterior) { mRendering.setSkyEnabled(false); - //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - calculateWeatherResult(time.getHour()); + calculateWeatherResult(time.getHour(), duration, paused); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; @@ -536,8 +588,6 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); - // disable sun during night if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); @@ -577,56 +627,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - if (!paused) - { - if(mCurrentWeather == 5 && !inTransition()) - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = Misc::Rng::rollDice(4); - std::string* soundName = NULL; - if (sound == 0) soundName = &mThunderSoundID0; - else if (sound == 1) soundName = &mThunderSoundID1; - else if (sound == 2) soundName = &mThunderSoundID2; - else if (sound == 3) soundName = &mThunderSoundID3; - if (soundName) - MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - //if (mThunderFlash > 0) - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - //else - { - mThunderChanceNeeded = static_cast(Misc::Rng::rollDice(100)); - mThunderChance = 0; - //mRendering->getSkyManager()->setLightningStrength( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = mThunderThreshold; - - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - - mThunderSoundDelay = 0.25; - } - } - } - //else - //mRendering->getSkyManager()->setLightningStrength(0.f); - } - + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); @@ -765,10 +766,6 @@ void WeatherManager::clear() { stopSounds(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - mCurrentRegion = ""; mTimePassed = 0.0f; mWeatherUpdateTime = 0.0f; @@ -921,16 +918,32 @@ inline void WeatherManager::addWeatherTransition(const int weatherID) } } -inline void WeatherManager::calculateWeatherResult(const float gameHour) +inline void WeatherManager::calculateWeatherResult(const float gameHour, + const float elapsedSeconds, + const bool isPaused) { + float flash = 0.0f; if(!inTransition()) { calculateResult(mCurrentWeather, gameHour); + flash = mWeatherSettings[mCurrentWeather].calculateThunder(1.0f, elapsedSeconds, isPaused); } else { calculateTransitionResult(1 - mTransitionFactor, gameHour); + float currentFlash = mWeatherSettings[mCurrentWeather].calculateThunder(mTransitionFactor, + elapsedSeconds, + isPaused); + float nextFlash = mWeatherSettings[mNextWeather].calculateThunder(1 - mTransitionFactor, + elapsedSeconds, + isPaused); + flash = currentFlash + nextFlash; } + osg::Vec4f flashColor(flash, flash, flash, 0.0f); + + mResult.mFogColor += flashColor; + mResult.mAmbientColor += flashColor; + mResult.mSunColor += flashColor; } inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index c808b029b9..a0c93a4604 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -113,11 +113,27 @@ namespace MWWorld // is broken in the vanilla game and was disabled. float transitionDelta() const; - float cloudBlendFactor(float transitionRatio) const; + float cloudBlendFactor(const float transitionRatio) const; + + float calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused); private: float mTransitionDelta; float mCloudsMaximumPercent; + + // Note: In MW, only thunderstorms support these attributes, but in the interest of making weather more + // flexible, these settings are imported for all weather types. Only thunderstorms will normally have any + // non-zero values. + float mThunderFrequency; + float mThunderThreshold; + std::string mThunderSoundID[4]; + float mFlashDecrement; + + float mFlashBrightness; + + void flashDecrement(const float elapsedSeconds); + float thunderChance(const float transitionRatio, const float elapsedSeconds) const; + void lightningAndThunder(void); }; /// A class for storing a region's weather. @@ -242,22 +258,10 @@ namespace MWWorld MoonModel mMasser; MoonModel mSecunda; - float mThunderFrequency; - float mThunderThreshold; - std::string mThunderSoundID0; - std::string mThunderSoundID1; - std::string mThunderSoundID2; - std::string mThunderSoundID3; - float mWindSpeed; bool mIsStorm; osg::Vec3f mStormDirection; - float mThunderSoundDelay; - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - std::string mCurrentRegion; float mTimePassed; bool mFastForward; @@ -288,7 +292,7 @@ namespace MWWorld bool inTransition(); void addWeatherTransition(const int weatherID); - void calculateWeatherResult(const float gameHour); + void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused); void calculateResult(const int weatherID, const float gameHour); void calculateTransitionResult(const float factor, const float gameHour); }; From e9c796166ae6866a118b0fec8a045373e5dc4577 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 18:48:34 +1200 Subject: [PATCH 1037/1812] Added MWMechanics::isPlayerInCombat() --- apps/openmw/mwmechanics/actorutil.cpp | 7 +++++++ apps/openmw/mwmechanics/actorutil.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/actionalchemy.cpp | 5 +++-- apps/openmw/mwworld/actionapply.cpp | 4 +++- apps/openmw/mwworld/actioneat.cpp | 4 +++- apps/openmw/mwworld/actionread.cpp | 5 +++-- apps/openmw/mwworld/actionrepair.cpp | 5 +++-- apps/openmw/mwworld/actionsoulgem.cpp | 5 +++-- 9 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp index dc37705563..537f271974 100644 --- a/apps/openmw/mwmechanics/actorutil.cpp +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -3,10 +3,17 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + namespace MWMechanics { MWWorld::Ptr getPlayer() { return MWBase::Environment::get().getWorld()->getPlayerPtr(); } + + bool isPlayerInCombat() + { + return MWBase::Environment::get().getWorld()->getPlayer().isInCombat(); + } } diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 95172b9f91..3c6dc940c5 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -9,6 +9,7 @@ namespace MWWorld namespace MWMechanics { MWWorld::Ptr getPlayer(); + bool isPlayerInCombat(); } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 711ecdbd28..12927101d8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -927,7 +927,7 @@ namespace MWMechanics return true; } - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); return true; } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index f413f1aed8..53ed1ad848 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,15 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 42757a41a1..e3699a6ac3 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWWorld { ActionApply::ActionApply (const Ptr& object, const std::string& id) @@ -32,7 +34,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 5339a113e5..82c7fb80e4 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "class.hpp" namespace MWWorld @@ -19,7 +21,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index d77ca73fda..90e9a375b3 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -5,6 +5,7 @@ #include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "player.hpp" #include "class.hpp" @@ -18,11 +19,11 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; //Ensure we're not in combat - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() + if(MWMechanics::isPlayerInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet // (since otherwise, there would be no way to pick it up) && getTarget().getContainerStore() == &actor.getClass().getContainerStore(actor) diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 993f32cdeb..8e19927b80 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -4,6 +4,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -14,10 +15,10 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; } diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index f87c16482f..98fe8ee34d 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -16,10 +17,10 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; } From 573a14993ac1d41979c805cd6298bd9f82227a64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 21:53:31 +1200 Subject: [PATCH 1038/1812] Moved isActorNearInactiveCell() logic to own function. Also, triggers when actor is near edge of cell, not when less than 1/2 way to edge. --- apps/openmw/mwmechanics/aipackage.cpp | 62 ++++++++++++++------------- apps/openmw/mwmechanics/aipackage.hpp | 1 + 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index b6b2408338..e5da16865f 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,6 +16,7 @@ #include "steering.hpp" #include "actorutil.hpp" +#include "coordinateconverter.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -32,45 +33,24 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell - const ESM::Cell *cell = actor.getCell()->getCell(); + //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 + //... units from player, and exterior cells are 8192 units long and wide. + //... But AI processing distance may increase in the future. + if (isActorNearInactiveCell(pos)) { - MWWorld::Ptr player = getPlayer(); - Movement &movement = actor.getClass().getMovementSettings(actor); - - //Ensure pursuer doesn't leave loaded cells - if(cell->mData.mX != player.getCell()->getCell()->mData.mX) - { - int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } - if(cell->mData.mY != player.getCell()->getCell()->mData.mY) - { - int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + return false; } - //Start position - ESM::Pathgrid::Point start = pos.pos; - //*********************** /// Checks if you can't get to the end position at all, adds end position to end of path /// Rebuilds path every quarter of a second, in case the target has moved //*********************** if(mTimer > 0.25) { + const ESM::Cell *cell = actor.getCell()->getCell(); if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved + mPathFinder.buildSyncedPath(pos.pos, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } @@ -133,3 +113,27 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } + +bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +{ + const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + if (playerCell->isExterior()) + { + // get actor's distance from origin of center cell + osg::Vec3f actorOffset(actorPos.asVec3()); + CoordinateConverter(playerCell).ToLocal(actorOffset); + + // currently assumes 3 x 3 grid for exterior cells, with player at center cell. + // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells + // While AI Process distance is 7168, AI shuts down actors before they reach edges of 3 x 3 grid. + const float distanceFromEdge = 200.0; + float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge; + float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge; + return (actorOffset[0] < minThreshold) || (maxThreshold < actorOffset[0]) + || (actorOffset[1] < minThreshold) || (maxThreshold < actorOffset[1]); + } + else + { + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4f919edbc6..befd159bf0 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,6 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + bool isActorNearInactiveCell(const ESM::Position& actorPos); }; } From 6f97187bb6558c44978d106b1394fe2c353406c1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 22:26:33 +1200 Subject: [PATCH 1039/1812] Fix travis warning about no newline at end of file. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index e5da16865f..c4091c63ef 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -136,4 +136,4 @@ bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorP { return false; } -} \ No newline at end of file +} From 584a7a66b97739c91c38cf8f17922ba29d5536e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Sep 2015 12:41:31 +0200 Subject: [PATCH 1040/1812] various minor fixes --- apps/opencs/model/tools/mergestages.cpp | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index fab5fae71f..f7c3b8dc05 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - const ESM::Land& land = record.get(); + const CSMWorld::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | @@ -228,22 +228,25 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) // because record is already fully loaded) newLand.mPlugin = 0; - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) + if (land.mDataTypes & ESM::Land::DATA_VTEX) { - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); + std::pair key; + key.second = land.mPlugin; - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } } } From 10eabc9d519d27d5a02c66e7c7bb886ad55228b2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 11 Sep 2015 18:43:06 +1200 Subject: [PATCH 1041/1812] actorutil.hpp includes mwworld/ptr.hpp As pointed out by Scrawl, fixes compiler error if getPlayer() is called before MWWorld::Ptr is defined, because getPlayer() returns a Ptr by value. --- apps/openmw/mwmechanics/actorutil.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 3c6dc940c5..510e41db35 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -1,10 +1,7 @@ #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H -namespace MWWorld -{ - class Ptr; -} +#include "../mwworld/ptr.hpp" namespace MWMechanics { From 23fde87816644912c9896920b80348429a045003 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 10:50:19 +0200 Subject: [PATCH 1042/1812] fixed an indexing error --- apps/opencs/model/tools/mergestages.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f7c3b8dc05..52e1e69649 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -171,10 +171,10 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (mNext==mState.mTextureIndices.end()) return; - mNext->second = stage; + mNext->second = stage+1; std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; + stream << mNext->first.first-1 << "_" << mNext->first.second; int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); @@ -184,9 +184,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes mState.mSource.getData().getLandTextures().getRecord (index).get(); std::ostringstream stream; - stream << mNext->second << "_0"; + stream << mNext->second-1 << "_0"; - texture.mIndex = mNext->second; + texture.mIndex = mNext->second-1; texture.mId = stream.str(); CSMWorld::Record newRecord ( From 5be176ee85da349163e161f86693f836fb1b5fdc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 13:02:24 +0200 Subject: [PATCH 1043/1812] disable on-demand loading of land data (for now, maybe) --- apps/opencs/model/world/data.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fe6d6ccbbd..a957619299 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -955,8 +955,10 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { int index = mLand.load(*mReader, mBase); - if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.loadData ( + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + if (index!=-1/* && !mBase*/) + mLand.getRecord (index).get().loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); From 5252dbcf1f4dc311419ca9f7d5f32a765771d1e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Sep 2015 21:09:54 +0200 Subject: [PATCH 1044/1812] Add some comments to ESM::Land --- components/esm/loadland.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 56267a28c0..8ec4f74ea0 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -76,17 +76,29 @@ struct Land struct LandData { + // Initial reference height for the first vertex, only needed for filling mHeights float mHeightOffset; + // Height in world space for each vertex float mHeights[LAND_NUM_VERTS]; + + // 24-bit normals, these aren't always correct though. Edge and corner normals may be garbage. VNML mNormals[LAND_NUM_VERTS * 3]; + + // 2D array of texture indices. An index can be used to look up an ESM::LandTexture, + // but to do so you must subtract 1 from the index first! + // An index of 0 indicates the default texture. uint16_t mTextures[LAND_NUM_TEXTURES]; + // 24-bit RGB color for each vertex unsigned char mColours[3 * LAND_NUM_VERTS]; + + // DataTypes available in this LandData, accessing data that is not available is an undefined operation int mDataTypes; // low-LOD heightmap (used for rendering the global map) signed char mWnam[81]; + // ??? short mUnk1; uint8_t mUnk2; From 258b2ba29abedf329db1db2c5660cf213445c999 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:04:43 +1000 Subject: [PATCH 1045/1812] Ensure ColumnId names are unique. Filter parser calls Columns::getId() which implies that these should be unique. --- apps/opencs/model/world/columns.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 045438befe..e6dabc4d77 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -265,7 +265,7 @@ namespace CSMWorld { ColumnId_LevelledList,"Levelled List" }, { ColumnId_LevelledItemId,"Levelled Item" }, - { ColumnId_LevelledItemLevel,"Level" }, + { ColumnId_LevelledItemLevel,"Item Level" }, { ColumnId_LevelledItemType, "Calculate all levels <= player" }, { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, @@ -281,26 +281,26 @@ namespace CSMWorld { ColumnId_InfoCondValue, "Values" }, { ColumnId_OriginalCell, "Original Cell" }, - { ColumnId_NpcAttributes, "Attributes" }, - { ColumnId_NpcSkills, "Skills" }, + { ColumnId_NpcAttributes, "NPC Attributes" }, + { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, - { ColumnId_NpcMisc, "Misc" }, + { ColumnId_NpcMisc, "NPC Misc" }, { ColumnId_NpcLevel, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "Health" }, + { ColumnId_NpcHealth, "NPC Health" }, { ColumnId_NpcMana, "Mana" }, { ColumnId_NpcFatigue, "Fatigue" }, - { ColumnId_NpcDisposition, "Disposition" }, + { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, - { ColumnId_NpcRank, "Rank" }, + { ColumnId_NpcRank, "NPC Rank" }, { ColumnId_NpcGold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, - { ColumnId_RaceAttributes, "Attributes" }, - { ColumnId_RaceMaleValue, "Male" }, - { ColumnId_RaceFemaleValue, "Female" }, + { ColumnId_RaceAttributes, "Race Attributes" }, + { ColumnId_RaceMaleValue, "Male Attrib" }, + { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Skills" }, + { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, From c4a900ca2c9b98267c9a507bb887829373fc9193 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:33:11 +1000 Subject: [PATCH 1046/1812] Rationalise the use of ColumnIds --- apps/opencs/model/world/columns.cpp | 15 +++++---------- apps/opencs/model/world/columns.hpp | 14 +++++++------- apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/nestedcoladapterimp.cpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 15 ++------------- apps/opencs/model/world/refidcollection.cpp | 14 +++++++------- apps/opencs/view/doc/viewmanager.cpp | 1 - 7 files changed, 24 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e6dabc4d77..9f39be5f31 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -199,8 +199,6 @@ namespace CSMWorld { ColumnId_RotY, "Rotation Y"}, { ColumnId_RotZ, "Rotation Z"}, - { ColumnId_Skill, "Skill" }, - { ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, @@ -271,7 +269,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, - { ColumnId_SkillImpact, "Skills" }, + { ColumnId_SkillImpact, "Skill" }, { ColumnId_InfoList, "Info List" }, { ColumnId_InfoCondition, "Info Conditions" }, @@ -285,22 +283,20 @@ namespace CSMWorld { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, { ColumnId_NpcMisc, "NPC Misc" }, - { ColumnId_NpcLevel, "Level" }, + { ColumnId_Level, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "NPC Health" }, - { ColumnId_NpcMana, "Mana" }, - { ColumnId_NpcFatigue, "Fatigue" }, + { ColumnId_Mana, "Mana" }, + { ColumnId_Fatigue, "Fatigue" }, { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, { ColumnId_NpcRank, "NPC Rank" }, - { ColumnId_NpcGold, "Gold" }, + { ColumnId_Gold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, { ColumnId_RaceMaleValue, "Male Attrib" }, { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, @@ -579,7 +575,6 @@ namespace // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; - case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2f66542b1e..5deaf65cb5 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -189,7 +189,7 @@ namespace CSMWorld ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, - ColumnId_Skill = 177, + // unused ColumnId_OwnerGlobal = 178, ColumnId_DefaultProfile = 179, ColumnId_BypassNewGame = 180, @@ -276,22 +276,22 @@ namespace CSMWorld ColumnId_NpcSkills = 249, ColumnId_UChar = 250, ColumnId_NpcMisc = 251, - ColumnId_NpcLevel = 252, + ColumnId_Level = 252, ColumnId_NpcFactionID = 253, - ColumnId_NpcHealth = 254, - ColumnId_NpcMana = 255, - ColumnId_NpcFatigue = 256, + // unused + ColumnId_Mana = 255, + ColumnId_Fatigue = 256, ColumnId_NpcDisposition = 257, ColumnId_NpcReputation = 258, ColumnId_NpcRank = 259, - ColumnId_NpcGold = 260, + ColumnId_Gold = 260, ColumnId_NpcPersistence = 261, ColumnId_RaceAttributes = 262, ColumnId_RaceMaleValue = 263, ColumnId_RaceFemaleValue = 264, ColumnId_RaceSkillBonus = 265, - ColumnId_RaceSkill = 266, + // unused ColumnId_RaceBonus = 267, ColumnId_Interior = 268, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ab9c8f74e8..a27ab50944 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -140,7 +140,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); @@ -151,7 +151,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index dc5cd22993..002838c67d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -922,7 +922,7 @@ namespace CSMWorld switch (subColIndex) { - case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str()); + case 0: return subRowIndex; case 1: return race.mData.mAttributeValues[subRowIndex].mMale; case 2: return race.mData.mAttributeValues[subRowIndex].mFemale; default: throw std::runtime_error("Race Attribute subcolumn index out of range"); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index c8cca5c3df..6a881d0af8 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -694,18 +694,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn * const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; if (subColIndex == 0) - switch (subRowIndex) - { - case 0: return QString("Strength"); - case 1: return QString("Intelligence"); - case 2: return QString("Willpower"); - case 3: return QString("Agility"); - case 4: return QString("Speed"); - case 5: return QString("Endurance"); - case 6: return QString("Personality"); - case 7: return QString("Luck"); - default: return QVariant(); // throw an exception here? - } + return subRowIndex; else if (subColIndex == 1) switch (subRowIndex) { @@ -815,7 +804,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu throw std::runtime_error ("index out of range"); if (subColIndex == 0) - return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); + return subRowIndex; else if (subColIndex == 1) return static_cast(npcStruct.mSkills[subRowIndex]); else diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c4d1107543..b20e12fef3 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -439,7 +439,7 @@ CSMWorld::RefIdCollection::RefIdCollection() attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -451,7 +451,7 @@ CSMWorld::RefIdCollection::RefIdCollection() skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -463,15 +463,15 @@ CSMWorld::RefIdCollection::RefIdCollection() miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -479,7 +479,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 60219d319c..ca4ad2d004 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -104,7 +104,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, - { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, }; for (std::size_t i=0; i Date: Sat, 12 Sep 2015 10:00:23 +1000 Subject: [PATCH 1047/1812] Add missing fields for editing creatures. - Should resolve resolve bugs #2878 (level), #2901 (gold) and #2889 (health). - Moved Soul, Combat, Magic and Stealth editing to dialogue only (to be consistent with editing NPCs) --- apps/opencs/model/world/columns.cpp | 7 + apps/opencs/model/world/columns.hpp | 7 + apps/opencs/model/world/refidadapterimp.cpp | 313 ++++++++++++++++++-- apps/opencs/model/world/refidadapterimp.hpp | 98 +++++- apps/opencs/model/world/refidcollection.cpp | 64 +++- 5 files changed, 453 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9f39be5f31..44ec9d384f 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -311,6 +311,13 @@ namespace CSMWorld { ColumnId_FileDescription, "File Description" }, { ColumnId_Author, "Author" }, + { ColumnId_CreatureAttributes, "Creature Attributes" }, + { ColumnId_AttributeValue, "Attrib Value" }, + { ColumnId_CreatureAttack, "Creature Attack" }, + { ColumnId_MinAttack, "Min Attack" }, + { ColumnId_MaxAttack, "Max Attack" }, + { ColumnId_CreatureMisc, "Creature Misc" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5deaf65cb5..981599e531 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -309,6 +309,13 @@ namespace CSMWorld ColumnId_MinMagnitude = 278, ColumnId_MaxMagnitude = 279, + ColumnId_CreatureAttributes = 280, + ColumnId_AttributeValue = 281, + ColumnId_CreatureAttack = 282, + ColumnId_MinAttack = 283, + ColumnId_MaxAttack = 284, + ColumnId_CreatureMisc = 285, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 6a881d0af8..da0cc07600 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -296,12 +296,11 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), mType(NULL), - mSoul(NULL), mScale(NULL), mOriginal(NULL), - mCombat(NULL), - mMagic(NULL), - mStealth(NULL) + mAttributes(NULL), + mAttacks(NULL), + mMisc(NULL) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -317,23 +316,20 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con if (column==mColumns.mType) return record.get().mData.mType; - if (column==mColumns.mSoul) - return record.get().mData.mSoul; - if (column==mColumns.mScale) return record.get().mScale; if (column==mColumns.mOriginal) return QString::fromUtf8 (record.get().mOriginal.c_str()); - if (column==mColumns.mCombat) - return static_cast (record.get().mData.mCombat); + if (column==mColumns.mAttributes) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mMagic) - return static_cast (record.get().mData.mMagic); + if (column==mColumns.mAttacks) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mStealth) - return static_cast (record.get().mData.mStealth); + if (column==mColumns.mMisc) + return true; // Required to show nested items in dialogue subview std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -354,18 +350,10 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa if (column==mColumns.mType) creature.mData.mType = value.toInt(); - else if (column==mColumns.mSoul) - creature.mData.mSoul = value.toInt(); else if (column==mColumns.mScale) creature.mScale = value.toFloat(); else if (column==mColumns.mOriginal) creature.mOriginal = value.toString().toUtf8().constData(); - else if (column==mColumns.mCombat) - creature.mData.mCombat = value.toInt(); - else if (column==mColumns.mMagic) - creature.mData.mMagic = value.toInt(); - else if (column==mColumns.mStealth) - creature.mData.mStealth = value.toInt(); else { std::map::const_iterator iter = @@ -964,6 +952,289 @@ int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, return 1; // fixed at size 1 } +CSMWorld::CreatureAttributesRefIdAdapter::CreatureAttributesRefIdAdapter() +{} + +void CSMWorld::CreatureAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttributesRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subColIndex == 0) + return subRowIndex; + else if (subColIndex == 1) + switch (subRowIndex) + { + case 0: return creature.mData.mStrength; + case 1: return creature.mData.mIntelligence; + case 2: return creature.mData.mWillpower; + case 3: return creature.mData.mAgility; + case 4: return creature.mData.mSpeed; + case 5: return creature.mData.mEndurance; + case 6: return creature.mData.mPersonality; + case 7: return creature.mData.mLuck; + default: return QVariant(); // throw an exception here? + } + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subColIndex == 1) + switch(subRowIndex) + { + case 0: creature.mData.mStrength = value.toInt(); break; + case 1: creature.mData.mIntelligence = value.toInt(); break; + case 2: creature.mData.mWillpower = value.toInt(); break; + case 3: creature.mData.mAgility = value.toInt(); break; + case 4: creature.mData.mSpeed = value.toInt(); break; + case 5: creature.mData.mEndurance = value.toInt(); break; + case 6: creature.mData.mPersonality = value.toInt(); break; + case 7: creature.mData.mLuck = value.toInt(); break; + default: return; // throw an exception here? + } + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 8 attributes + return 8; +} + +CSMWorld::CreatureAttackRefIdAdapter::CreatureAttackRefIdAdapter() +{} + +void CSMWorld::CreatureAttackRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttackRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + return subRowIndex + 1; + else if (subColIndex < 3) // 1 or 2 + return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)]; + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 1 || subColIndex == 2) + creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)] = value.toInt(); + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 3; +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 3 attacks + return 3; +} + +CSMWorld::CreatureMiscRefIdAdapter::CreatureMiscRefIdAdapter() +{} + +CSMWorld::CreatureMiscRefIdAdapter::~CreatureMiscRefIdAdapter() +{} + +void CSMWorld::CreatureMiscRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + throw std::logic_error ("cannot add a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + throw std::logic_error ("cannot remove a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + throw std::logic_error ("table operation not supported"); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureMiscRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + throw std::logic_error ("table operation not supported"); +} + +QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + switch (subColIndex) + { + case 0: return creature.mData.mLevel; + case 1: return creature.mData.mHealth; + case 2: return creature.mData.mMana; + case 3: return creature.mData.mFatigue; + case 4: return creature.mData.mSoul; + case 5: return creature.mData.mCombat; + case 6: return creature.mData.mMagic; + case 7: return creature.mData.mStealth; + case 8: return creature.mData.mGold; + default: return QVariant(); // throw an exception here? + } +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + switch(subColIndex) + { + case 0: creature.mData.mLevel = value.toInt(); break; + case 1: creature.mData.mHealth = value.toInt(); break; + case 2: creature.mData.mMana = value.toInt(); break; + case 3: creature.mData.mFatigue = value.toInt(); break; + case 4: creature.mData.mSoul = value.toInt(); break; + case 5: creature.mData.mCombat = value.toInt(); break; + case 6: creature.mData.mMagic = value.toInt(); break; + case 7: creature.mData.mStealth = value.toInt(); break; + case 8: creature.mData.mGold = value.toInt(); break; + default: return; // throw an exception here? + } + + record.setModified (creature); +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 9; // Level, Health, Mana, Fatigue, Soul, Combat, Magic, Steath, Gold +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 1; // fixed at size 1 +} + CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns) : EnchantableColumns (columns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 5ceb3325ae..41f2543558 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -696,12 +696,11 @@ namespace CSMWorld { std::map mFlags; const RefIdColumn *mType; - const RefIdColumn *mSoul; const RefIdColumn *mScale; const RefIdColumn *mOriginal; - const RefIdColumn *mCombat; - const RefIdColumn *mMagic; - const RefIdColumn *mStealth; + const RefIdColumn *mAttributes; + const RefIdColumn *mAttack; + const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); }; @@ -938,6 +937,97 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; }; + class CreatureAttributesRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttributesRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureAttackRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttackRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureMiscRefIdAdapter : public NestedRefIdAdapterBase + { + CreatureMiscRefIdAdapter (const CreatureMiscRefIdAdapter&); + CreatureMiscRefIdAdapter& operator= (const CreatureMiscRefIdAdapter&); + + public: + + CreatureMiscRefIdAdapter (); + virtual ~CreatureMiscRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + template class EffectsListAdapter; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index b20e12fef3..f8c9e28fe4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -297,21 +297,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); creatureColumns.mType = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_SoulPoints, ColumnBase::Display_Integer)); - creatureColumns.mSoul = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); - creatureColumns.mCombat = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_MagicState, ColumnBase::Display_Integer)); - creatureColumns.mMagic = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_StealthState, ColumnBase::Display_Integer)); - creatureColumns.mStealth = &mColumns.back(); static const struct { @@ -350,6 +339,59 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttributes = &mColumns.back(); + std::map creaAttrMap; + creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaAttrMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer)); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttacks = &mColumns.back(); + std::map attackMap; + attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attackMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MinAttack, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer)); + + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + creatureColumns.mMisc = &mColumns.back(); + std::map creaMiscMap; + creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaMiscMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_SoulPoints, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CombatState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MagicState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_StealthState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound)); const RefIdColumn *openSound = &mColumns.back(); From 45aee1b5088cb110e06540356670b806887f7372 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:15:32 +1000 Subject: [PATCH 1048/1812] Remove AI flag from the UI and instead auto-detect whether to save AIDT records. Should resolve bug #2879. --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 8 +------- apps/opencs/model/world/refidcollection.cpp | 2 -- components/esm/loadcrea.cpp | 7 ++++++- components/esm/loadnpc.cpp | 7 ++++++- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 44ec9d384f..2e0a697a57 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -71,7 +71,6 @@ namespace CSMWorld { ColumnId_Weight, "Weight" }, { ColumnId_EnchantmentPoints, "Enchantment Points" }, { ColumnId_Quality, "Quality" }, - { ColumnId_Ai, "AI" }, { ColumnId_AiHello, "AI Hello" }, { ColumnId_AiFlee, "AI Flee" }, { ColumnId_AiFight, "AI Fight" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 981599e531..fb25004ecd 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -65,7 +65,7 @@ namespace CSMWorld ColumnId_Weight = 50, ColumnId_EnchantmentPoints = 51, ColumnId_Quality = 52, - ColumnId_Ai = 53, + // unused ColumnId_AiHello = 54, ColumnId_AiFlee = 55, ColumnId_AiFight = 56, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 41f2543558..ae446599ef 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -479,7 +479,6 @@ namespace CSMWorld struct ActorColumns : public NameColumns { - const RefIdColumn *mHasAi; const RefIdColumn *mHello; const RefIdColumn *mFlee; const RefIdColumn *mFight; @@ -524,9 +523,6 @@ namespace CSMWorld const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); - if (column==mActors.mHasAi) - return record.get().mHasAI!=0; - if (column==mActors.mHello) return record.get().mAiData.mHello; @@ -568,9 +564,7 @@ namespace CSMWorld data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); RecordT record2 = record.get(); - if (column==mActors.mHasAi) - record2.mHasAI = value.toInt(); - else if (column==mActors.mHello) + if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) record2.mAiData.mFlee = value.toInt(); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f8c9e28fe4..d7b7cedfab 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -113,8 +113,6 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Ai, ColumnBase::Display_Boolean)); - actorsColumns.mHasAi = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_Integer)); actorsColumns.mHello = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_Integer)); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 50c47349ca..8c4f49e452 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -96,7 +96,12 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } mTransport.save(esm); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 44d2987853..67a437176c 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -121,7 +121,12 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } From 192f01e3ac5db4f0d1d9d78c2a419b274f307bb1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:17:14 +1000 Subject: [PATCH 1049/1812] Set default creature scale to 1. Partially resolves bug #2880. (no creature verifier yet) --- components/esm/loadcrea.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 8c4f49e452..fb235e6b3d 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -120,7 +120,7 @@ namespace ESM { for (int i=0; i<6; ++i) mData.mAttack[i] = 0; mData.mGold = 0; mFlags = 0; - mScale = 0; + mScale = 1.f; mModel.clear(); mName.clear(); mScript.clear(); From 1365b8edd1f0a20e97ccb9a30cd74a6dc97c44bd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 11:18:07 +1000 Subject: [PATCH 1050/1812] Fix typo. --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ae446599ef..53da63806e 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -693,7 +693,7 @@ namespace CSMWorld const RefIdColumn *mScale; const RefIdColumn *mOriginal; const RefIdColumn *mAttributes; - const RefIdColumn *mAttack; + const RefIdColumn *mAttacks; const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); From 8e2fe1985d8a794aaf70173c71e7c63cd4ac3f1a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 12 Sep 2015 14:17:46 +1200 Subject: [PATCH 1051/1812] Fixed errors pointed out by Zini. 1. Removed "Actor" from name of function isActorNearInactiveCell(). 2. Corrected case of CoordinateConverter member function names. --- apps/openmw/mwmechanics/aipackage.cpp | 6 +++--- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/coordinateconverter.cpp | 8 ++++---- apps/openmw/mwmechanics/coordinateconverter.hpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwrender/pathgrid.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c4091c63ef..1af0f1c5a3 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -36,7 +36,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 //... units from player, and exterior cells are 8192 units long and wide. //... But AI processing distance may increase in the future. - if (isActorNearInactiveCell(pos)) + if (isNearInactiveCell(pos)) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; return false; @@ -114,14 +114,14 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } -bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos) { const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell osg::Vec3f actorOffset(actorPos.asVec3()); - CoordinateConverter(playerCell).ToLocal(actorOffset); + CoordinateConverter(playerCell).toLocal(actorOffset); // currently assumes 3 x 3 grid for exterior cells, with player at center cell. // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index befd159bf0..e16d66dbe6 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,7 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); - bool isActorNearInactiveCell(const ESM::Position& actorPos); + bool isNearInactiveCell(const ESM::Position& actorPos); }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b789c44286..a3fdc69ccc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -588,7 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - CoordinateConverter(cell).ToWorld(point); + CoordinateConverter(cell).toWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -746,7 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - CoordinateConverter(cell).ToLocal(npcPos); + CoordinateConverter(cell).toLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp index 583ac41c52..0a2d99f924 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.cpp +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -15,25 +15,25 @@ namespace MWMechanics } } - void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point) { point.mX += mCellX; point.mY += mCellY; } - void CoordinateConverter::ToWorld(osg::Vec3f& point) + void CoordinateConverter::toWorld(osg::Vec3f& point) { point.x() += static_cast(mCellX); point.y() += static_cast(mCellY); } - void CoordinateConverter::ToLocal(osg::Vec3f& point) + void CoordinateConverter::toLocal(osg::Vec3f& point) { point.x() -= static_cast(mCellX); point.y() -= static_cast(mCellY); } - osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + osg::Vec3f CoordinateConverter::toLocalVec3(const ESM::Pathgrid::Point& point) { return osg::Vec3f( static_cast(point.mX - mCellX), diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp index 2c4d3d3ba8..cd855e84a2 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.hpp +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -18,15 +18,15 @@ namespace MWMechanics CoordinateConverter(const ESM::Cell* cell); /// in-place conversion from local to world - void ToWorld(ESM::Pathgrid::Point& point); + void toWorld(ESM::Pathgrid::Point& point); /// in-place conversion from local to world - void ToWorld(osg::Vec3f& point); + void toWorld(osg::Vec3f& point); /// in-place conversion from world to local - void ToLocal(osg::Vec3f& point); + void toLocal(osg::Vec3f& point); - osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + osg::Vec3f toLocalVec3(const ESM::Pathgrid::Point& point); private: int mCellX; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index daab321367..f26d3e109a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -207,10 +207,10 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); + osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); + osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -223,7 +223,7 @@ namespace MWMechanics if(startNode == endNode.first) { ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); - converter.ToWorld(temp); + converter.toWorld(temp); mPath.push_back(temp); } else @@ -233,7 +233,7 @@ namespace MWMechanics // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) { - converter.ToWorld(*iter); + converter.toWorld(*iter); } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index bd22446dea..ae8bda1fb7 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -208,7 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); + MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 0feae19140f6c869fc025772432183a00059e570 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 14 Sep 2015 19:57:22 +1200 Subject: [PATCH 1052/1812] AiCombat use evadeObstacles() from AiPackage. --- apps/openmw/mwmechanics/aicombat.cpp | 7 +++---- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5ea3ba6a3b..58f74a87f0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -200,7 +200,7 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - updateActorsMovement(actor, storage.mMovement); + updateActorsMovement(actor, duration, storage.mMovement); storage.updateAttack(characterController); storage.mActionCooldown -= duration; @@ -494,7 +494,7 @@ namespace MWMechanics return false; } - void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -506,8 +506,7 @@ namespace MWMechanics } else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actorMovementSettings.mPosition[1] = 1; + evadeObstacles(actor, duration, pos); } } else diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 73d0254f3b..93d6305291 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,7 +65,7 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& movement); void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1af0f1c5a3..1cd9649f76 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -77,7 +77,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return false; } -void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos) { zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index e16d66dbe6..3f227a49a2 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -78,6 +78,8 @@ namespace MWMechanics virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; @@ -87,7 +89,6 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; private: - void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); bool isNearInactiveCell(const ESM::Position& actorPos); }; From 6c6fc662ef80b5c99fc2b3723faa410edb37868c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 15:14:18 +0200 Subject: [PATCH 1053/1812] Add CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..879113a515 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +Description +=========== + +Your pull request description should include: + +* Summary of the changes made +* Reasoning / motivation behind the change +* What testing you have carried out to verify the change +* If applicable, a link back to the bug report or forum discussion that prompted the change + +Other notes +=========== + +* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time. +* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. +* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). From 5fde9149594f6503c192f9d949d8f0bb3f3df5ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 17:17:38 +0200 Subject: [PATCH 1054/1812] CONTRIBUTING.md: clarify "if applicable" --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 879113a515..a9cd6a6903 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,12 @@ Description =========== -Your pull request description should include: +Your pull request description should include (if applicable): +* A link back to the bug report or forum discussion that prompted the change * Summary of the changes made * Reasoning / motivation behind the change * What testing you have carried out to verify the change -* If applicable, a link back to the bug report or forum discussion that prompted the change Other notes =========== From 2a981a5272e4d9bc513c3555c9dbcb0de2a31879 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 13:58:07 +0200 Subject: [PATCH 1055/1812] make sure local variables are loaded when trying to access them from outside of a script (Fixes #2659) --- apps/openmw/mwscript/globalscripts.cpp | 11 +++---- apps/openmw/mwscript/locals.cpp | 39 +++++++++++++++++++++-- apps/openmw/mwscript/locals.hpp | 26 +++++++++++++-- apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 23 ++++--------- apps/openmw/mwworld/refdata.hpp | 6 ++-- 6 files changed, 75 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index f339fa5200..6074a12d0e 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -198,13 +198,12 @@ namespace MWScript if (iter==mScripts.end()) { - if (const ESM::Script *script = mStore.get().find (name)) - { - GlobalScriptDesc desc; - desc.mLocals.configure (*script); + const ESM::Script *script = mStore.get().find (name); - iter = mScripts.insert (std::make_pair (name, desc)).first; - } + GlobalScriptDesc desc; + desc.mLocals.configure (*script); + + iter = mScripts.insert (std::make_pair (name2, desc)).first; } return iter->second.mLocals; diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a18d0d5ae5..ee93ea2e7b 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -9,13 +9,32 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/esmstore.hpp" #include namespace MWScript { - void Locals::configure (const ESM::Script& script) + void Locals::ensure (const std::string& scriptName) { + if (!mInitialised) + { + const ESM::Script *script = MWBase::Environment::get().getWorld()->getStore(). + get().find (scriptName); + + configure (*script); + } + } + + Locals::Locals() : mInitialised (false) {} + + bool Locals::configure (const ESM::Script& script) + { + if (mInitialised) + return false; + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals (script.mId); @@ -25,6 +44,9 @@ namespace MWScript mLongs.resize (locals.get ('l').size(), 0); mFloats.clear(); mFloats.resize (locals.get ('f').size(), 0); + + mInitialised = true; + return true; } bool Locals::isEmpty() const @@ -36,6 +58,8 @@ namespace MWScript { try { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); @@ -49,6 +73,8 @@ namespace MWScript int Locals::getIntVar(const std::string &script, const std::string &var) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -73,6 +99,8 @@ namespace MWScript bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -94,8 +122,11 @@ namespace MWScript return false; } - void Locals::write (ESM::Locals& locals, const std::string& script) const + bool Locals::write (ESM::Locals& locals, const std::string& script) const { + if (!mInitialised) + return false; + try { const Compiler::Locals& declarations = @@ -132,10 +163,14 @@ namespace MWScript catch (const Compiler::SourceException&) { } + + return true; } void Locals::read (const ESM::Locals& locals, const std::string& script) { + ensure (script); + try { const Compiler::Locals& declarations = diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index a9fcf317c8..bb4df42bf5 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -15,30 +15,50 @@ namespace MWScript { class Locals { + bool mInitialised; + + void ensure (const std::string& scriptName); + public: std::vector mShorts; std::vector mLongs; std::vector mFloats; + Locals(); + /// Are there any locals? + /// + /// \note Will return false, if locals have not been configured yet. bool isEmpty() const; - void configure (const ESM::Script& script); + /// \return Did the state of *this change from uninitialised to initialised? + bool configure (const ESM::Script& script); /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary bool setVarByInt(const std::string& script, const std::string& var, int val); + /// \note Locals will be automatically configured first, if necessary + // + // \note If it can not be determined if the variable exists, the error will be + // ignored and false will be returned. bool hasVar(const std::string& script, const std::string& var); /// if var does not exist, returns 0 /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary int getIntVar (const std::string& script, const std::string& var); - void write (ESM::Locals& locals, const std::string& script) const; + /// \note If locals have not been configured yet, no data is written. + /// + /// \return Locals written? + bool write (ESM::Locals& locals, const std::string& script) const; + /// \note Locals will be automatically configured first, if necessary void read (const ESM::Locals& locals, const std::string& script); }; } #endif - diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 084beb8121..b73c9a642c 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -170,7 +170,7 @@ namespace MWScript return iter->second; } - if (const ESM::Script *script = mStore.get().find (name2)) + if (const ESM::Script *script = mStore.get().search (name2)) { if (mVerbose) std::cout diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 2062e78d90..88a6fa3533 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -14,7 +14,6 @@ namespace MWWorld { mBaseNode = refData.mBaseNode; mLocals = refData.mLocals; - mHasLocals = refData.mHasLocals; mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; @@ -34,7 +33,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -45,7 +44,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged @@ -56,13 +55,13 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode(0), mDeleted(false), mHasLocals (false), + : mBaseNode(0), mDeleted(false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true) // Loading from a savegame -> assume changed - { + { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } @@ -83,10 +82,7 @@ namespace MWWorld void RefData::write (ESM::ObjectState& objectState, const std::string& scriptId) const { - objectState.mHasLocals = mHasLocals; - - if (mHasLocals) - mLocals.write (objectState.mLocals, scriptId); + objectState.mHasLocals = mLocals.write (objectState.mLocals, scriptId); objectState.mEnabled = mEnabled; objectState.mCount = mCount; @@ -139,13 +135,8 @@ namespace MWWorld void RefData::setLocals (const ESM::Script& script) { - if (!mHasLocals) - { - mLocals.configure (script); - mHasLocals = true; - if (!mLocals.isEmpty()) - mChanged = true; - } + if (mLocals.configure (script) && !mLocals.isEmpty()) + mChanged = true; } void RefData::setCount (int count) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 61055aa736..4075f62ce3 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -31,11 +31,9 @@ namespace MWWorld { osg::PositionAttitudeTransform* mBaseNode; - MWScript::Locals mLocals; // if we find the overhead of heaving a locals - // object in the refdata of refs without a script, - // we can make this a pointer later. + MWScript::Locals mLocals; + bool mDeleted; // separate delete flag used for deletion by a content file - bool mHasLocals; bool mEnabled; int mCount; // 0: deleted From 4d94f38f4b7255fd1abbcdc8d2bd388e604bec04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 14:57:07 +0200 Subject: [PATCH 1056/1812] replaced context-sensitive implementation of allowing digits at the beginning of names with a more general implementation (Fixes #1730) --- components/compiler/fileparser.cpp | 2 -- components/compiler/scanner.cpp | 38 +++++++++++++++++------------- components/compiler/scanner.hpp | 3 --- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index c8a512340f..8711d92fec 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -63,7 +63,6 @@ namespace Compiler if (mState==BeginState && keyword==Scanner::K_begin) { mState = NameState; - scanner.allowNameStartingwithDigit(); return true; } @@ -110,7 +109,6 @@ namespace Compiler scanner.scan (mScriptParser); mState = EndNameState; - scanner.allowNameStartingwithDigit(); return true; } diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 5af396d275..f25e69e399 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -47,9 +47,6 @@ namespace Compiler bool Scanner::scanToken (Parser& parser) { - bool allowDigit = mNameStartingWithDigit; - mNameStartingWithDigit = false; - switch (mPutback) { case Putback_Special: @@ -114,7 +111,6 @@ namespace Compiler else if (isWhitespace (c)) { mLoc.mLiteral.clear(); - mNameStartingWithDigit = allowDigit; return true; } else if (c==':') @@ -123,7 +119,7 @@ namespace Compiler mLoc.mLiteral.clear(); return true; } - else if (std::isalpha (c) || c=='_' || c=='"' || (allowDigit && std::isdigit (c))) + else if (std::isalpha (c) || c=='_' || c=='"') { bool cont = false; @@ -179,10 +175,18 @@ namespace Compiler { value += c; } - else if (std::isalpha (c) || c=='_') - error = true; - else if (c=='.' && !error) + else if (isStringCharacter (c)) { + error = true; + value += c; + } + else if (c=='.') + { + if (error) + { + putback (c); + break; + } return scanFloat (value, parser, cont); } else @@ -193,7 +197,15 @@ namespace Compiler } if (error) - return false; + { + /// workaround that allows names to begin with digits + /// \todo disable + TokenLoc loc (mLoc); + mLoc.mLiteral.clear(); + cont = parser.parseName (value, loc, *this); + return true; +// return false; + } TokenLoc loc (mLoc); mLoc.mLiteral.clear(); @@ -555,8 +567,7 @@ namespace Compiler Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream, const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), - mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), - mNameStartingWithDigit (false) + mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0) { } @@ -608,9 +619,4 @@ namespace Compiler if (mExtensions) mExtensions->listKeywords (keywords); } - - void Scanner::allowNameStartingwithDigit() - { - mNameStartingWithDigit = true; - } } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index ed01bbe44e..8478959785 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -124,9 +124,6 @@ namespace Compiler void listKeywords (std::vector& keywords); ///< Append all known keywords to \a kaywords. - - /// For the next token allow names to start with a digit. - void allowNameStartingwithDigit(); }; } From 84747fbdd764eb00dde424b4ac6e9201b8beb3f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:37:36 +0200 Subject: [PATCH 1057/1812] Use the actual sneak state to determine visibility of indicator (Fixes #2915) --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/character.hpp | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fcda6fa088..1c26c7dd11 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1094,7 +1094,7 @@ namespace MWMechanics static float sneakTimer = 0.f; // times update of sneak icon // if player is in sneak state see if anyone detects him - if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) + if (playerCharacter && playerCharacter->isSneaking()) { static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75e..4a826043b3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1768,7 +1768,7 @@ void CharacterController::update(float duration) if(mAnimQueue.empty() || inwater || sneak) { - idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); + idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle)); } else if(mAnimQueue.size() > 1) { @@ -2048,6 +2048,15 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +bool CharacterController::isSneaking() const +{ + return mIdleState == CharState_IdleSneak || + mMovementState == CharState_SneakForward || + mMovementState == CharState_SneakBack || + mMovementState == CharState_SneakLeft || + mMovementState == CharState_SneakRight; +} + void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 98c1817491..4448467f76 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,7 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + bool isSneaking() const; void setAttackingOrSpell(bool attackingOrSpell); From 5692ef1eae83cf80b21a643782ecfe80eab087b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:43:42 +0200 Subject: [PATCH 1058/1812] Add convenience operator [] to AnimPriority --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4a826043b3..0d7c0ff260 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -278,7 +278,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mHitState = CharState_Block; mCurrentHit = "shield"; MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); - priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } @@ -1063,7 +1063,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; + priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c1ae5fed5d..b14e629d07 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[blendMask] < state->second.mPriority[blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 30b6d156ad..ef572c7c30 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,6 +105,16 @@ public: return true; } + int& operator[] (int n) + { + return mPriority[n]; + } + + const int& operator[] (int n) const + { + return mPriority[n]; + } + bool contains(int priority) const { for (unsigned int i=0; i Date: Wed, 16 Sep 2015 16:14:17 +0200 Subject: [PATCH 1059/1812] Keep playing IdleSneak on the lower body when casting spells / using weapons --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0d7c0ff260..49e40349b1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -483,7 +483,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat idlePriority = Priority_SwimIdle; } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) + { idle = "idlesneak"; + idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody; + } else if(mIdleState != CharState_None) { idle = "idle"; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4448467f76..fee7b959cb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SneakIdleLowerBody, Priority_SwimIdle, Priority_Jump, Priority_Movement, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b14e629d07..078d136f15 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority[blendMask] < state->second.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[(BoneGroup)blendMask] < state->second.mPriority[(BoneGroup)blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ef572c7c30..e64879a756 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,12 +105,12 @@ public: return true; } - int& operator[] (int n) + int& operator[] (BoneGroup n) { return mPriority[n]; } - const int& operator[] (int n) const + const int& operator[] (BoneGroup n) const { return mPriority[n]; } From f8d4bc378ff1ef08de7547877deb8b3a6f0b3d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 16:15:55 +0200 Subject: [PATCH 1060/1812] Move setAlpha from NpcAnimation to Animation (Fixes #2917) --- apps/openmw/mwrender/animation.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++- apps/openmw/mwrender/npcanimation.cpp | 36 --------------------------- apps/openmw/mwrender/npcanimation.hpp | 4 --- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 078d136f15..24d540e20e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -292,6 +294,7 @@ namespace MWRender , mTextKeyListener(NULL) , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) + , mAlpha(1.f) { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -1247,6 +1250,37 @@ namespace MWRender return found->second; } + void Animation::setAlpha(float alpha) + { + if (alpha == mAlpha) + return; + mAlpha = alpha; + + if (alpha != 1.f) + { + osg::StateSet* stateset (new osg::StateSet); + + osg::BlendFunc* blendfunc (new osg::BlendFunc); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // FIXME: overriding diffuse/ambient/emissive colors + osg::Material* material (new osg::Material); + material->setColorMode(osg::Material::OFF); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + stateset->setNestRenderBins(false); + mObjectRoot->setStateSet(stateset); + } + else + { + mObjectRoot->setStateSet(NULL); + } + } + void Animation::setLightEffect(float effect) { if (effect == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e64879a756..94b792c0da 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -253,6 +253,8 @@ protected: osg::ref_ptr mGlowLight; + float mAlpha; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -419,7 +421,8 @@ public: virtual void showCarriedLeft(bool show) {} virtual void setWeaponGroup(const std::string& group) {} virtual void setVampire(bool vampire) {} - virtual void setAlpha(float alpha) {} + /// A value < 1 makes the animation translucent, 1.f = fully opaque + void setAlpha(float alpha); virtual void setPitchFactor(float factor) {} virtual void attachArrow() {} virtual void releaseArrow(float attackStrength) {} diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 66a3d3ec61..99ee886e16 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include @@ -278,7 +276,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mAlpha(1.f), mSoundsDisabled(disableSounds) { mNpc = mPtr.get()->mBase; @@ -422,7 +419,6 @@ void NpcAnimation::updateParts() if (!mObjectRoot.get()) return; - mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); NpcType curType = Type_Normal; @@ -902,7 +898,6 @@ void NpcAnimation::showWeapons(bool showWeapon) { removeIndividualPart(ESM::PRT_Weapon); } - mAlpha = 1.f; } void NpcAnimation::showCarriedLeft(bool show) @@ -988,37 +983,6 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo } } -void NpcAnimation::setAlpha(float alpha) -{ - if (alpha == mAlpha) - return; - mAlpha = alpha; - - if (alpha != 1.f) - { - osg::StateSet* stateset (new osg::StateSet); - - osg::BlendFunc* blendfunc (new osg::BlendFunc); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - // FIXME: overriding diffuse/ambient/emissive colors - osg::Material* material (new osg::Material); - material->setColorMode(osg::Material::OFF); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); - stateset->setNestRenderBins(false); - mObjectRoot->setStateSet(stateset); - } - else - { - mObjectRoot->setStateSet(NULL); - } -} - void NpcAnimation::enableHeadAnimation(bool enable) { mHeadAnimationTime->setEnabled(enable); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 6462c53c3f..06f40f8475 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -65,7 +65,6 @@ private: boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; - float mAlpha; bool mSoundsDisabled; void updateNpcBase(); @@ -134,9 +133,6 @@ public: /// Get the inventory slot that the given node path leads into, or -1 if not found. int getSlot(const osg::NodePath& path) const; - /// Make the NPC only partially visible - virtual void setAlpha(float alpha); - virtual void setVampire(bool vampire); /// Set a translation offset (in object root space) to apply to meshes when in first person mode. From 47e29480ce9c46f5787885183537ef7774742656 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 16:04:25 +0200 Subject: [PATCH 1061/1812] show duration of light sources in tooltip I had forgotten light sources disappear after a while, this way at least you know it's normal ! --- apps/openmw/mwclass/light.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c532b5d65d..cbd051fdb3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,6 +169,7 @@ namespace MWClass std::string text; + text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); From 1472711583358f633d17cc055a24edfb970e85eb Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 17:32:00 +0200 Subject: [PATCH 1062/1812] add duration to spell icons too and use gmststrings instead of direct strings in tooltips durations can display minutes and hours I don't know any effect lasting an hour or more but you never know... --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index cbd051fdb3..98d86e5aef 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,7 +169,7 @@ namespace MWClass std::string text; - text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index b2995af3c7..f132cd73ef 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,6 +133,23 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } } From b0d373f7e6ffec07b8f356dfeb2ec3805f31574c Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 19:18:01 +0200 Subject: [PATCH 1063/1812] durations in tooltips : water walking effects is seen differently so move the duration info out of this block... --- apps/openmw/mwgui/spellicons.cpp | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index f132cd73ef..632baeb19c 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,24 +133,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) From a47617c21f11c33e10b8a635292c3b1a4d8d5769 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:45:37 +0200 Subject: [PATCH 1064/1812] Fix tab indentations in apps/ and components/ --- apps/esmtool/record.cpp | 30 +++++++++---------- apps/esmtool/record.hpp | 2 +- .../model/world/infotableproxymodel.cpp | 2 +- apps/opencs/view/widget/droplineedit.cpp | 2 +- apps/openmw/android_commandLine.cpp | 26 ++++++++-------- apps/openmw/android_main.c | 20 ++++++------- apps/openmw/crashcatcher.cpp | 4 +-- apps/openmw/mwgui/debugwindow.cpp | 8 ++--- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 4 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 14 ++++----- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/compiler/extensions0.hpp | 2 +- components/esm/loadmgef.hpp | 4 +-- components/files/configurationmanager.hpp | 10 +++---- components/sdlutil/sdlinputwrapper.hpp | 4 +-- 18 files changed, 70 insertions(+), 70 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 76c14e728d..5fe6471b0f 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -493,14 +493,14 @@ void Record::print() std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; if (mPrintPlain) { - std::cout << " Text:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Text:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Text: [skipped]" << std::endl; + std::cout << " Text: [skipped]" << std::endl; } } @@ -799,14 +799,14 @@ void Record::print() { if (mPrintPlain) { - std::cout << " Result Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mResultScript << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Result Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mResultScript << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Result Script: [skipped]" << std::endl; + std::cout << " Result Script: [skipped]" << std::endl; } } } @@ -1201,14 +1201,14 @@ void Record::print() if (mPrintPlain) { - std::cout << " Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mScriptText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mScriptText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Script: [skipped]" << std::endl; + std::cout << " Script: [skipped]" << std::endl; } } diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c1b90ac2bc..5e03c64dba 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -53,7 +53,7 @@ namespace EsmTool } void setPrintPlain(bool plain) { - mPrintPlain = plain; + mPrintPlain = plain; } virtual void load(ESM::ESMReader &esm) = 0; diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index f55f775ab3..4f0b2e7528 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -16,7 +16,7 @@ namespace CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : + mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : Columns::ColumnId_Journal), mInfoColumnIndex(-1), mLastAddedSourceRow(-1) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 1df598cb8d..2ca3064613 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); - setText(QString::fromUtf8(id.getId().c_str())); + setText(QString::fromUtf8(id.getId().c_str())); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index ebfff28ca2..7e7f368e05 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -7,21 +7,21 @@ int argcData; extern "C" void releaseArgv(); void releaseArgv() { - delete[] argvData; + delete[] argvData; } JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, - jobject obj, jint argc, jobjectArray stringArray) { - jboolean iscopy; - argcData = (int) argc; - argvData = new const char *[argcData + 1]; - argvData[0] = "openmw"; - for (int i = 1; i < argcData + 1; i++) { - jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, - i - 1); - argvData[i] = (env)->GetStringUTFChars(string, &iscopy); - (env)->DeleteLocalRef(string); - } - (env)->DeleteLocalRef(stringArray); + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData = new const char *[argcData + 1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); + } + (env)->DeleteLocalRef(stringArray); } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 1b28395199..47b77a8b38 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -16,22 +16,22 @@ extern const char **argvData; void releaseArgv(); int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, - jobject obj) { + jobject obj) { - SDL_Android_Init(env, cls); + SDL_Android_Init(env, cls); - SDL_SetMainReady(); + SDL_SetMainReady(); - /* Run the application code! */ + /* Run the application code! */ - int status; + int status; - status = main(argcData+1, argvData); - releaseArgv(); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + status = main(argcData+1, argvData); + releaseArgv(); + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ - return status; + return status; } #endif /* __ANDROID__ */ diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 8f25d041cb..373d78746c 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -37,8 +37,8 @@ static const char pipe_err[] = "!!! Failed to create pipe\n"; static const char fork_err[] = "!!! Failed to fork debug process\n"; static const char exec_err[] = "!!! Failed to exec debug process\n"; -#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ -# define PATH_MAX 256 +#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ +# define PATH_MAX 256 #endif static char argv0[PATH_MAX]; diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index a6dab66c10..37ea3470d4 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -18,9 +18,9 @@ namespace float accumulated_time=0,parent_time = pit->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : pit->Get_Current_Parent_Total_Time(); int i,j; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); - for (i=0;iGet_Current_Parent_Name())+" (total running time: "+MyGUI::utility::toString(parent_time,3)+" ms) ---\n"; os << s; @@ -35,7 +35,7 @@ namespace accumulated_time += current_total_time; float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; - for (j=0;jGet_Current_Name()+" ("+MyGUI::utility::toString(fraction,2)+" %) :: "+MyGUI::utility::toString(ms,3)+" ms / frame ("+MyGUI::utility::toString(pit->Get_Current_Total_Calls())+" calls)\n"; os << s; @@ -47,7 +47,7 @@ namespace { os << "what's wrong\n"; } - for (i=0;i SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f; s = "Unaccounted: ("+MyGUI::utility::toString(unaccounted,3)+" %) :: "+MyGUI::utility::toString(parent_time - accumulated_time,3)+" ms\n"; os << s; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 384bccfea5..983b50fe2f 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -109,7 +109,7 @@ namespace MWGui static std::string sSchoolNames[6]; - int mHorizontalScrollIndex; + int mHorizontalScrollIndex; float mDelay; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 481ffaadec..695337cde4 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -605,7 +605,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) @@ -621,7 +621,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index bd94d60c64..ad5fe35bd9 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -102,9 +102,9 @@ namespace MWInput mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - /* Joystick Init */ + /* Joystick Init */ - //Load controller mappings + // Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) if(controllerBindingsFile!="") { @@ -112,10 +112,10 @@ namespace MWInput } #endif - //Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { + // Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { if(SDL_IsGameController(i)) { SDL_ControllerDeviceEvent evt; @@ -126,7 +126,7 @@ namespace MWInput { //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); } - } + } float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); if (uiScale != 0.f) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f0..45a6cce6d7 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -57,7 +57,7 @@ namespace osg::Vec3f dir = to - from; dir.z() = 0; dir.normalize(); - float verticalOffset = 200; // instead of '200' here we want the height of the actor + float verticalOffset = 200; // instead of '200' here we want the height of the actor osg::Vec3f _from = from + dir*offsetXY + osg::Vec3f(0,0,1) * verticalOffset; // cast up-down ray and find height in world space of hit diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c4fec7256c..e666161da9 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -747,7 +747,7 @@ namespace MWPhysics { } - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == mMe) return 1.f; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24f..f812fd8fd3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -287,7 +287,7 @@ namespace MWWorld if (mPlayer) { - mPlayer->clear(); + mPlayer->clear(); mPlayer->setCell(0); mPlayer->getPlayer().getRefData() = RefData(); mPlayer->set(mStore.get().find ("player")); diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index 83f3a44fa6..e9ce6a6d6a 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -44,7 +44,7 @@ namespace Compiler namespace Gui { - void registerExtensions (Extensions& extensions); + void registerExtensions (Extensions& extensions); } namespace Misc diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 32b8a85a6d..eeb4268c2c 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -31,9 +31,9 @@ struct MagicEffect CastTouch = 0x80, // Allows range - cast on touch. CastTarget = 0x100, // Allows range - cast on target. UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second. - NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. + NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally. - CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. + CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. // Originally modifiable flags AllowSpellmaking = 0x200, // Can be used for spellmaking diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 5f0062c2e9..102f7c3cb7 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -52,11 +52,11 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; - #if defined HAVE_UNORDERED_MAP - typedef std::unordered_map TokensMappingContainer; - #else - typedef std::tr1::unordered_map TokensMappingContainer; - #endif + #if defined HAVE_UNORDERED_MAP + typedef std::unordered_map TokensMappingContainer; + #else + typedef std::tr1::unordered_map TokensMappingContainer; + #endif void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, diff --git a/components/sdlutil/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp index bdb5842ae8..a821b9012c 100644 --- a/components/sdlutil/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -30,8 +30,8 @@ namespace SDLUtil void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); - bool isModifierHeld(SDL_Keymod mod); - bool isKeyDown(SDL_Scancode key); + bool isModifierHeld(SDL_Keymod mod); + bool isKeyDown(SDL_Scancode key); void setMouseVisible (bool visible); void setMouseRelative(bool relative); From 29a84452ab71886d1e97d6110844ad88e2cb48f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 22:41:42 +0200 Subject: [PATCH 1065/1812] durations in tooltips : use "show effect duration" setting --- apps/openmw/mwclass/light.cpp | 4 +++- apps/openmw/mwgui/spellicons.cpp | 36 +++++++++++++++++--------------- files/settings-default.cfg | 2 ++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 98d86e5aef..f1dd18acca 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -169,7 +170,8 @@ namespace MWClass std::string text; - text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + if (Settings::Manager::getBool("show effect duration","Game")) + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 632baeb19c..27896381ef 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -134,23 +135,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } + if (effectIt->mRemainingTime > -1 && + Settings::Manager::getBool("show effect duration","Game")) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c793225c22..274a31315c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -175,6 +175,8 @@ difficulty = 0 #2: tint crosshair #3: both show owned = 0 +# Show the remaining duration of magic effects and lights +show effect duration = false [Saves] character = From ab97a90c760fb3a558f25bd49527bf69fbba8d64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:50:57 +0200 Subject: [PATCH 1066/1812] Add travis-ci script to detect tab characters in the code --- .travis.yml | 2 +- CI/check_tabs.sh | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 CI/check_tabs.sh diff --git a/.travis.yml b/.travis.yml index 80277f8ba0..69879bd781 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi -after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh new file mode 100755 index 0000000000..91f81e2a1e --- /dev/null +++ b/CI/check_tabs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) + +if [[ $OUTPUT ]] ; then + echo "Error: Tab characters found!" + echo $OUTPUT + exit 1 +fi From c4b5a41ac396fc0e69df339513217ee0d5ba5ba9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 01:08:16 +0200 Subject: [PATCH 1067/1812] Improve combat AI vertical aiming (Fixes #1366, Fixes #1330) --- apps/openmw/mwbase/world.hpp | 4 +++ apps/openmw/mwmechanics/aicombat.cpp | 29 ++++++++-------- apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 44 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 4 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a3d293d953..1622e15376 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -541,6 +541,10 @@ namespace MWBase virtual void resetActors() = 0; virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0; + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f0..93b4e0ee79 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -34,10 +34,9 @@ namespace return std::atan2(dir.x(), dir.y()); } - float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) + float getXAngleToDir(const osg::Vec3f& dir) { - float len = (dirLen > 0.0f)? dirLen : dir.length(); - return -std::asin(dir.z() / len); + return -std::asin(dir.z() / dir.length()); } const float REACTION_INTERVAL = 0.25f; @@ -346,8 +345,9 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); osg::Vec3f vActorPos(pos.asVec3()); osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; - float distToTarget = vDirToTarget.length(); + + osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); + float distToTarget = (vTargetPos - vActorPos).length(); osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; @@ -388,7 +388,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); @@ -396,8 +396,8 @@ namespace MWMechanics } else { - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated } // (not quite attack dist while following) @@ -431,19 +431,19 @@ namespace MWMechanics if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability - preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vAimDir.x(), vAimDir.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } // don't use pathgrid when actor can move in 3 dimensions if (canMoveByZ) { preferShortcut = true; - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); } if(preferShortcut) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; mPathFinder.clearPath(); @@ -478,7 +478,7 @@ namespace MWMechanics // if there is no new path, then go straight on target if (!mPathFinder.isPathConstructed()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); } } @@ -779,9 +779,8 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same - osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3(); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vDirToTarget = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = vDirToTarget.length(); osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos; @@ -812,7 +811,7 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t t_collision = projDistDiff / (std::sqrt(projVelDirSquared) - velDir); else t_collision = 0; // speed of projectile is not enough to reach moving target - return vTargetPos + vTargetMoveDir * t_collision - vActorPos; + return vDirToTarget + vTargetMoveDir * t_collision; } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ee9378ea49..db8da2886f 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -107,6 +107,7 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24f..b3e1c6ecb6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1018,14 +1018,11 @@ namespace MWWorld return facedObject; } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + osg::Vec3f getActorHeadPosition(const MWWorld::Ptr& actor, MWRender::RenderingManager* rendering) { - const ESM::Position &posdata = ptr.getRefData().getPosition(); + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos (posdata.asVec3()); - - MWRender::Animation* anim = mRendering->getAnimation(ptr); + MWRender::Animation* anim = rendering->getAnimation(actor); if (anim != NULL) { const osg::Node* node = anim->getNode("Head"); @@ -1035,9 +1032,18 @@ namespace MWWorld { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - pos = mats[0].getTrans(); + origin = mats[0].getTrans(); } } + return origin; + } + + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + { + const ESM::Position &posdata = ptr.getRefData().getPosition(); + + osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos = getActorHeadPosition(ptr, mRendering); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); if(result.first.isEmpty()) @@ -2608,21 +2614,7 @@ namespace MWWorld MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - - MWRender::Animation* anim = mRendering->getAnimation(actor); - if (anim != NULL) - { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) - { - osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); - } - } + osg::Vec3f origin = getActorHeadPosition(actor, mRendering); osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); @@ -3262,4 +3254,12 @@ namespace MWWorld return true; return false; } + + osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) + { + osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); + targetPos.z() += mPhysics->getHalfExtents(target).z(); + return (targetPos - weaponPos); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 241dacc8aa..26153086a3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -630,6 +630,10 @@ namespace MWWorld virtual void resetActors(); virtual bool isWalkingOnWater (const MWWorld::Ptr& actor); + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); }; } From a7f898057ba345d1c06f1f9071f1e067ab02bda4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 04:30:55 +0200 Subject: [PATCH 1068/1812] Don't activate the initial death animation when skipAnim is set (Fixes #2513) --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75e..e80d6f4d04 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -701,8 +701,9 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mIdleState = CharState_Idle; else { - int deathindex = mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation(); - playDeath(1.0f, CharacterState(CharState_Death1 + deathindex)); + // Set the death state, but don't play it yet + // We will play it in the first frame, but only if no script set the skipAnim flag + mDeathState = static_cast(CharState_Death1 + mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation()); } } else @@ -1835,6 +1836,13 @@ void CharacterController::update(float duration) } else if(cls.getCreatureStats(mPtr).isDead()) { + // initial start of death animation for actors that started the game as dead + // not done in constructor since we need to give scripts a chance to set the mSkipAnim flag + if (!mSkipAnim && mDeathState != CharState_None && mCurrentDeath.empty()) + { + playDeath(1.f, mDeathState); + } + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } From 56163dcb2a33fdf67bd78dc63a6134c4f408505a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 09:39:42 +0200 Subject: [PATCH 1069/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 16c8882393..8e9d35cf23 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -113,6 +113,7 @@ Programmers viadanna Vincent Heuken vocollapse + zelurker Manual ------ From b3b4fb3efbaf84a31b9a62203f9767b08328b671 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:27:55 +0200 Subject: [PATCH 1070/1812] removed some left-over signal slot stuff that shouldn't have been there in the first place --- apps/opencs/view/world/scenesubview.cpp | 7 ------- apps/opencs/view/world/scenesubview.hpp | 8 -------- 2 files changed, 15 deletions(-) diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 2ca2548c0c..b698d9034a 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -247,8 +247,6 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mToolbar = toolbar; connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus())); - connect (this, SIGNAL (updateSceneUserSetting(const QString &, const QStringList &)), - mScene, SLOT (updateUserSetting(const QString &, const QStringList &))); connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus())); mLayout->addWidget (mToolbar, 0); @@ -257,8 +255,3 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); } - -void CSVWorld::SceneSubView::updateUserSetting (const QString &key, const QStringList &list) -{ - emit updateSceneUserSetting(key, list); -} diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index fc45347d0b..65aaca999e 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -83,14 +83,6 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); - - public slots: - - void updateUserSetting (const QString &, const QStringList &); - - signals: - - void updateSceneUserSetting (const QString &, const QStringList &); }; } From 659b87b25faec71089ae5f8b96b4283d58abaab7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:31:25 +0200 Subject: [PATCH 1071/1812] more cleanup --- apps/opencs/view/doc/view.hpp | 3 --- apps/opencs/view/world/scenesubview.cpp | 5 ----- apps/opencs/view/world/scenesubview.hpp | 2 -- 3 files changed, 10 deletions(-) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index adda735265..2dd7174407 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -115,9 +115,6 @@ namespace CSVDoc Operations *getOperations() const; - /// Function called by view manager when user preferences are updated - void updateEditorSetting (const QString &, const QString &); - signals: void newGameRequest(); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b698d9034a..c2f3442f89 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -132,11 +132,6 @@ void CSVWorld::SceneSubView::setEditLock (bool locked) } -void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) -{ - -} - void CSVWorld::SceneSubView::setStatusBar (bool show) { mBottom->setStatusBar (show); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 65aaca999e..a34d719013 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -52,8 +52,6 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateEditorSetting (const QString& key, const QString& value); - virtual void setStatusBar (bool show); virtual void useHint (const std::string& hint); From 1aa926c7e0e151e2744ab90174d8b62caacb9dfe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 12:41:56 +0200 Subject: [PATCH 1072/1812] restored T-shortcut (focus toolbar) in scene widget --- apps/opencs/view/render/scenewidget.cpp | 4 ++++ apps/opencs/view/render/scenewidget.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d91c075e17..59cc718558 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -143,6 +143,10 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys mView->setLightingMode(osgViewer::View::NO_LIGHT); setLighting(&mLightingDay); + + /// \todo make shortcut configurable + QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); } SceneWidget::~SceneWidget() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index f5c36b6418..54f001c151 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -88,6 +88,10 @@ namespace CSVRender private slots: void selectLightingMode (const std::string& mode); + + signals: + + void focusToolbarRequest(); }; From 169fc6a61b2c2d2eed99c3e28156d53367e9312a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:22 +0200 Subject: [PATCH 1073/1812] OpenCS: Remove margin around the render window --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 59cc718558..0a5087998d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -52,6 +52,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(window->getGLWidget()); setLayout(layout); From dac3b33efba7872ab5ff1f458e3248632e4d2edf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:40 +0200 Subject: [PATCH 1074/1812] OpenCS: Pass events from the QGLWidget to the RenderWidget --- apps/opencs/view/render/scenewidget.cpp | 21 +++++++++++++++++++++ apps/opencs/view/render/scenewidget.hpp | 2 ++ 2 files changed, 23 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 0a5087998d..fb3bcb3c3d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -56,6 +56,9 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) layout->addWidget(window->getGLWidget()); setLayout(layout); + // Pass events through this widget first + window->getGLWidget()->installEventFilter(this); + mView->getCamera()->setGraphicsContext(window); mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); @@ -94,6 +97,24 @@ void RenderWidget::setVisibilityMask(int mask) mView->getCamera()->setCullMask(mask<<1); } +bool RenderWidget::eventFilter(QObject* obj, QEvent* event) +{ + // handle event in this widget, is there a better way to do this? + if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + if (event->type() == QEvent::MouseButtonRelease) + mouseReleaseEvent(static_cast(event)); + if (event->type() == QEvent::MouseMove) + mouseMoveEvent(static_cast(event)); + if (event->type() == QEvent::KeyPress) + keyPressEvent(static_cast(event)); + if (event->type() == QEvent::KeyRelease) + keyReleaseEvent(static_cast(event)); + + // Always pass the event on to GLWidget, i.e. to OSG event queue + return QObject::eventFilter(obj, event); +} + // -------------------------------------------------- CompositeViewer::CompositeViewer() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 54f001c151..63da01a45b 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -45,6 +45,8 @@ namespace CSVRender void setVisibilityMask(int mask); + bool eventFilter(QObject *, QEvent *); + protected: osg::ref_ptr mView; From 41ea76fd836eb956b9a7517c2181181c7c8ea115 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:05 +0200 Subject: [PATCH 1075/1812] OpenCS: Add selection outline effect to CSVRender::Object --- apps/opencs/view/render/object.cpp | 26 +++++++++++++++++++++++++- apps/opencs/view/render/object.hpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 973893a711..f05e311f9d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" @@ -116,9 +118,14 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; + mOutline = new osgFX::Scribe; + mOutline->addChild(mBaseNode); + + mBaseNode->setUserData(new ObjectHolder(this)); + parentNode->addChild(mBaseNode); // 0x1 reserved for separating cull and update visitors @@ -145,6 +152,23 @@ CSVRender::Object::~Object() mParentNode->removeChild(mBaseNode); } +void CSVRender::Object::setSelected(bool selected) +{ + mSelected = selected; + + mParentNode->removeChild(mOutline); + mParentNode->removeChild(mBaseNode); + if (selected) + mParentNode->addChild(mOutline); + else + mParentNode->addChild(mBaseNode); +} + +bool CSVRender::Object::getSelected() const +{ + return mSelected; +} + bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9f411ffc6d..9b37490699 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -6,6 +6,7 @@ #include #include +#include class QModelIndex; @@ -16,6 +17,11 @@ namespace osg class Group; } +namespace osgFX +{ + class Scribe; +} + namespace Resource { class ResourceSystem; @@ -29,12 +35,29 @@ namespace CSMWorld namespace CSVRender { + + class Object; + + // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query + class ObjectHolder : public osg::Referenced + { + public: + ObjectHolder(Object* obj) + : mObject(obj) + { + } + + Object* mObject; + }; + class Object { const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; osg::ref_ptr mBaseNode; + osg::ref_ptr mOutline; + bool mSelected; osg::Group* mParentNode; Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; @@ -68,6 +91,11 @@ namespace CSVRender ~Object(); + /// Mark the object as selected, selected objects show an outline effect + void setSelected(bool selected); + + bool getSelected() const; + /// \return Did this call result in a modification of the visual representation of /// this object? bool referenceableDataChanged (const QModelIndex& topLeft, From 18d0cae801e77f9c10dc4f26124b32e5372697e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:33 +0200 Subject: [PATCH 1076/1812] OpenCS: Select objects with the right mouse button --- apps/opencs/view/render/worldspacewidget.cpp | 48 ++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index d45fc45a80..a1f0f6bf2a 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,6 +1,7 @@ #include "worldspacewidget.hpp" #include +#include #include #include @@ -12,6 +13,8 @@ #include #include +#include + #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -19,6 +22,7 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" +#include "object.hpp" #include "elements.hpp" #include "editmode.hpp" @@ -370,11 +374,49 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + if (event->button() != Qt::RightButton) + return; + + // (0,0) is considered the lower left corner of an OpenGL window + int x = event->x(); + int y = height() - event->y(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(getInteractionMask() << 1); + + mView->getCamera()->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) { - //mMouse->mousePressEvent(event); + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + + // reject back-facing polygons + osg::Vec3f normal = intersection.getWorldIntersectNormal(); + normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); + if (normal.z() < 0) + continue; + + for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::Node* node = *it; + if (CSVRender::ObjectHolder* holder = dynamic_cast(node->getUserData())) + { + // hit an Object, toggle its selection state + CSVRender::Object* obj = holder->mObject; + obj->setSelected(!obj->getSelected()); + return; + } + } + + // must be terrain, report coordinates + std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; + return; } - //SceneWidget::mousePressEvent(event); } void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) From a37dee09e2f074a76ce1b2c38c1473b3a3e03334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 21:29:32 +0200 Subject: [PATCH 1077/1812] Fix invisibility effect disappearing after a view mode switch --- apps/openmw/mwrender/animation.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 24d540e20e..37ec4c2139 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -935,8 +935,10 @@ namespace MWRender void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { + osg::ref_ptr previousStateset; if (mObjectRoot) { + previousStateset = mObjectRoot->getStateSet(); mObjectRoot->getParent(0)->removeChild(mObjectRoot); } mObjectRoot = NULL; @@ -961,6 +963,9 @@ namespace MWRender mObjectRoot = newObjectRoot; } + if (previousStateset) + mObjectRoot->setStateSet(previousStateset); + if (baseonly) { RemoveDrawableVisitor removeDrawableVisitor; From 5369d206822def39fac0d6b7674fb8e1537cb82d Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 15:34:02 +1200 Subject: [PATCH 1078/1812] Moved pathfinding logic from AiCombat to Pathfinding. --- apps/openmw/mwmechanics/aicombat.cpp | 24 +++--------------------- apps/openmw/mwmechanics/pathfinding.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b42c3bdccc..6270779a49 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -458,28 +458,10 @@ namespace MWMechanics followTarget = false; - buildNewPath(actor, target); //may fail to build a path, check before use + buildNewPath(actor, target); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target - // This works on the borders between the path grid and areas with no waypoints. - if(inLOS && mPathFinder.getPath().size() > 1) - { - // get point just before target - std::list::const_iterator pntIter = --mPathFinder.getPath().end(); - --pntIter; - osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - - if(distToTarget <= (vTargetPos - vBeforeTarget).length()) - { - mPathFinder.clearPath(); - } - } - - // if there is no new path, then go straight on target - if (!mPathFinder.isPathConstructed()) - { - movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); - } + // should always return a path (even if it's just go straight on target.) + assert(mPathFinder.isPathConstructed()); } if (readyToAttack) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f26d3e109a..dbe20fdc05 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -215,6 +215,17 @@ namespace MWMechanics endPointInLocalCoords, startNode); + // if it's shorter for actor to travel from start to end, than to travel from either + // start or end to nearest pathgrid point, just travel from start to end. + float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2(); + float endTolastNodeLength2 = distanceSquared(mPathgrid->mPoints[endNode.first], endPointInLocalCoords); + float startTo1stNodeLength2 = distanceSquared(mPathgrid->mPoints[startNode], startPointInLocalCoords); + if ((startToEndLength2 < startTo1stNodeLength2) || (startToEndLength2 < endTolastNodeLength2)) + { + mPath.push_back(endPoint); + return; + } + // AiWander has logic that depends on whether a path was created, // deleting allowed nodes if not. Hence a path needs to be created // even if the start and the end points are the same. From 60d0ad928386e4d77aa08add8e763fcc4c9ab170 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 16:14:00 +1200 Subject: [PATCH 1079/1812] When stuck, try moving backwards as well as to side. --- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++---- apps/openmw/mwmechanics/obstacle.hpp | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index fe3d68a583..53f12a982e 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -15,6 +15,14 @@ namespace MWMechanics static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; + const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = + { + { 1.0f, 0.0f }, // move to side + { 1.0f, -1.0f }, // move to side and backwards + { -1.0f, 0.0f }, // move to other side + { -1.0f, -1.0f } // move to side and backwards + }; + // Proximity check function for interior doors. Given that most interior cells // do not have many doors performance shouldn't be too much of an issue. // @@ -69,7 +77,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time - , mEvadeDirection(1.0f) + , mEvadeDirectionIndex(0) { } @@ -176,8 +184,8 @@ namespace MWMechanics void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) { - actorMovement.mPosition[0] = mEvadeDirection; - actorMovement.mPosition[1] = 0; + actorMovement.mPosition[0] = evadeDirections[mEvadeDirectionIndex][0]; + actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } void ObstacleCheck::chooseEvasionDirection(bool samePosition) @@ -185,7 +193,11 @@ namespace MWMechanics // change direction if attempt didn't work if (samePosition && (0 < mEvadeDuration)) { - mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) + { + mEvadeDirectionIndex = 0; + } } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ef3e29e8b0..ecff00a5c2 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -13,6 +13,8 @@ namespace MWMechanics /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; + static const int NUM_EVADE_DIRECTIONS = 4; + /// tests actor's proximity to a closed door by default bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr = MIN_DIST_TO_DOOR_SQUARED, @@ -47,6 +49,9 @@ namespace MWMechanics float mPrevX; float mPrevY; + // directions to try moving in when get stuck + static const float evadeDirections[NUM_EVADE_DIRECTIONS][2]; + enum WalkState { State_Norm, @@ -58,7 +63,7 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed - float mEvadeDirection; + int mEvadeDirectionIndex; void chooseEvasionDirection(bool samePosition); }; From 8de3ce90a7e0d219137eaf61ec120c24f8419c2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:04:24 +0200 Subject: [PATCH 1080/1812] Add comments for weather IDs --- apps/openmw/mwworld/weather.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cdd0a8d79b..b0e617f2b0 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -458,16 +458,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mPlayingSoundID() { mWeatherSettings.reserve(10); - addWeather("Clear", fallback); - addWeather("Cloudy", fallback); - addWeather("Foggy", fallback); - addWeather("Overcast", fallback); - addWeather("Rain", fallback, "rain"); - addWeather("Thunderstorm", fallback, "rain heavy"); - addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); + addWeather("Clear", fallback); // 0 + addWeather("Cloudy", fallback); // 1 + addWeather("Foggy", fallback); // 2 + addWeather("Overcast", fallback); // 3 + addWeather("Rain", fallback, "rain"); // 4 + addWeather("Thunderstorm", fallback, "rain heavy"); // 5 + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) From 39b73405800bd3409184a894a0d899ba28904c41 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 Sep 2015 15:32:18 +0200 Subject: [PATCH 1081/1812] added mouse button settings for 3D scene (not in use yet) --- apps/opencs/model/settings/usersettings.cpp | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 24680ada3a..3daf7f9ecd 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -371,6 +371,41 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "list go to the first/last item"); } + declareSection ("scene-input", "3D Scene Input"); + { + QString left ("Left Mouse-Button"); + QString cLeft ("Ctrl-Left Mouse-Button"); + QString right ("Right Mouse-Button"); + QString cRight ("Ctrl-Right Mouse-Button"); + QString middle ("Middle Mouse-Button"); + QString cMiddle ("Ctrl-Middle Mouse-Button"); + + QStringList values; + values << left << cLeft << right << cRight << middle << cMiddle; + + Setting *primaryNavigation = createSetting (Type_ComboBox, "p-navi", "Primary Camera Navigation Button"); + primaryNavigation->setDeclaredValues (values); + primaryNavigation->setDefaultValue (left); + + Setting *secondaryNavigation = createSetting (Type_ComboBox, "s-navi", "Secondary Camera Navigation Button"); + secondaryNavigation->setDeclaredValues (values); + secondaryNavigation->setDefaultValue (cLeft); + + Setting *primaryEditing = createSetting (Type_ComboBox, "p-edit", "Primary Editing Button"); + primaryEditing->setDeclaredValues (values); + primaryEditing->setDefaultValue (right); + + Setting *secondaryEditing = createSetting (Type_ComboBox, "s-edit", "Secondary Editing Button"); + secondaryEditing->setDeclaredValues (values); + secondaryEditing->setDefaultValue (cRight); + + values << "Context Sensitive"; + + Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); + selection->setDeclaredValues (values); + selection->setDefaultValue (middle); + } + { /****************************************************************** * There are three types of values: From 6bafa564d4b96a7336490d6ea4be8b96438ee72b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:08:31 +0200 Subject: [PATCH 1082/1812] Move sun texture setting out of the Updater class so we can reuse the Updater for fading the flash texture --- apps/openmw/mwrender/sky.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dba2e5b0eb..67e842c8df 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -359,14 +359,20 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mUpdater(new Updater(textureManager)) + , mUpdater(new Updater) { - mGeode->addUpdateCallback(mUpdater); + mTransform->addUpdateCallback(mUpdater); + + osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); } ~Sun() { - mGeode->removeUpdateCallback(mUpdater); + mTransform->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) @@ -387,22 +393,15 @@ public: private: struct Updater : public SceneUtil::StateSetUpdater { - Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - Updater(Resource::TextureManager& textureManager) - : mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + Updater() + : mColor(1.f, 1.f, 1.f, 1.0f) { } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From d191a528470b990be094bf243b697694ad159dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:10:02 +0200 Subject: [PATCH 1083/1812] Create occlusion query nodes for the sun flash --- apps/openmw/mwrender/sky.cpp | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 67e842c8df..3d2b35c375 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -368,6 +371,18 @@ public: osg::Texture::CLAMP); mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + + // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area + osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); + queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + // Need to render after the world geometry so we can correctly test for occlusions + queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + + mTransform->addChild(queryTransform); + + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); } ~Sun() @@ -391,6 +406,46 @@ public: } private: + /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. + osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) + { + osg::ref_ptr oqn = new osg::OcclusionQueryNode; + oqn->setQueriesEnabled(true); + + // Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry, + // so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry + // is only called once. + // Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal. + oqn->getQueryGeometry()->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr queryGeode = osg::clone(mGeode.get(), osg::CopyOp::DEEP_COPY_ALL); + // Disable writing to the color buffer. We are using this geode for visibility tests only. + osg::ref_ptr colormask (new osg::ColorMask(0, 0, 0, 0)); + queryGeode->getOrCreateStateSet()->setAttributeAndModes(colormask, osg::StateAttribute::ON); + + oqn->addChild(queryGeode); + + if (queryVisible) + { + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::LESS); + // This is a trick to make fragments written by the query always use the maximum depth value, + // without having to retrieve the current far clipping distance. + // We want the sun glare to be "infinitely" far away. + depth->setZNear(1.0); + depth->setZFar(1.0); + oqn->getQueryStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + else + { + oqn->getQueryStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + } + + parent->addChild(oqn); + + return oqn; + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -414,6 +469,8 @@ private: }; osg::ref_ptr mUpdater; + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; }; class Moon : public CelestialBody From 89d9323c2b6d870d7ea5d0b3d33a84a834916ef5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:19:36 +0200 Subject: [PATCH 1084/1812] Document RenderBin numbers in a common header to keep them organised --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderbin.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/sky.cpp | 5 +++-- apps/openmw/mwrender/water.cpp | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwrender/renderbin.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2dd16a4e6c..5a9b52cb24 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,6 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation + renderbin ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderbin.hpp b/apps/openmw/mwrender/renderbin.hpp new file mode 100644 index 0000000000..63ccdd2599 --- /dev/null +++ b/apps/openmw/mwrender/renderbin.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_MWRENDER_RENDERBIN_H +#define OPENMW_MWRENDER_RENDERBIN_H + +namespace MWRender +{ + + /// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first. + /// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false). + enum RenderBins + { + RenderBin_Sky = -1, + RenderBin_Default = 0, + RenderBin_Water = 9, + RenderBin_OcclusionQuery = 10, + RenderBin_SunGlare = 11 + }; + +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3d2b35c375..8588d21588 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -41,6 +41,7 @@ #include "../mwworld/fallback.hpp" #include "vismask.hpp" +#include "renderbin.hpp" namespace { @@ -376,7 +377,7 @@ public: osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); mTransform->addChild(queryTransform); @@ -680,7 +681,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); + mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); } void SkyManager::create() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b5f141963a..03ab58e6be 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -21,6 +21,7 @@ #include "vismask.hpp" #include "ripplesimulation.hpp" +#include "renderbin.hpp" namespace { @@ -86,7 +87,7 @@ namespace depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - stateset->setRenderBinDetails(9, "RenderBin"); + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; for (int i=0; i<32; ++i) From ac5d0bf40502f355a2bd46cdf57c12b3723d59b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:22:16 +0200 Subject: [PATCH 1085/1812] Render the sun flash (not adjusted based on occlusion yet) --- apps/openmw/mwrender/sky.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8588d21588..17b4f2f6a9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -364,6 +364,7 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) + , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -384,6 +385,8 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + + createSunFlash(textureManager); } ~Sun() @@ -447,6 +450,34 @@ private: return oqn; } + void createSunFlash(Resource::TextureManager& textureManager) + { + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + + mTransform->addChild(transform); + + osg::ref_ptr geode (new osg::Geode); + transform->addChild(geode); + + geode->addDrawable(createTexturedQuad()); + + osg::StateSet* stateset = geode->getOrCreateStateSet(); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + + // TODO: change size depending on occlusion + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -472,6 +503,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; + float mInitialFlashScale; }; class Moon : public CelestialBody From a2a4532e71317332068e6617a29a2bfc5aa20544 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:03:30 +0200 Subject: [PATCH 1086/1812] Add the full-screen sun glare effect --- apps/openmw/mwrender/sky.cpp | 262 +++++++++++++++++++++++++++++--- apps/openmw/mwrender/sky.hpp | 3 +- apps/openmw/mwworld/weather.cpp | 8 + 3 files changed, 254 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 17b4f2f6a9..69041a7248 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -376,7 +377,7 @@ public: // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); // Need to render after the world geometry so we can correctly test for occlusions queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); @@ -386,17 +387,26 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - createSunFlash(textureManager); + osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); + mTransform->addCullCallback(mSunFlashCallback); + + createSunGlare(); } ~Sun() { mTransform->removeUpdateCallback(mUpdater); + destroySunFlash(); + destroySunGlare(); } virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; + if (mSunGlareCallback) + mSunGlareCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -409,6 +419,12 @@ public: mTransform->setAttitude(quat); } + void setGlareTimeOfDayFade(float val) + { + if (mSunGlareCallback) + mSunGlareCallback->setTimeOfDayFade(val); + } + private: /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) @@ -450,7 +466,7 @@ private: return oqn; } - void createSunFlash(Resource::TextureManager& textureManager) + osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -474,12 +490,58 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); - - // TODO: change size depending on occlusion + return transform; + } + void destroySunFlash() + { + mTransform->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; } - struct Updater : public SceneUtil::StateSetUpdater + void createSunGlare() { + osg::ref_ptr camera (new osg::Camera); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // add to skyRoot instead? + camera->setViewMatrix(osg::Matrix::identity()); + camera->setClearMask(0); + camera->setRenderOrder(osg::Camera::NESTED_RENDER); + camera->setAllowEventFocus(false); + + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(2,0,0), osg::Vec3f(0,2,0)); + geode->addDrawable(geom); + + camera->addChild(geode); + + osg::StateSet* stateset = geom->getOrCreateStateSet(); + + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + // set up additive blending + osg::ref_ptr blendFunc (new osg::BlendFunc); + blendFunc->setSource(osg::BlendFunc::SRC_ALPHA); + blendFunc->setDestination(osg::BlendFunc::ONE); + stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON); + + mSunGlareCallback = new SunGlareCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, mTransform); + mSunGlareNode = camera; + + mSunGlareNode->addCullCallback(mSunGlareCallback); + + mTransform->addChild(camera); + } + void destroySunGlare() + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; + } + + class Updater : public SceneUtil::StateSetUpdater + { + public: osg::Vec4f mColor; Updater() @@ -489,8 +551,7 @@ private: virtual void setDefaults(osg::StateSet* stateset) { - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) @@ -500,7 +561,181 @@ private: } }; + class OcclusionCallback : public osg::NodeCallback + { + public: + OcclusionCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) + : mOcclusionQueryVisiblePixels(oqnVisible) + , mOcclusionQueryTotalPixels(oqnTotal) + { + } + + protected: + float getVisibleRatio (osg::Camera* camera) + { + int visible = mOcclusionQueryVisiblePixels->getQueryGeometry()->getNumPixels(camera); + int total = mOcclusionQueryTotalPixels->getQueryGeometry()->getNumPixels(camera); + + float visibleRatio = 0.f; + if (total > 0) + visibleRatio = static_cast(visible) / static_cast(total); + + float dt = MWBase::Environment::get().getFrameDuration(); + + float lastRatio = mLastRatio[osg::observer_ptr(camera)]; + + float change = dt*10; + + if (visibleRatio > lastRatio) + visibleRatio = std::min(visibleRatio, lastRatio + change); + else + visibleRatio = std::max(visibleRatio, lastRatio - change); + + mLastRatio[osg::observer_ptr(camera)] = visibleRatio; + + return visibleRatio; + } + + private: + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; + + std::map, float> mLastRatio; + }; + + /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + class SunFlashCallback : public OcclusionCallback + { + public: + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr flashNode, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mFlashNode(flashNode) + { + mInitialScale = mFlashNode->getScale().x(); + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + handleOcclusionResult (visibleRatio, cv); + + traverse(node, nv); + } + + void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) + { + // TODO + } + + private: + float mInitialScale; + osg::ref_ptr mFlashNode; + }; + + + /// SunGlareCallback controls a full-screen glare effect depending on occlusion query result and the angle between sun and camera. + /// Must be attached as a cull callback to the node above the glare node. + class SunGlareCallback : public OcclusionCallback + { + public: + SunGlareCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mSunTransform(sunTransform) + , mTimeOfDayFade(1.f) + , mGlareView(1.f) + { + + } + + virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max + + float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians); + + const float sunGlareFaderMax = 0.5f; + float fade = value * sunGlareFaderMax; + + fade *= mTimeOfDayFade * mGlareView * visibleRatio; + + if (fade == 0.f) + { + // no traverse + return; + } + else + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr mat (createUnlitMaterial()); + + osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1); + + // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, + // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, + // so the resulting color looks more orange than red. + sunGlareFaderColor *= 2; + for (int i=0; i<3; ++i) + sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); + + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); + mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + + cv->pushStateSet(stateset); + traverse(node, nv); + cv->popStateSet(); + } + } + + void setTimeOfDayFade(float val) + { + mTimeOfDayFade = val; + } + + void setGlareView(float glareView) + { + mGlareView = glareView; + } + + private: + float getAngleToSunInRadians(osg::Camera* camera) const + { + osg::Vec3d eye, center, up; + camera->getViewMatrixAsLookAt(eye, center, up); + + osg::Vec3d forward = center - eye; + osg::Vec3d sun = mSunTransform->getPosition(); + + forward.normalize(); + sun.normalize(); + float angleRadians = std::acos(forward * sun); + return angleRadians; + } + + osg::ref_ptr mSunTransform; + float mTimeOfDayFade; + float mGlareView; + }; + osg::ref_ptr mUpdater; + osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunGlareCallback; + osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; float mInitialFlashScale; @@ -1223,11 +1458,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleFader->setAlpha(weather.mEffectFade); } -void SkyManager::setGlare(const float glare) -{ - mGlare = glare; -} - void SkyManager::sunEnable() { if (!mCreated) return; @@ -1276,11 +1506,9 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -void SkyManager::setGlareEnabled (bool enabled) +void SkyManager::setGlareTimeOfDayFade(float val) { - if (!mCreated || !mEnabled) - return; - //mSunGlare->setVisible (mSunEnabled && enabled); + mSun->setGlareTimeOfDayFade(val); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index de27cf4479..b9b27b3d0d 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,7 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setGlare(const float glare); - void setGlareEnabled(bool enabled); + void setGlareTimeOfDayFade(float val); private: void create(); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b0e617f2b0..050b6652cd 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -624,6 +624,14 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; + if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) + mRendering.getSkyManager()->setGlareTimeOfDayFade(0); + else if (time.getHour() < peakHour) + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (peakHour - time.getHour()) / (peakHour - mSunriseTime)); + else + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (time.getHour() - peakHour) / (mSunsetTime - peakHour)); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); From 96b31d3bba084e2a95ae63c3f245b427dc1f3977 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:34:30 +0200 Subject: [PATCH 1087/1812] Scale the sun flash texture depending on occlusion query --- apps/openmw/mwrender/sky.cpp | 73 ++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 69041a7248..78b1aba705 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -387,11 +387,7 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); - - mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); - mTransform->addCullCallback(mSunFlashCallback); - + createSunFlash(textureManager); createSunGlare(); } @@ -466,7 +462,7 @@ private: return oqn; } - osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) + void createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -490,12 +486,19 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); - return transform; + + mSunFlashNode = transform; + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels); + mSunFlashNode->addCullCallback(mSunFlashCallback); } void destroySunFlash() { - mTransform->removeCullCallback(mSunFlashCallback); - mSunFlashCallback = NULL; + if (mSunFlashNode) + { + mSunFlashNode->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; + } } void createSunGlare() @@ -535,8 +538,11 @@ private: } void destroySunGlare() { - mSunGlareNode->removeCullCallback(mSunGlareCallback); - mSunGlareCallback = NULL; + if (mSunGlareNode) + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; + } } class Updater : public SceneUtil::StateSetUpdater @@ -603,17 +609,13 @@ private: std::map, float> mLastRatio; }; - /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + /// SunFlashCallback handles fading/scaling of a node depending on occlusion query result. Must be attached as a cull callback. class SunFlashCallback : public OcclusionCallback { public: - SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, - osg::ref_ptr flashNode, - osg::ref_ptr sunTransform) + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) - , mFlashNode(flashNode) { - mInitialScale = mFlashNode->getScale().x(); } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -622,19 +624,33 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); - handleOcclusionResult (visibleRatio, cv); + if (visibleRatio > 0.f) + { + // rescale into [0.35, 1.0] range + const float threshold = 0.35; + visibleRatio = visibleRatio * (1.f - threshold) + threshold; + } - traverse(node, nv); + float scale = visibleRatio; + + if (scale == 0.f) + { + // no traverse + return; + } + else + { + osg::Matrix modelView = *cv->getModelViewMatrix(); + + modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); + } } - - void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) - { - // TODO - } - - private: - float mInitialScale; - osg::ref_ptr mFlashNode; }; @@ -734,6 +750,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunFlashNode; osg::ref_ptr mSunGlareCallback; osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; From 9bb6c3f288c001ba11a2c08bf260ad927410f253 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:09:24 +0200 Subject: [PATCH 1088/1812] Improve accuracy of sun occlusion query (use circular shape) --- apps/openmw/mwrender/sky.cpp | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 78b1aba705..63a041579c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -375,17 +376,20 @@ public: mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area - osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); + osg::ref_ptr queryNode (new osg::Group); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); - queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + queryNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); + queryNode->getOrCreateStateSet()->setNestRenderBins(false); + // Set up alpha testing on the occlusion testing subgraph, that way we can get the occlusion tested fragments to match the circular shape of the sun + osg::ref_ptr alphaFunc (new osg::AlphaFunc); + alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); + queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - mTransform->addChild(queryTransform); + mTransform->addChild(queryNode); - mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); - mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false); createSunFlash(textureManager); createSunGlare(); @@ -441,6 +445,26 @@ private: oqn->addChild(queryGeode); + // Remove the default OFF|PROTECTED setting for texturing. We *want* to enable texturing for alpha testing purposes + oqn->getQueryStateSet()->removeTextureMode(0, GL_TEXTURE_2D); + + // Need to add texture coordinates so that texturing works. A bit ugly, relies on the vertex ordering + // used within OcclusionQueryNode. + osg::ref_ptr texCoordArray (new osg::Vec2Array); + for (int i=0; i<8; ++i) + { + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(1,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(1,1)); + } + + oqn->getQueryGeometry()->setTexCoordArray(0, texCoordArray, osg::Array::BIND_PER_VERTEX); + if (queryVisible) { osg::ref_ptr depth (new osg::Depth); @@ -626,8 +650,7 @@ private: if (visibleRatio > 0.f) { - // rescale into [0.35, 1.0] range - const float threshold = 0.35; + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } From 854fd9fe051c17395ec49a4e8321497b1c9e721e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:18:27 +0200 Subject: [PATCH 1089/1812] Remove dead code --- apps/openmw/mwrender/sky.cpp | 53 ++++++------------------------------ apps/openmw/mwrender/sky.hpp | 3 -- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 63a041579c..86a9a1765f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -972,8 +972,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) - , mGlare(0.0f) - , mGlareFade(0.0f) , mRainEnabled(false) , mRainSpeed(0) , mRainFrequency(1) @@ -1290,32 +1288,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - if (mSunEnabled) - { - // take 1/10 sec for fading the glare effect from invisible to full - if (mGlareFade > mGlare) - { - mGlareFade -= duration*10; - if (mGlareFade < mGlare) mGlareFade = mGlare; - } - else if (mGlareFade < mGlare) - { - mGlareFade += duration*10; - if (mGlareFade > mGlare) mGlareFade = mGlare; - } - - // increase the strength of the sun glare effect depending - // on how directly the player is looking at the sun - /* - Vector3 sun = mSunGlare->getPosition(); - Vector3 cam = mCamera->getRealDirection(); - const Degree angle = sun.angleBetween( cam ); - float val = 1- (angle.valueDegrees() / 180.f); - val = (val*val*val*val)*6; - mSunGlare->setSize(val * mGlareFade); - */ - } - // rotate the stars by 360 degrees every 4 days mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f); if (mAtmosphereNightNode->getNodeMask() != 0) @@ -1466,6 +1438,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); + + /* + float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); + float strength; + if (timeofday_angle <= 0.44) + strength = timeofday_angle/0.44f; + else + strength = 1.f; + */ mSun->adjustTransparency(weather.mGlareView); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; @@ -1478,20 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); - - /* - float strength; - float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - - mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - - mSun->setVisibility(weather.mGlareView * strength); - */ - if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? if (mParticleFader) @@ -1522,8 +1489,6 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) if (!mCreated) return; mSun->setDirection(direction); - - //mSunGlare->setPosition(direction); } void SkyManager::setMasserState(const MoonState& state) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index b9b27b3d0d..0cef463460 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -209,9 +209,6 @@ namespace MWRender float mRemainingTransitionTime; - float mGlare; // target - float mGlareFade; // actual - bool mRainEnabled; std::string mRainEffect; float mRainSpeed; From d812434feeb8b32aa1edada2e240994e5715cd43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:32:57 +0200 Subject: [PATCH 1090/1812] Add a subtle fading effect to the sun flash texture --- apps/openmw/mwrender/sky.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 86a9a1765f..7f5666b17a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -385,6 +385,7 @@ public: alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); mTransform->addChild(queryNode); @@ -407,6 +408,8 @@ public: mUpdater->mColor.a() = ratio; if (mSunGlareCallback) mSunGlareCallback->setGlareView(ratio); + if (mSunFlashCallback) + mSunFlashCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -505,8 +508,6 @@ private: osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); @@ -639,6 +640,7 @@ private: public: SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) + , mGlareView(1.f) { } @@ -648,8 +650,20 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + osg::ref_ptr stateset; + if (visibleRatio > 0.f) { + const float fadeThreshold = 0.1; + if (visibleRatio < fadeThreshold) + { + float fade = 1.f - (fadeThreshold - visibleRatio) / fadeThreshold; + osg::ref_ptr mat (createUnlitMaterial()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade*mGlareView)); + stateset = new osg::StateSet; + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } @@ -667,13 +681,27 @@ private: modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + if (stateset) + cv->pushStateSet(stateset); + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); + + if (stateset) + cv->popStateSet(); } } + + void setGlareView(float value) + { + mGlareView = value; + } + + private: + float mGlareView; }; @@ -728,10 +756,8 @@ private: for (int i=0; i<3; ++i) sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); From 1a1f1fae87097885d11773f0137aed5ba0f03b51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:50:36 +0200 Subject: [PATCH 1091/1812] Minor cleanup --- apps/openmw/mwrender/sky.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7f5666b17a..754e009099 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -366,7 +366,6 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) - , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -496,7 +495,8 @@ private: osg::Texture::CLAMP); osg::ref_ptr transform (new osg::PositionAttitudeTransform); - transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + const float scale = 2.6f; + transform->setScale(osg::Vec3f(scale,scale,scale)); mTransform->addChild(transform); @@ -804,7 +804,6 @@ private: osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; - float mInitialFlashScale; }; class Moon : public CelestialBody From f7e5a40143d0db37e349ee5e3541c3e2e2ace1b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:58:57 +0200 Subject: [PATCH 1092/1812] Fix typo --- components/sceneutil/statesetupdater.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index a4fcd7866e..37d08e025c 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -6,7 +6,7 @@ namespace SceneUtil { - /// @brief Implements efficient pre-frame updating of StateSets. + /// @brief Implements efficient per-frame updating of StateSets. /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw From 385f4f729c967c02fbcc6fac062af9c0d27a82b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 19:43:48 +0200 Subject: [PATCH 1093/1812] Implement SunDiscSunsetColor, fade the sun during sunrise & sunset --- apps/openmw/mwrender/sky.cpp | 23 ++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 ++ apps/openmw/mwworld/weather.cpp | 33 ++++++++++++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 9 ++------- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 754e009099..317f2229d6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -402,6 +402,13 @@ public: destroySunGlare(); } + void setColor(const osg::Vec4f& color) + { + mUpdater->mColor.r() = color.r(); + mUpdater->mColor.g() = color.g(); + mUpdater->mColor.b() = color.b(); + } + virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; @@ -576,7 +583,7 @@ private: osg::Vec4f mColor; Updater() - : mColor(1.f, 1.f, 1.f, 1.0f) + : mColor(1.f, 1.f, 1.f, 1.f) { } @@ -588,7 +595,8 @@ private: virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mColor.a())); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(mColor.r(), mColor.g(), mColor.b(), 1)); } }; @@ -1464,15 +1472,8 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); - /* - float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); - float strength; - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - */ - mSun->adjustTransparency(weather.mGlareView); + mSun->setColor(weather.mSunDiscColor); + mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a()); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0cef463460..072083d270 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -48,8 +48,10 @@ namespace MWRender osg::Vec4f mSkyColor; + // sun light color osg::Vec4f mSunColor; + // alpha is the sun transparency osg::Vec4f mSunDiscColor; float mFogDepth; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 050b6652cd..78ae6fa0bf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -432,6 +432,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) , mNightStart(mSunsetTime + mSunsetDuration) , mNightEnd(mSunriseTime - 0.5f) , mDayStart(mSunriseTime + mSunriseDuration) @@ -966,7 +967,6 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mAmbientSoundVolume = 1.f; mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; mResult.mIsStorm = current.mIsStorm; @@ -980,6 +980,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + // TODO: use pre/post sunset/sunrise time values in [Weather] section // night if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) { @@ -1050,6 +1051,36 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNightFade = factor; } } + + if (gameHour >= mSunsetTime - mSunPreSunsetTime) + { + float factor = (gameHour - (mSunsetTime - mSunPreSunsetTime)) / mSunPreSunsetTime; + factor = std::min(1.f, factor); + mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor); + // The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because + // MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline + // would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped. + // Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense. + mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor); + for (int i=0; i<3; ++i) + mResult.mSunDiscColor[i] = std::min(1.f, mResult.mSunDiscColor[i]); + } + else + mResult.mSunDiscColor = osg::Vec4f(1,1,1,1); + + if (gameHour >= mSunsetTime) + { + float fade = std::min(1.f, (gameHour - mSunsetTime) / 2.f); + fade = fade*fade; + mResult.mSunDiscColor.a() = 1.f - fade; + } + else if (gameHour >= mSunriseTime && gameHour <= mSunriseTime + 1) + { + mResult.mSunDiscColor.a() = gameHour - mSunriseTime; + } + else + mResult.mSunDiscColor.a() = 1; + } inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a0c93a4604..7ce7c1bf84 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -75,7 +75,7 @@ namespace MWWorld float mLandFogDayDepth; float mLandFogNightDepth; - // Color modulation for the sun itself during sunset (not completely sure) + // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) @@ -242,12 +242,7 @@ namespace MWWorld float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - // Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ + float mSunPreSunsetTime; float mNightStart; float mNightEnd; float mDayStart; From 7bef97bf3331dbdf9544c2caad17ecf68b3be96b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 22 Sep 2015 15:36:00 +0200 Subject: [PATCH 1094/1812] fixed local variable caching issue in automatic error checking (Fixes #2927) --- apps/opencs/model/world/scriptcontext.cpp | 17 +++++++++++-- apps/opencs/model/world/scriptcontext.hpp | 3 +++ apps/opencs/view/world/scripterrortable.cpp | 5 ++++ apps/opencs/view/world/scripterrortable.hpp | 5 ++++ apps/opencs/view/world/scriptsubview.cpp | 27 ++++++++++++++++++++- apps/opencs/view/world/scriptsubview.hpp | 1 + 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index bcbca4b28d..f644ad37ad 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -39,8 +39,6 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const std::pair CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const { - /// \todo invalidate locals cache on change to scripts - std::string id2 = Misc::StringUtils::lowerCase (id); int index = mData.getScripts().searchId (id2); @@ -120,3 +118,18 @@ void CSMWorld::ScriptContext::clear() mIdsUpdated = false; mLocals.clear(); } + +bool CSMWorld::ScriptContext::clearLocals (const std::string& script) +{ + std::map::iterator iter = + mLocals.find (Misc::StringUtils::lowerCase (script)); + + if (iter!=mLocals.end()) + { + mLocals.erase (iter); + mIdsUpdated = false; + return true; + } + + return false; +} diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 29ee42645a..2cd59f070f 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -46,6 +46,9 @@ namespace CSMWorld void clear(); ///< Remove all cached data. + + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); }; } diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index b44e1c0bde..a9e315c73c 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -131,6 +131,11 @@ void CSVWorld::ScriptErrorTable::clear() setRowCount (0); } +bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) +{ + return mContext.clearLocals (script); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 98db425cfd..33af7c8643 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -44,6 +44,11 @@ namespace CSVWorld void clear(); + /// Clear local variable cache for \a script. + /// + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d405d17652..d99f789b3a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -89,6 +89,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mIdColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -241,6 +242,15 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo ScriptEdit::ChangeLock lock (*mEditor); + bool updateRequired = false; + + for (int i=topLeft.row(); i<=bottomRight.row(); ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) @@ -256,13 +266,28 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - recompile(); + updateRequired = true; } } + + if (updateRequired) + recompile(); } void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + bool updateRequired = false; + + for (int i=start; i<=end; ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + + if (updateRequired) + recompile(); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (!parent.isValid() && index.row()>=start && index.row()<=end) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6125dd259d..907dc7958b 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mIdColumn; int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; From 12b8fcf0bfb4cd5950a1f1dd7e7be460d5f3a75a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Sep 2015 23:37:09 +0200 Subject: [PATCH 1095/1812] OpenCS: Fix camera position retrieval in WorldspaceWidget --- apps/opencs/view/render/pagedworldspacewidget.cpp | 5 ++++- apps/opencs/view/render/unpagedworldspacewidget.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 274c776201..b0c1e74a9a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -170,7 +170,10 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; + std::ostringstream stream; stream diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a5733ad102..3e1733c819 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,7 +166,9 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; std::ostringstream stream; From 7d4125d97ff1e79ad19f9d11f43410c50de9354c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:21:42 +0200 Subject: [PATCH 1096/1812] Fixes for building with unity build --- apps/openmw/CMakeLists.txt | 3 ++- apps/openmw/mwgui/dialogue.cpp | 28 ++++++++++---------- apps/openmw/mwmechanics/steering.hpp | 1 + apps/openmw/mwrender/camera.cpp | 6 ++--- apps/openmw/mwrender/globalmap.cpp | 6 ++--- apps/openmw/mwrender/localmap.cpp | 6 ++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 24 ++++++++--------- apps/openmw/mwscript/statsextensions.cpp | 2 +- apps/openmw/mwworld/store.cpp | 6 ++--- apps/openmw/mwworld/weather.cpp | 5 ++-- components/CMakeLists.txt | 2 +- components/files/windowspath.cpp | 2 +- components/vfs/bsaarchive.hpp | 5 ++++ 14 files changed, 50 insertions(+), 47 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5a9b52cb24..fa05576f5d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor + store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager ) @@ -179,4 +179,5 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + add_definitions("-D_USE_MATH_DEFINES") endif (MSVC) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a6000a739d..d325886316 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -31,7 +31,7 @@ namespace { - MyGUI::Colour getTextColour (const std::string& type) + MyGUI::Colour getDialogueTextColour (const std::string& type) { return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}")); } @@ -115,7 +115,7 @@ namespace MWGui void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("header")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("header")); typesetter->sectionBreak(9); if (mTitle != "") typesetter->write(title, to_utf8_span(mTitle.c_str())); @@ -159,14 +159,14 @@ namespace MWGui if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { intptr_t topicId = it->second; - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); if (formatted < it->first.first) typesetter->write(style, formatted, it->first.first); @@ -199,11 +199,11 @@ namespace MWGui void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); if (topicId) style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); @@ -217,7 +217,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("notify")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("notify")); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -486,9 +486,9 @@ namespace MWGui typesetter->sectionBreak(9); // choices - const MyGUI::Colour linkHot (getTextColour("answer_over")); - const MyGUI::Colour linkNormal (getTextColour("answer")); - const MyGUI::Colour linkActive (getTextColour("answer_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("answer_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("answer")); + const MyGUI::Colour linkActive(getDialogueTextColour("answer_pressed")); for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 4b29dc1d93..632ab36115 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -1,4 +1,5 @@ #ifndef OPENMW_MECHANICS_STEERING_H +#define OPENMW_MECHANICS_STEERING_H #include diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 316c9308be..fb6573d65f 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -14,10 +14,10 @@ namespace { -class UpdateCameraCallback : public osg::NodeCallback +class UpdateRenderCameraCallback : public osg::NodeCallback { public: - UpdateCameraCallback(MWRender::Camera* cam) + UpdateRenderCameraCallback(MWRender::Camera* cam) : mCamera(cam) { } @@ -67,7 +67,7 @@ namespace MWRender mMainCam.yaw = 0.f; mMainCam.offset = 400.f; - mUpdateCallback = new UpdateCameraCallback(this); + mUpdateCallback = new UpdateRenderCameraCallback(this); mCamera->addUpdateCallback(mUpdateCallback); } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 7acda92a32..3445e4189b 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -59,10 +59,10 @@ namespace } - class CameraUpdateCallback : public osg::NodeCallback + class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -263,7 +263,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 02ca0cb4c6..fe685f97c0 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -27,10 +27,10 @@ namespace { - class CameraUpdateCallback : public osg::NodeCallback + class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -205,7 +205,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); return camera; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 317f2229d6..6f1b26733e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,6 +1,5 @@ #include "sky.hpp" -#define _USE_MATH_DEFINES #include #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index e33c7580fb..4e3e010f7e 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,10 +56,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); @@ -97,10 +97,10 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); @@ -131,10 +131,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 4debb24fed..e4ad71875f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -228,7 +228,7 @@ namespace MWScript // workaround broken endgame scripts that kill dagoth ur if (!R::implicit && - Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) + ::Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) { runtime.push (peek); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 29187f950d..b647a6c888 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -994,7 +994,7 @@ namespace MWWorld template<> - inline void Store::setUp() + void Store::setUp() { // DialInfos marked as deleted are kept during the loading phase, so that the linked list // structure is kept intact for inserting further INFOs. Delete them now that loading is done. @@ -1013,7 +1013,7 @@ namespace MWWorld } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); std::map::iterator it = mStatic.find(idLower); @@ -1029,7 +1029,6 @@ namespace MWWorld // Script //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::Script scpt; scpt.load(esm); @@ -1046,7 +1045,6 @@ namespace MWWorld // StartScript //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::StartScript s; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 78ae6fa0bf..5008d8fbfc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,6 +1,3 @@ -#define _USE_MATH_DEFINES -#include - #include "weather.hpp" #include @@ -26,6 +23,8 @@ #include "fallback.hpp" #include "cellstore.hpp" +#include + using namespace MWWorld; namespace diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 946c3af164..00eac6ca52 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -47,7 +47,7 @@ add_component_dir (sceneutil ) add_component_dir (nif - controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream + controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream ) add_component_dir (nifosg diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index ece4049a87..4b7c6c50a8 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -4,9 +4,9 @@ #include -#include #include #include +#include #include namespace bconv = boost::locale::conv; diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 9617469470..25ad60e0a6 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -1,3 +1,6 @@ +#ifndef VFS_BSAARCHIVE_HPP_ +#define VFS_BSAARCHIVE_HPP_ + #include "archive.hpp" #include @@ -30,3 +33,5 @@ namespace VFS }; } + +#endif \ No newline at end of file From b2cb5f037447e6baa8ad6bbdeb076c388d89595a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Sep 2015 15:51:16 +0200 Subject: [PATCH 1097/1812] pass on user settings updates to potentially interested parties within a scene subview --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.cpp | 5 +++++ apps/opencs/view/render/worldspacewidget.hpp | 2 ++ apps/opencs/view/widget/scenetoolmode.cpp | 5 +++++ apps/opencs/view/widget/scenetoolmode.hpp | 3 +++ apps/opencs/view/world/scenesubview.cpp | 15 ++++++++++++--- apps/opencs/view/world/scenesubview.hpp | 4 ++++ 8 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 8a99ba0490..bf96fea3a5 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -16,3 +16,8 @@ void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); } + +void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) +{ + +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c3192f8ea5..381a6abcb4 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -22,6 +22,9 @@ namespace CSVRender unsigned int getInteractionMask() const; virtual void activate (CSVWidget::SceneToolbar *toolbar); + + /// Default-implementation: Do nothing. + virtual void updateUserSetting (const QString& name, const QStringList& value); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a1f0f6bf2a..2eb84d0a28 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -254,6 +254,11 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const return mInteractionMask & getVisibilityMask(); } +void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) +{ + +} + void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index fe4555820a..c3796af34a 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -93,6 +93,8 @@ namespace CSVRender /// marked for interaction. unsigned int getInteractionMask() const; + virtual void updateUserSetting (const QString& name, const QStringList& value); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 9f963873c8..a93bb05567 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -71,6 +71,11 @@ void CSVWidget::SceneToolMode::addButton (ModeButton *button, const std::string& } } +CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent() +{ + return mCurrent; +} + void CSVWidget::SceneToolMode::selected() { std::map::const_iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index e6f462cf89..6828a22691 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -41,6 +41,9 @@ namespace CSVWidget /// The ownership of \a button is transferred to *this. void addButton (ModeButton *button, const std::string& id); + /// Will return a 0-pointer only if the mode does not have any buttons yet. + ModeButton *getCurrent(); + signals: void modeChanged (const std::string& id); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index c2f3442f89..f0b18dd864 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -15,6 +15,7 @@ #include "../render/pagedworldspacewidget.hpp" #include "../render/unpagedworldspacewidget.hpp" +#include "../render/editmode.hpp" #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" @@ -26,7 +27,8 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) +: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), + mEditMode (0) { QVBoxLayout *layout = new QVBoxLayout; @@ -121,8 +123,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); - CSVWidget::SceneToolMode *editModeTool = widget->makeEditModeSelector (toolbar); - toolbar->addTool (editModeTool); + mEditMode = widget->makeEditModeSelector (toolbar); + toolbar->addTool (mEditMode); return toolbar; } @@ -147,6 +149,13 @@ std::string CSVWorld::SceneSubView::getTitle() const return mTitle; } +void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) +{ + mScene->updateUserSetting (name, value); + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); + CSVDoc::SubView::updateUserSetting (name, value); +} + void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index a34d719013..29aca5ab63 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -27,6 +27,7 @@ namespace CSVRender namespace CSVWidget { class SceneToolbar; + class SceneToolMode; } namespace CSVWorld @@ -45,6 +46,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSVWidget::SceneToolbar* mToolbar; std::string mTitle; + CSVWidget::SceneToolMode *mEditMode; public: @@ -58,6 +60,8 @@ namespace CSVWorld virtual std::string getTitle() const; + virtual void updateUserSetting (const QString& name, const QStringList& value); + private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); From caa119f13c7599736b7e7466371d09c92cd696db Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:55:38 +0200 Subject: [PATCH 1098/1812] Fix instantiation on non-Visual Studio --- apps/openmw/mwworld/store.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index b647a6c888..7a471eaa4b 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1029,7 +1029,8 @@ namespace MWWorld // Script //========================================================================= - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::Script scpt; scpt.load(esm); Misc::StringUtils::toLower(scpt.mId); @@ -1045,7 +1046,8 @@ namespace MWWorld // StartScript //========================================================================= - inline void Store::load(ESM::ESMReader &esm, const std::string &id) + template <> + void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::StartScript s; s.load(esm); From 3ada08af90dab4440247ba4b3190b669e6b42b73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Sep 2015 16:07:17 +0200 Subject: [PATCH 1099/1812] store lock state and pass it on to edit mode --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/world/scenesubview.cpp | 13 +++++++++++-- apps/opencs/view/world/scenesubview.hpp | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index bf96fea3a5..c3aad3f7a1 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -21,3 +21,8 @@ void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringL { } + +void CSVRender::EditMode::setEditLock (bool locked) +{ + +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 381a6abcb4..1212cd2854 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -25,6 +25,9 @@ namespace CSVRender /// Default-implementation: Do nothing. virtual void updateUserSetting (const QString& name, const QStringList& value); + + /// Default-implementation: Ignored. + virtual void setEditLock (bool locked); }; } diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index f0b18dd864..9679099697 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -28,7 +28,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), - mEditMode (0) + mEditMode (0), mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -131,7 +131,8 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp void CSVWorld::SceneSubView::setEditLock (bool locked) { - + mLocked = locked; + dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); } void CSVWorld::SceneSubView::setStatusBar (bool show) @@ -258,4 +259,12 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); + + connect (mEditMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (editModeChanged (const std::string&))); +} + +void CSVWorld::SceneSubView::editModeChanged (const std::string& id) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); } diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 29aca5ab63..f59fee37f6 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -47,6 +47,7 @@ namespace CSVWorld CSVWidget::SceneToolbar* mToolbar; std::string mTitle; CSVWidget::SceneToolMode *mEditMode; + bool mLocked; public: @@ -85,6 +86,8 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); + + void editModeChanged (const std::string& id); }; } From d597bef2cda32eea1c12d623d0956d6e18b05976 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 10:58:20 +0200 Subject: [PATCH 1100/1812] refined selection related user settings --- apps/opencs/model/settings/usersettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3daf7f9ecd..5cc60c3184 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -399,11 +399,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() secondaryEditing->setDeclaredValues (values); secondaryEditing->setDefaultValue (cRight); - values << "Context Sensitive"; - Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); selection->setDeclaredValues (values); selection->setDefaultValue (middle); + + Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); + contextSensitive->setDefaultValue ("false"); } { From 5c34a0205804dd718cc4d6efe26ee3be51b37101 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 13:11:40 +0200 Subject: [PATCH 1101/1812] store mouse bindings in WorldspaceWidget --- apps/opencs/view/render/worldspacewidget.cpp | 57 +++++++++++++++++++- apps/opencs/view/render/worldspacewidget.hpp | 6 +++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2eb84d0a28..5d866fc6c5 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -18,6 +18,8 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/settings/usersettings.hpp" + #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" @@ -26,6 +28,17 @@ #include "elements.hpp" #include "editmode.hpp" +namespace +{ + static const char * const sMappingSettings[] = + { + "p-navi", "s-navi", + "p-edit", "s-edit", + "select", + 0 + }; +} + CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0) @@ -59,6 +72,13 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&))); connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); + + for (int i=0; sMappingSettings[i]; ++i) + { + QString key ("scene-input/"); + key += sMappingSettings[i]; + storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); + } } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -256,7 +276,8 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) { - + if (!value.isEmpty() && storeMappingSetting (name, value.first())) + return; } void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( @@ -293,6 +314,40 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) event->accept(); } + +bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const QString& value) +{ + const QString prefix = "scene-input/"; + + if (key.startsWith (prefix)) + { + QString key2 (key.mid (prefix.length())); + + for (int i=0; sMappingSettings[i]; ++i) + if (key2==sMappingSettings[i]) + { + std::cout<<"button :"< (event->mimeData()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index c3796af34a..23f672fbdb 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H #define OPENCS_VIEW_WORLDSPACEWIDGET_H +#include + #include #include "scenewidget.hpp" @@ -31,6 +33,7 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; unsigned int mInteractionMask; + std::map, std::string> mButtonMapping; public: @@ -120,6 +123,9 @@ namespace CSVRender void dragMoveEvent(QDragMoveEvent *event); + /// \return Is \a key a button mapping setting? (ignored otherwise) + bool storeMappingSetting (const QString& key, const QString& value); + virtual std::string getStartupInstruction() = 0; private slots: From d46eeb04cd49d3543e3800707789fde4bdf8cadf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Sep 2015 14:16:41 +0200 Subject: [PATCH 1102/1812] removed a left-over debugging statement --- apps/opencs/view/render/worldspacewidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5d866fc6c5..834762a678 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -326,7 +326,6 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const for (int i=0; sMappingSettings[i]; ++i) if (key2==sMappingSettings[i]) { - std::cout<<"button :"< Date: Fri, 25 Sep 2015 14:18:08 +0200 Subject: [PATCH 1103/1812] scripts: recognize '+' also as a unary operator it fixes the armor sorter in "Blades safe house.esp" --- components/compiler/exprparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index b588b6196b..53b24eab69 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -650,8 +650,13 @@ namespace Compiler mOperators.push_back ('m'); mTokenLoc = loc; return true; + } else if (code ==Scanner::S_plus && mNextOperand) { + // Also unary, but +, just ignore it + mTokenLoc = loc; + return true; } + if (code==Scanner::S_open) { if (mNextOperand) From 2fff6b06cc604b436fe075232b2e11c5242385b0 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Thu, 24 Sep 2015 16:42:10 +0200 Subject: [PATCH 1104/1812] removed items by mods do not break cell loading like fortify intelligence potions removed by sris_alchemy which break the loading of the firewatch mages guild --- apps/openmw/mwworld/containerstore.cpp | 63 ++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8c6f7d2595..5a26f09f5b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -411,41 +411,48 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); + try { + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) - { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - - if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i 0 ? 1 : -1, true, levItem->mId); - return; + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + + if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) + { + for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + return; + } + else + { + std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); + if (id.empty()) + return; + addInitialItem(id, owner, count, false, levItem->mId); + } } else { - std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); - if (id.empty()) - return; - addInitialItem(id, owner, count, false, levItem->mId); - } - } - else - { - // A negative count indicates restocking items - // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks - if (!levItem.empty() && count < 0) - { - if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) - mLevelledItemMap[id] = 0; - mLevelledItemMap[id] += std::abs(count); - } - count = std::abs(count); + // A negative count indicates restocking items + // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks + if (!levItem.empty() && count < 0) + { + if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) + mLevelledItemMap[id] = 0; + mLevelledItemMap[id] += std::abs(count); + } + count = std::abs(count); - ref.getPtr().getCellRef().setOwner(owner); - addImp (ref.getPtr(), count); + ref.getPtr().getCellRef().setOwner(owner); + addImp (ref.getPtr(), count); + } } + catch (const std::exception& e) + { + std::cerr << "Error in MWWorld::ContainerStore::addInitialItem: " << e.what() << std::endl; + } + } void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) From 169d76b49b7b304b44170a6a042b627dd2c29e1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:20:20 +0200 Subject: [PATCH 1105/1812] Fix scrollbar step in count dialog --- files/mygui/openmw_count_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index e9a1cb2c80..27b62ebf03 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -13,6 +13,8 @@ + + From 8e69c80bf60456687491e975c92ab39eaf314cfd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:21:33 +0200 Subject: [PATCH 1106/1812] Add framenumber checks in various cull callbacks, so we don't update more than once per frame when multiple cameras are used --- components/nifosg/nifloader.cpp | 13 ++++++++++++- components/sceneutil/riggeometry.cpp | 11 +++++++---- components/sceneutil/riggeometry.hpp | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 54a02c9508..75a427c5a8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,6 +113,7 @@ namespace // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. + // Must be set as a cull callback. class BillboardCallback : public osg::NodeCallback { public: @@ -160,24 +161,34 @@ namespace struct UpdateMorphGeometry : public osg::Drawable::CullCallback { UpdateMorphGeometry() + : mLastFrameNumber(0) { } UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) : osg::Drawable::CullCallback(copy, copyop) + , mLastFrameNumber(0) { } META_Object(NifOsg, UpdateMorphGeometry) - virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + virtual bool cull(osg::NodeVisitor* nv, osg::Drawable * drw, osg::State *) const { osgAnimation::MorphGeometry* geom = static_cast(drw); if (!geom) return false; + + if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + return false; + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + geom->transformSoftwareMethod(); return false; } + + private: + mutable unsigned int mLastFrameNumber; }; // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2a67c6ce60..8eb08f546d 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -60,7 +60,7 @@ public: RigGeometry::RigGeometry() : mSkeleton(NULL) - , mFirstFrame(true) + , mLastFrameNumber(0) , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); @@ -72,7 +72,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) - , mFirstFrame(copy.mFirstFrame) + , mLastFrameNumber(0) , mBoundsFirstFrame(copy.mBoundsFirstFrame) { setSourceGeometry(copy.mSourceGeometry); @@ -206,9 +206,12 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - if (!mSkeleton->getActive() && !mFirstFrame) + if (!mSkeleton->getActive() && mLastFrameNumber != 0) return; - mFirstFrame = false; + + if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + return; + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); mSkeleton->updateBoneMatrices(nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index bd7c586c47..e51fc0cf69 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -64,7 +64,7 @@ namespace SceneUtil BoneSphereMap mBoneSphereMap; - bool mFirstFrame; + unsigned int mLastFrameNumber; bool mBoundsFirstFrame; bool initFromParentSkeleton(osg::NodeVisitor* nv); From b9c6a6862a328cc044793a5c8547ca9e67ec9406 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:49:58 +0200 Subject: [PATCH 1107/1812] Don't reset god mode, scripts enabled and sky enabled flags when loading a save game These flags aren't stored in the save file, so it makes no sense to reset them to their default each time a save game is loaded. Instead, reset on "new game". --- apps/openmw/mwworld/worldimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ff7a750a6..5857861366 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -204,6 +204,10 @@ namespace MWWorld mLevitationEnabled = true; mTeleportEnabled = true; + mGodMode = false; + mScriptsEnabled = true; + mSky = true; + // Rebuild player setupPlayer(); @@ -297,9 +301,6 @@ namespace MWWorld mDoorStates.clear(); - mGodMode = false; - mScriptsEnabled = true; - mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; From 387624e1580d4345dcbd3a3ae3a695de94bdd377 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 01:55:12 +0200 Subject: [PATCH 1108/1812] Add a threshold to AiFollow distance Idle animations can move the actor around slightly, which sometimes causes AiFollow to constantly toggle between "arrived" and "following" state even when the player isn't moving. Could be observed by summoning a bonelord. --- apps/openmw/mwmechanics/aifollow.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index cd67c60582..d9356da93f 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -20,8 +20,9 @@ namespace MWMechanics struct AiFollowStorage : AiTemporaryBase { float mTimer; + bool mMoving; - AiFollowStorage() : mTimer(0.f) {} + AiFollowStorage() : mTimer(0.f), mMoving(false) {} }; int AiFollow::mFollowIndexCounter = 0; @@ -64,10 +65,11 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); + AiFollowStorage& storage = state.get(); + // AiFollow requires the target to be in range and within sight for the initial activation if (!mActive) { - AiFollowStorage& storage = state.get(); storage.mTimer -= duration; if (storage.mTimer < 0) @@ -126,7 +128,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target destination from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; - if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < followDistance) //Stop when you get close + float dist = distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]); + const float threshold = 10; + + if (storage.mMoving) //Stop when you get close + storage.mMoving = (dist > followDistance); + else + storage.mMoving = (dist > followDistance + threshold); + + if(!storage.mMoving) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; @@ -141,9 +151,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte } //Check if you're far away - if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 450) + if(dist > 450) actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run - else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold + else if(dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk return false; From 899e35591c24c5cd90d88f680c8a5011b32ab79c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Sep 2015 02:08:23 +0200 Subject: [PATCH 1109/1812] Escape MyGUI markup codes in console output --- apps/openmw/mwgui/console.cpp | 10 +++++----- apps/openmw/mwgui/console.hpp | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 083dd32b0a..761f7d1642 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -170,25 +170,25 @@ namespace MWGui mCommandLine->setFontName(fntName); } - void Console::print(const std::string &msg) + void Console::print(const std::string &msg, const std::string& color) { - mHistory->addText(msg); + mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg)); } void Console::printOK(const std::string &msg) { - print("#FF00FF" + msg + "\n"); + print(msg + "\n", "#FF00FF"); } void Console::printError(const std::string &msg) { - print("#FF2222" + msg + "\n"); + print(msg + "\n", "#FF2222"); } void Console::execute (const std::string& command) { // Log the command - print("#FFFFFF> " + command + "\n"); + print("> " + command + "\n"); Compiler::Locals locals; Compiler::Output output (locals); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 09a05be487..98e46a5596 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -48,9 +48,8 @@ namespace MWGui void onResChange(int width, int height); - // Print a message to the console. Messages may contain color - // code, eg. "#FFFFFF this is white". - void print(const std::string &msg); + // Print a message to the console, in specified color. + void print(const std::string &msg, const std::string& color = "#FFFFFF"); // These are pre-colored versions that you should use. From ae54f34f25ce08a2abc5ee9a162292940d256c84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 11:30:35 +0200 Subject: [PATCH 1110/1812] removed a redundant else and made unary + work also in the console --- components/compiler/exprparser.cpp | 6 ++++-- components/compiler/lineparser.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 53b24eab69..c0375b4366 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -650,13 +650,15 @@ namespace Compiler mOperators.push_back ('m'); mTokenLoc = loc; return true; - } else if (code ==Scanner::S_plus && mNextOperand) { + } + + if (code ==Scanner::S_plus && mNextOperand) + { // Also unary, but +, just ignore it mTokenLoc = loc; return true; } - if (code==Scanner::S_open) { if (mNextOperand) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 032af7d650..c1622c3e04 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -555,7 +555,7 @@ namespace Compiler } if (mAllowExpression && mState==BeginState && - (code==Scanner::S_open || code==Scanner::S_minus)) + (code==Scanner::S_open || code==Scanner::S_minus || code==Scanner::S_plus)) { scanner.putbackSpecial (code, loc); parseExpression (scanner, loc); From 435e52306a0b1a7ef4cf7059bbc388b3262d2631 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 11:34:46 +0200 Subject: [PATCH 1111/1812] adjusted a workaround for names starting with digits that interfered with some numerical expressions written without spaces --- components/compiler/scanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index f25e69e399..3c5bb77475 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -175,7 +175,7 @@ namespace Compiler { value += c; } - else if (isStringCharacter (c)) + else if (c!='-' && isStringCharacter (c)) { error = true; value += c; From 748b13b45b5b08ac0184dd3cb8acd4ef30f5302a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:05:44 +0200 Subject: [PATCH 1112/1812] renamed ObjectHolder into ObjectTag --- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/object.hpp | 4 ++-- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f05e311f9d..c7485c8911 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -124,7 +124,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mOutline = new osgFX::Scribe; mOutline->addChild(mBaseNode); - mBaseNode->setUserData(new ObjectHolder(this)); + mBaseNode->setUserData(new ObjectTag(this)); parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9b37490699..1a1295b530 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -39,10 +39,10 @@ namespace CSVRender class Object; // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query - class ObjectHolder : public osg::Referenced + class ObjectTag : public osg::Referenced { public: - ObjectHolder(Object* obj) + ObjectTag (Object* obj) : mObject(obj) { } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 834762a678..378b5bea98 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -463,7 +463,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::Node* node = *it; - if (CSVRender::ObjectHolder* holder = dynamic_cast(node->getUserData())) + if (CSVRender::ObjectTag* holder = dynamic_cast(node->getUserData())) { // hit an Object, toggle its selection state CSVRender::Object* obj = holder->mObject; From 71247a018652cf5ac4894e1f242daccd971e41bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:18:18 +0200 Subject: [PATCH 1113/1812] inserted TagBase between ObjectTag and osg::Referenced --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/object.cpp | 5 +++++ apps/opencs/view/render/object.hpp | 17 ++++++++--------- apps/opencs/view/render/tagbase.cpp | 9 +++++++++ apps/opencs/view/render/tagbase.hpp | 22 ++++++++++++++++++++++ 5 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 apps/opencs/view/render/tagbase.cpp create mode 100644 apps/opencs/view/render/tagbase.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f9a73a09f8..cfa9384737 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage + lightingbright object cell terrainstorage tagbase ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c7485c8911..ac96cb2835 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -38,6 +38,11 @@ namespace } +CSVRender::ObjectTag::ObjectTag (Object* object) +: TagBase (Element_Reference), mObject (object) +{} + + void CSVRender::Object::clear() { } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 1a1295b530..0858a2edb2 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -8,8 +8,9 @@ #include #include -class QModelIndex; +#include "tagbase.hpp" +class QModelIndex; namespace osg { @@ -35,21 +36,19 @@ namespace CSMWorld namespace CSVRender { - class Object; // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query - class ObjectTag : public osg::Referenced + class ObjectTag : public TagBase { - public: - ObjectTag (Object* obj) - : mObject(obj) - { - } + public: - Object* mObject; + ObjectTag (Object* object); + + Object* mObject; }; + class Object { const CSMWorld::Data& mData; diff --git a/apps/opencs/view/render/tagbase.cpp b/apps/opencs/view/render/tagbase.cpp new file mode 100644 index 0000000000..af9a376243 --- /dev/null +++ b/apps/opencs/view/render/tagbase.cpp @@ -0,0 +1,9 @@ + +#include "tagbase.hpp" + +CSVRender::TagBase::TagBase (Elements element) : mElement (element) {} + +CSVRender::Elements CSVRender::TagBase::getElement() const +{ + return mElement; +} diff --git a/apps/opencs/view/render/tagbase.hpp b/apps/opencs/view/render/tagbase.hpp new file mode 100644 index 0000000000..874b856c63 --- /dev/null +++ b/apps/opencs/view/render/tagbase.hpp @@ -0,0 +1,22 @@ +#ifndef OPENCS_VIEW_TAGBASE_H +#define OPENCS_VIEW_TAGBASE_H + +#include + +#include "elements.hpp" + +namespace CSVRender +{ + class TagBase : public osg::Referenced + { + Elements mElement; + + public: + + TagBase (Elements element); + + Elements getElement() const; + }; +} + +#endif From 72bb33c2c479ef82eebe5c07450c0f4388848891 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 12:24:41 +0200 Subject: [PATCH 1114/1812] filter mouse interaction by interaction mask --- apps/opencs/view/render/worldspacewidget.cpp | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 378b5bea98..246f6a4bf5 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -463,18 +463,27 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::Node* node = *it; - if (CSVRender::ObjectTag* holder = dynamic_cast(node->getUserData())) + if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) { - // hit an Object, toggle its selection state - CSVRender::Object* obj = holder->mObject; - obj->setSelected(!obj->getSelected()); + if (!(tag->getElement() && mInteractionMask)) + break; // not interested -> continue looking + + // hit something marked with a tag + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag)) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } + return; } } +// ignoring terrain for now // must be terrain, report coordinates - std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; - return; +// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; +// return; } } From 3844c94975d18f7b98a3cd19f7e57ec310df636c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 17:39:55 +0200 Subject: [PATCH 1115/1812] bit masking fix --- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 246f6a4bf5..42f81eea45 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -465,7 +465,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) osg::Node* node = *it; if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) { - if (!(tag->getElement() && mInteractionMask)) + if (!(tag->getElement() & mInteractionMask)) break; // not interested -> continue looking // hit something marked with a tag From 501ae6372d60a6d6932f5ed72719da6196fcc665 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 17:51:41 +0200 Subject: [PATCH 1116/1812] factored out mouse picking into a separate function --- apps/opencs/view/render/worldspacewidget.cpp | 97 +++++++++++--------- apps/opencs/view/render/worldspacewidget.hpp | 4 + 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 42f81eea45..15978e0e18 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -347,6 +347,53 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const return false; } +osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseEvent *event) +{ + // (0,0) is considered the lower left corner of an OpenGL window + int x = event->x(); + int y = height() - event->y(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(getInteractionMask() << 1); + + mView->getCamera()->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) + { + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + + // reject back-facing polygons + osg::Vec3f normal = intersection.getWorldIntersectNormal(); + normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); + if (normal.z() < 0) + continue; + + for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::Node* node = *it; + if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) + { + if (!(tag->getElement() & mInteractionMask)) + break; // not interested -> continue looking + + return tag; + } + } + +// ignoring terrain for now + // must be terrain, report coordinates +// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; +// return; + } + + return osg::ref_ptr(); +} + void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -436,54 +483,16 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) if (event->button() != Qt::RightButton) return; - // (0,0) is considered the lower left corner of an OpenGL window - int x = event->x(); - int y = height() - event->y(); + osg::ref_ptr tag = mousePick (event); - osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); - - intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); - osgUtil::IntersectionVisitor visitor(intersector); - - visitor.setTraversalMask(getInteractionMask() << 1); - - mView->getCamera()->accept(visitor); - - for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); - it != intersector->getIntersections().end(); ++it) + if (tag) { - osgUtil::LineSegmentIntersector::Intersection intersection = *it; - - // reject back-facing polygons - osg::Vec3f normal = intersection.getWorldIntersectNormal(); - normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); - if (normal.z() < 0) - continue; - - for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - osg::Node* node = *it; - if (CSVRender::TagBase* tag = dynamic_cast(node->getUserData())) - { - if (!(tag->getElement() & mInteractionMask)) - break; // not interested -> continue looking - - // hit something marked with a tag - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag)) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); - } - - return; - } + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); } - -// ignoring terrain for now - // must be terrain, report coordinates -// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; -// return; } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 23f672fbdb..90a85006f6 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -25,6 +25,8 @@ namespace CSVWidget namespace CSVRender { + class TagBase; + class WorldspaceWidget : public SceneWidget { Q_OBJECT @@ -126,6 +128,8 @@ namespace CSVRender /// \return Is \a key a button mapping setting? (ignored otherwise) bool storeMappingSetting (const QString& key, const QString& value); + osg::ref_ptr mousePick (QMouseEvent *event); + virtual std::string getStartupInstruction() = 0; private slots: From 7bbc475bda71ea8d87ca63933c3d8c0c21dc2841 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 26 Sep 2015 18:01:49 +0200 Subject: [PATCH 1117/1812] apply button mapping --- apps/opencs/view/render/worldspacewidget.cpp | 39 +++++++++++++++----- apps/opencs/view/render/worldspacewidget.hpp | 2 + 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 15978e0e18..5b52191849 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -394,6 +395,20 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE return osg::ref_ptr(); } +std::string CSVRender::WorldspaceWidget::mapButton (QMouseEvent *event) +{ + std::pair phyiscal ( + event->button(), QApplication::keyboardModifiers() & Qt::ControlModifier); + + std::map, std::string>::const_iterator iter = + mButtonMapping.find (phyiscal); + + if (iter!=mButtonMapping.end()) + return iter->second; + + return ""; +} + void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -480,18 +495,24 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if (event->button() != Qt::RightButton) - return; + std::string button = mapButton (event); - osg::ref_ptr tag = mousePick (event); - - if (tag) + if (button=="p-navi" || button=="s-navi") { - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + + } + else if (button=="p-edit" || button=="s-edit" || button=="select") + { + osg::ref_ptr tag = mousePick (event); + + if (tag) { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } } } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 90a85006f6..ed5c5bcc83 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -130,6 +130,8 @@ namespace CSVRender osg::ref_ptr mousePick (QMouseEvent *event); + std::string mapButton (QMouseEvent *event); + virtual std::string getStartupInstruction() = 0; private slots: From 5d9863aec12429aa086d54012da7638a4eb663bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 11:34:14 +0200 Subject: [PATCH 1118/1812] removed a redundant check --- apps/opencs/view/render/worldspacewidget.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5b52191849..70def97b9b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -378,12 +378,7 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE { osg::Node* node = *it; if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) - { - if (!(tag->getElement() & mInteractionMask)) - break; // not interested -> continue looking - return tag; - } } // ignoring terrain for now From 9bf27c7e371e4b1fdf01b356210a7bb9d02d58d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 14:38:12 +0200 Subject: [PATCH 1119/1812] moved edit mode handling from SceneSubView to WorldspaceWidget --- apps/opencs/view/render/worldspacewidget.cpp | 23 ++++++++++++++++---- apps/opencs/view/render/worldspacewidget.hpp | 5 +++++ apps/opencs/view/world/scenesubview.cpp | 18 +++------------ apps/opencs/view/world/scenesubview.hpp | 4 ---- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 70def97b9b..be4d32bb5a 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -42,7 +42,7 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0) + mInteractionMask (0), mEditMode (0), mLocked (false) { setAcceptDrops(true); @@ -199,11 +199,14 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector ( CSVWidget::SceneToolbar *parent) { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Edit Mode"); + mEditMode = new CSVWidget::SceneToolMode (parent, "Edit Mode"); - addEditModeSelectorButtons (tool); + addEditModeSelectorButtons (mEditMode); - return tool; + connect (mEditMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (editModeChanged (const std::string&))); + + return mEditMode; } CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType ( @@ -279,6 +282,13 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const { if (!value.isEmpty() && storeMappingSetting (name, value.first())) return; + + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); +} + +void CSVRender::WorldspaceWidget::setEditLock (bool locked) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); } void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( @@ -468,6 +478,11 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde } } +void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) +{ + dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); +} + void CSVRender::WorldspaceWidget::elementSelectionChanged() { setVisibilityMask (getVisibilityMask()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ed5c5bcc83..272987a054 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -36,6 +36,8 @@ namespace CSVRender CSMDoc::Document& mDocument; unsigned int mInteractionMask; std::map, std::string> mButtonMapping; + CSVWidget::SceneToolMode *mEditMode; + bool mLocked; public: @@ -100,6 +102,8 @@ namespace CSVRender virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void setEditLock (bool locked); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); @@ -158,6 +162,7 @@ namespace CSVRender void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end); + void editModeChanged (const std::string& id); protected slots: diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 9679099697..753d791c0f 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -27,8 +27,7 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL), - mEditMode (0), mLocked (false) +: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) { QVBoxLayout *layout = new QVBoxLayout; @@ -123,16 +122,14 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); - mEditMode = widget->makeEditModeSelector (toolbar); - toolbar->addTool (mEditMode); + toolbar->addTool (widget->makeEditModeSelector (toolbar)); return toolbar; } void CSVWorld::SceneSubView::setEditLock (bool locked) { - mLocked = locked; - dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); + mScene->setEditLock (locked); } void CSVWorld::SceneSubView::setStatusBar (bool show) @@ -153,7 +150,6 @@ std::string CSVWorld::SceneSubView::getTitle() const void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) { mScene->updateUserSetting (name, value); - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); CSVDoc::SubView::updateUserSetting (name, value); } @@ -259,12 +255,4 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); - - connect (mEditMode, SIGNAL (modeChanged (const std::string&)), - this, SLOT (editModeChanged (const std::string&))); -} - -void CSVWorld::SceneSubView::editModeChanged (const std::string& id) -{ - dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); } diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index f59fee37f6..2458d58f42 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -46,8 +46,6 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSVWidget::SceneToolbar* mToolbar; std::string mTitle; - CSVWidget::SceneToolMode *mEditMode; - bool mLocked; public: @@ -86,8 +84,6 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); - - void editModeChanged (const std::string& id); }; } From 981a8a2cc2754fe5f9c9abc5e1b42b86f091dc3d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 27 Sep 2015 16:18:22 +0200 Subject: [PATCH 1120/1812] delegated editing and selection functions to mode objects --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/editmode.cpp | 6 ++++ apps/opencs/view/render/editmode.hpp | 12 +++++++ apps/opencs/view/render/instancemode.cpp | 35 ++++++++++++++++++++ apps/opencs/view/render/instancemode.hpp | 24 ++++++++++++++ apps/opencs/view/render/worldspacewidget.cpp | 22 ++++++------ 6 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/view/render/instancemode.cpp create mode 100644 apps/opencs/view/render/instancemode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cfa9384737..2ed55218ad 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -85,7 +85,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget editmode + previewwidget editmode instancemode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index c3aad3f7a1..2240318b62 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -26,3 +26,9 @@ void CSVRender::EditMode::setEditLock (bool locked) { } + +void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 1212cd2854..c006695349 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -1,11 +1,14 @@ #ifndef CSV_RENDER_EDITMODE_H #define CSV_RENDER_EDITMODE_H +#include + #include "../widget/modebutton.hpp" namespace CSVRender { class WorldspaceWidget; + class TagBase; class EditMode : public CSVWidget::ModeButton { @@ -28,6 +31,15 @@ namespace CSVRender /// Default-implementation: Ignored. virtual void setEditLock (bool locked); + + /// Default-implementation: Ignored. + virtual void primaryEditPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void secondaryEditPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void selectPressed (osg::ref_ptr tag); }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp new file mode 100644 index 0000000000..ccff8c7c5c --- /dev/null +++ b/apps/opencs/view/render/instancemode.cpp @@ -0,0 +1,35 @@ + +#include "instancemode.hpp" + +#include "elements.hpp" +#include "object.hpp" + +CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) +: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", + parent) +{ + +} + +void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) +{ + +} + +void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) +{ + +} + +void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) +{ + if (tag) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + } + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp new file mode 100644 index 0000000000..6071aedf03 --- /dev/null +++ b/apps/opencs/view/render/instancemode.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_RENDER_INSTANCEMODE_H +#define CSV_RENDER_INSTANCEMODE_H + +#include "editmode.hpp" + +namespace CSVRender +{ + class InstanceMode : public EditMode + { + Q_OBJECT + + public: + + InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + + virtual void primaryEditPressed (osg::ref_ptr tag); + + virtual void secondaryEditPressed (osg::ref_ptr tag); + + virtual void selectPressed (osg::ref_ptr tag); + }; +} + +#endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index be4d32bb5a..1c1dc4d6b6 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -28,6 +28,7 @@ #include "object.hpp" #include "elements.hpp" #include "editmode.hpp" +#include "instancemode.hpp" namespace { @@ -302,9 +303,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) { /// \todo replace EditMode with suitable subclasses - tool->addButton ( - new EditMode (this, QIcon (":placeholder"), Element_Reference, "Instance editing"), - "object"); + tool->addButton (new InstanceMode (this, tool), "object"); tool->addButton ( new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"), "pathgrid"); @@ -515,15 +514,14 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - if (tag) - { - if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); - } - } + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); } } From 319e3f24a3d23e158adbc3e46f0f80dc55e5206f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 13:48:04 +0200 Subject: [PATCH 1121/1812] on edit mode change clear selection of elements that are not affected by current edit mode (only support for instance for now since we do not have selection for other elements yet) --- apps/opencs/view/render/cell.cpp | 21 +++++++++++++++++++ apps/opencs/view/render/cell.hpp | 11 ++++++++++ apps/opencs/view/render/editmode.cpp | 1 + .../view/render/pagedworldspacewidget.cpp | 7 +++++++ .../view/render/pagedworldspacewidget.hpp | 3 +++ .../view/render/unpagedworldspacewidget.cpp | 5 +++++ .../view/render/unpagedworldspacewidget.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.hpp | 10 ++++++--- 8 files changed, 58 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 28a48cfbdc..c4f7445103 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -211,3 +211,24 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int return addObjects (start, end); } + +void CSVRender::Cell::setSelection (int elementMask, Selection mode) +{ + if (elementMask & Element_Reference) + { + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + { + bool selected = false; + + switch (mode) + { + case Selection_Clear: selected = false; break; + case Selection_All: selected = true; break; + case Selection_Invert: selected = !iter->second->getSelected(); break; + } + + iter->second->setSelected (selected); + } + } +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f4272b8879..d26a2d9af7 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -49,6 +49,15 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + public: + + enum Selection + { + Selection_Clear, + Selection_All, + Selection_Invert + }; + public: Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); @@ -75,6 +84,8 @@ namespace CSVRender /// \return Did this call result in a modification of the visual representation of /// this cell? bool referenceAdded (const QModelIndex& parent, int start, int end); + + void setSelection (int elementMask, Selection mode); }; } diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 2240318b62..e1f69a63d3 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -15,6 +15,7 @@ unsigned int CSVRender::EditMode::getInteractionMask() const void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); + mWorldspaceWidget->clearSelection (~mMask); } void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b0c1e74a9a..543f3788a7 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -314,6 +314,13 @@ unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection(); } +void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) +{ + for (std::map::iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->setSelection (elementMask, Cell::Selection_Clear); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 64a0bccd1a..d52efd90e4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -79,6 +79,9 @@ namespace CSVRender virtual unsigned int getVisibilityMask() const; + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 3e1733c819..989c976ff1 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -102,6 +102,11 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorsetSelection (elementMask, Cell::Selection_Clear); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index d01c3e7667..9e6fa97f43 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -43,6 +43,9 @@ namespace CSVRender virtual bool handleDrop (const std::vector& data, DropType type); + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask); + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 272987a054..ffdcf3bc3d 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,10 +5,11 @@ #include -#include "scenewidget.hpp" +#include "../../model/doc/document.hpp" +#include "../../model/world/tablemimedata.hpp" -#include -#include +#include "scenewidget.hpp" +#include "elements.hpp" namespace CSMWorld { @@ -104,6 +105,9 @@ namespace CSVRender virtual void setEditLock (bool locked); + /// \param elementMask Elements to be affected by the clear operation + virtual void clearSelection (int elementMask) = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); From f28fa9fc16ec1477b1de18bf078a5d16af2b34aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 13:53:47 +0200 Subject: [PATCH 1122/1812] clear instance selection on select click on nothing/something that isn't an instance --- apps/opencs/view/render/editmode.cpp | 5 +++++ apps/opencs/view/render/editmode.hpp | 4 ++++ apps/opencs/view/render/instancemode.cpp | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index e1f69a63d3..816067107f 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -2,6 +2,11 @@ #include "worldspacewidget.hpp" +CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget() +{ + return *mWorldspaceWidget; +} + CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask, const QString& tooltip, QWidget *parent) : ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask) diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c006695349..fa2beedd89 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -17,6 +17,10 @@ namespace CSVRender WorldspaceWidget *mWorldspaceWidget; unsigned int mMask; + protected: + + WorldspaceWidget& getWorldspaceWidget(); + public: EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask, diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ccff8c7c5c..2e8f8cda26 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -3,6 +3,7 @@ #include "elements.hpp" #include "object.hpp" +#include "worldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", @@ -30,6 +31,9 @@ void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) // hit an Object, toggle its selection state CSVRender::Object* object = objectTag->mObject; object->setSelected (!object->getSelected()); + return; } } + + getWorldspaceWidget().clearSelection (Element_Reference); } From 2cb106f6adfe5f8f7f94079077de0d43f41f8a44 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 16:06:55 +0200 Subject: [PATCH 1123/1812] added missing flagAsModified calls --- apps/opencs/view/render/pagedworldspacewidget.cpp | 2 ++ apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 543f3788a7..7403113b37 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -319,6 +319,8 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) for (std::map::iterator iter = mCells.begin(); iter!=mCells.end(); ++iter) iter->second->setSelection (elementMask, Cell::Selection_Clear); + + flagAsModified(); } CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 989c976ff1..68f068daca 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -105,6 +105,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorsetSelection (elementMask, Cell::Selection_Clear); + flagAsModified(); } void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, From 8e87b48866e66c1546c7d7f7914f9ab4f7fd015e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Sep 2015 16:07:14 +0200 Subject: [PATCH 1124/1812] handle context-sensitive select mode in instance editing --- apps/opencs/view/render/instancemode.cpp | 23 ++++++++++++++++++++--- apps/opencs/view/render/instancemode.hpp | 6 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 2e8f8cda26..333d916565 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,25 +1,42 @@ #include "instancemode.hpp" +#include "../../model/settings/usersettings.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent) + parent), mContextSelect (false) { } +void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) +{ + EditMode::activate (toolbar); + + mContextSelect = CSMSettings::UserSettings::instance().setting ("scene-input/context-select")=="true"; +} + +void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStringList& value) +{ + if (name=="scene-input/context-select") + mContextSelect = value.at (0)=="true"; +} + void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { - + if (mContextSelect) + selectPressed (tag); } void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) { - + if (mContextSelect) + selectPressed (tag); } void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 6071aedf03..cc4fd54349 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -9,10 +9,16 @@ namespace CSVRender { Q_OBJECT + bool mContextSelect; + public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); + virtual void activate (CSVWidget::SceneToolbar *toolbar); + + virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); From 3f27c856300671083123d3027cf7b6299bc01438 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 10:46:03 +1000 Subject: [PATCH 1125/1812] Added StartScriptCreator class with redefined getErrors method. --- apps/opencs/view/world/startscriptcreator.cpp | 26 +++++++++++++++++++ apps/opencs/view/world/startscriptcreator.hpp | 25 ++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 apps/opencs/view/world/startscriptcreator.cpp create mode 100644 apps/opencs/view/world/startscriptcreator.hpp diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp new file mode 100644 index 0000000000..5812cd9312 --- /dev/null +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -0,0 +1,26 @@ +#include "startscriptcreator.hpp" + +StartScriptCreator::StartScriptCreator() +{ + +} + + +CSVWORLD::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): + GenericCreator (data, undoStack, id, true) +{} + +std::string CSVWORLD::StartScriptCreator::getErrors() const +{ + std::string errors; + + errors = getIdValidatorResult(); + if (errors.length() > 0) + return errors; + else if (getData().getScripts().searchId(getId()) == -1) + errors = "Script ID not found"; + else if (getData().getStartScripts().searchId(getId()) > -1 ) + errors = "Script with this ID already registered as Start Script"; + + return errors; +} diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp new file mode 100644 index 0000000000..4c91ad96a2 --- /dev/null +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -0,0 +1,25 @@ +#ifndef STARTSCRIPTCREATOR_HPP +#define STARTSCRIPTCREATOR_HPP + +#include "genericcreator.hpp" + +namespace CSVWORLD { + + class StartScriptCreator : public GenericCreator + { + Q_OBJECT + + public: + StartScriptCreator(CSMWorld::Data& data, QUndoStack& undoStack, + const CSMWorld::UniversalId& id, bool relaxedIdRules = false); + + virtual std::string getErrors() const; + ///< Return formatted error descriptions for the current state of the creator. if an empty + /// string is returned, there is no error. + }; + +} + + + +#endif // STARTSCRIPTCREATOR_HPP From e672880f644066716452d363b61eff1c56010b0f Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 22:43:20 +1000 Subject: [PATCH 1126/1812] Fix namespace, add file to CMakeLists.txt --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/startscriptcreator.cpp | 10 ++-------- apps/opencs/view/world/startscriptcreator.hpp | 4 ++-- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f9a73a09f8..c428cd27a9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -67,7 +67,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator - cellcreator referenceablecreator referencecreator scenesubview + cellcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator ) diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 5812cd9312..69b1b3ff12 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -1,16 +1,10 @@ #include "startscriptcreator.hpp" -StartScriptCreator::StartScriptCreator() -{ - -} - - -CSVWORLD::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): +CSVWorld::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules): GenericCreator (data, undoStack, id, true) {} -std::string CSVWORLD::StartScriptCreator::getErrors() const +std::string CSVWorld::StartScriptCreator::getErrors() const { std::string errors; diff --git a/apps/opencs/view/world/startscriptcreator.hpp b/apps/opencs/view/world/startscriptcreator.hpp index 4c91ad96a2..07fe8ff3d3 100644 --- a/apps/opencs/view/world/startscriptcreator.hpp +++ b/apps/opencs/view/world/startscriptcreator.hpp @@ -3,7 +3,7 @@ #include "genericcreator.hpp" -namespace CSVWORLD { +namespace CSVWorld { class StartScriptCreator : public GenericCreator { @@ -16,7 +16,7 @@ namespace CSVWORLD { virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. - }; + }; } From 903cd3322b2a24e4d0a757ede8e429583f34f2b4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 22:44:25 +1000 Subject: [PATCH 1127/1812] add getIdValidatorResult method to GenericCreator, for use in subclass StartScriptCreator --- apps/opencs/view/world/genericcreator.cpp | 10 ++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 8ed52bf803..df77399417 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -47,6 +47,16 @@ std::string CSVWorld::GenericCreator::getId() const return mId->text().toUtf8().constData(); } +std::string CSVWorld::GenericCreator::getIdValidatorResult() const +{ + std::string errors; + + if (!mId->hasAcceptableInput()) + errors = mValidator->getError(); + + return errors; +} + void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {} void CSVWorld::GenericCreator::pushCommand (std::auto_ptr command, diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 471d0622eb..f63c451092 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -60,6 +60,8 @@ namespace CSVWorld virtual std::string getId() const; + virtual std::string getIdValidatorResult() const; + /// Allow subclasses to add additional data to \a command. virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const; From ecce3a197550cd8b689e7d2bf697461325a7c6b9 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 29 Sep 2015 23:52:35 +1000 Subject: [PATCH 1128/1812] Add StartScriptCreator to a factory manager. --- apps/opencs/view/world/subviews.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 299ac6ebec..88375caafc 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -10,6 +10,7 @@ #include "cellcreator.hpp" #include "referenceablecreator.hpp" #include "referencecreator.hpp" +#include "startscriptcreator.hpp" #include "scenesubview.hpp" #include "dialoguecreator.hpp" #include "infocreator.hpp" @@ -42,7 +43,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_Pathgrids, - CSMWorld::UniversalId::Type_StartScripts, CSMWorld::UniversalId::Type_None // end marker }; @@ -51,6 +51,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_StartScripts, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Cells, new CSVDoc::SubViewFactoryWithCreator >); @@ -123,7 +126,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_Pathgrid, - CSMWorld::UniversalId::Type_StartScript, CSMWorld::UniversalId::Type_None // end marker }; @@ -133,6 +135,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_StartScript, + new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_Skill, new CSVDoc::SubViewFactoryWithCreator (false)); From 64902bf22112d0b44464f7657b12db86627cdd38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 30 Sep 2015 09:44:05 +0200 Subject: [PATCH 1129/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8e9d35cf23..e968d1d01a 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -19,6 +19,7 @@ Programmers Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) + artemutin Arthur Moore (EmperorArthur) athile Bret Curtis (psi29a) From 0a5bfb2107ddf46465ce74902470dc7056eb279b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 12:46:01 +0200 Subject: [PATCH 1130/1812] added framework for drag operations --- apps/opencs/view/render/editmode.cpp | 21 ++++++ apps/opencs/view/render/editmode.hpp | 27 +++++++ apps/opencs/view/render/worldspacewidget.cpp | 75 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 4 ++ 4 files changed, 116 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 816067107f..e1ab619cdd 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -38,3 +38,24 @@ void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} + +bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) +{ + return false; +} + +void CSVRender::EditMode::drag (int diffX, int diffY) {} + +void CSVRender::EditMode::dragCompleted() {} + +void CSVRender::EditMode::dragAborted() {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index fa2beedd89..361ffc5ed2 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -44,6 +44,33 @@ namespace CSVRender /// Default-implementation: Ignored. virtual void selectPressed (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool primaryEditStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool secondaryEditStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool selectStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignored + virtual void drag (int diffX, int diffY); + + /// Default-implementation: ignored + virtual void dragCompleted(); + + /// Default-implementation: ignored + /// + /// \note dragAborted will not be called, if the drag is aborted via changing + /// editing mode + virtual void dragAborted(); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1c1dc4d6b6..25ee56a050 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -43,7 +43,7 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false) + mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false) { setAcceptDrops(true); @@ -480,6 +480,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); + mDragging = false; } void CSVRender::WorldspaceWidget::elementSelectionChanged() @@ -495,10 +496,45 @@ void CSVRender::WorldspaceWidget::updateOverlay() void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + if (!mDragging) { - //mMouse->mouseMoveEvent(event); + if (mDragMode=="p-navi" || mDragMode=="s-navi") + { + + } + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + { + osg::ref_ptr tag = mousePick (event); + + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (mDragMode=="p-edit") + mDragging = editMode.primaryEditStartDrag (tag); + else if (mDragMode=="s-edit") + mDragging = editMode.secondaryEditStartDrag (tag); + else if (mDragMode=="select") + mDragging = editMode.selectStartDrag (tag); + + if (mDragging) + { + mDragX = event->posF().x(); + mDragY = height() - event->posF().y(); + } + } } + else + { + int diffX = event->x() - mDragX; + int diffY = (height() - event->y()) - mDragY; + + mDragX = event->x(); + mDragY = height() - event->y(); + + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.drag (diffX, diffY); + } + RenderWidget::mouseMoveEvent(event); } @@ -506,6 +542,9 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { std::string button = mapButton (event); + if (!mDragging) + mDragMode = button; + if (button=="p-navi" || button=="s-navi") { @@ -527,17 +566,25 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { - if(event->button() == Qt::RightButton) + if (mDragging) { - /* - if(!getViewport()) + std::string button = mapButton (event); + + if (mDragMode=="p-navi" || mDragMode=="s-navi") { - SceneWidget::mouseReleaseEvent(event); - return; + + } + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragCompleted(); + mDragging = false; } - */ - //mMouse->mouseReleaseEvent(event); } + + mDragMode.clear(); + RenderWidget::mouseReleaseEvent(event); } @@ -560,7 +607,13 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { - //mMouse->cancelDrag(); + if (mDragging) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragAborted(); + mDragging = false; + } } else RenderWidget::keyPressEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ffdcf3bc3d..f51ce047e7 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -39,6 +39,10 @@ namespace CSVRender std::map, std::string> mButtonMapping; CSVWidget::SceneToolMode *mEditMode; bool mLocked; + std::string mDragMode; + bool mDragging; + int mDragX; + int mDragY; public: From 1d4f8b2595b6f7d49d2dbc95590f5bdd2486dd68 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 13:19:48 +0200 Subject: [PATCH 1131/1812] send mouse wheel input to active EditMode during drag operations --- apps/opencs/view/render/editmode.cpp | 2 ++ apps/opencs/view/render/editmode.hpp | 3 +++ apps/opencs/view/render/scenewidget.cpp | 2 ++ apps/opencs/view/render/worldspacewidget.cpp | 10 ++++++++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index e1ab619cdd..cc76e33623 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -59,3 +59,5 @@ void CSVRender::EditMode::drag (int diffX, int diffY) {} void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} + +void CSVRender::EditMode::dragWheel (int diff) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 361ffc5ed2..0a4bdf9b80 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -71,6 +71,9 @@ namespace CSVRender /// \note dragAborted will not be called, if the drag is aborted via changing /// editing mode virtual void dragAborted(); + + /// Default-implementation: ignored + virtual void dragWheel (int diff); }; } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index fb3bcb3c3d..76b3db348d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -110,6 +110,8 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event) keyPressEvent(static_cast(event)); if (event->type() == QEvent::KeyRelease) keyReleaseEvent(static_cast(event)); + if (event->type() == QEvent::Wheel) + wheelEvent(static_cast(event)); // Always pass the event on to GLWidget, i.e. to OSG event queue return QObject::eventFilter(obj, event); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 25ee56a050..3971f76fa0 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -599,8 +599,14 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - //if(!mMouse->wheelEvent(event)) - RenderWidget::wheelEvent(event); + if (mDragging) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragWheel (event->delta()); + } + + RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) From 323f8bb29f04b7b48f0cbe4e5a04ac6a3f880e6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 1 Oct 2015 13:42:21 +0200 Subject: [PATCH 1132/1812] sensitivity settings --- apps/opencs/model/settings/usersettings.cpp | 15 +++++++++++ apps/opencs/view/render/editmode.cpp | 4 +-- apps/opencs/view/render/editmode.hpp | 4 +-- apps/opencs/view/render/worldspacewidget.cpp | 27 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 3 +++ 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 5cc60c3184..3e5ab24d13 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -405,6 +405,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); contextSensitive->setDefaultValue ("false"); + + Setting *dragMouseSensitivity = createSetting (Type_DoubleSpinBox, "drag-factor", + "Mouse sensitivity during drag operations"); + dragMouseSensitivity->setDefaultValue (1.0); + dragMouseSensitivity->setRange (0.001, 100.0); + + Setting *dragWheelSensitivity = createSetting (Type_DoubleSpinBox, "drag-wheel-factor", + "Mouse wheel sensitivity during drag operations"); + dragWheelSensitivity->setDefaultValue (1.0); + dragWheelSensitivity->setRange (0.001, 100.0); + + Setting *dragShiftFactor = createSetting (Type_DoubleSpinBox, "drag-shift-factor", + "Acceleration factor during drag operations while holding down shift"); + dragShiftFactor->setDefaultValue (4.0); + dragShiftFactor->setRange (0.001, 100.0); } { diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index cc76e33623..c35b4f3549 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -54,10 +54,10 @@ bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) return false; } -void CSVRender::EditMode::drag (int diffX, int diffY) {} +void CSVRender::EditMode::drag (int diffX, int diffY, double speedFactor) {} void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} -void CSVRender::EditMode::dragWheel (int diff) {} +void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 0a4bdf9b80..77676d6a3f 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -61,7 +61,7 @@ namespace CSVRender virtual bool selectStartDrag (osg::ref_ptr tag); /// Default-implementation: ignored - virtual void drag (int diffX, int diffY); + virtual void drag (int diffX, int diffY, double speedFactor); /// Default-implementation: ignored virtual void dragCompleted(); @@ -73,7 +73,7 @@ namespace CSVRender virtual void dragAborted(); /// Default-implementation: ignored - virtual void dragWheel (int diff); + virtual void dragWheel (int diff, double speedFactor); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3971f76fa0..2789cd9d5d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -81,6 +81,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg key += sMappingSettings[i]; storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); } + + mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); + mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); + mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -284,7 +288,14 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const if (!value.isEmpty() && storeMappingSetting (name, value.first())) return; - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); + if (name=="scene-input/drag-factor") + mDragFactor = value.at (0).toDouble(); + else if (name=="scene-input/drag-wheel-factor") + mDragWheelFactor = value.at (0).toDouble(); + else if (name=="scene-input/drag-shift-factor") + mDragShiftFactor = value.at (0).toDouble(); + else + dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); } void CSVRender::WorldspaceWidget::setEditLock (bool locked) @@ -530,9 +541,14 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragX = event->x(); mDragY = height() - event->y(); + double factor = mDragFactor; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + factor *= mDragShiftFactor; + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - editMode.drag (diffX, diffY); + editMode.drag (diffX, diffY, factor); } RenderWidget::mouseMoveEvent(event); @@ -601,9 +617,14 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { if (mDragging) { + double factor = mDragWheelFactor; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + factor *= mDragShiftFactor; + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - editMode.dragWheel (event->delta()); + editMode.dragWheel (event->delta(), factor); } RenderWidget::wheelEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f51ce047e7..338ebcc971 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -43,6 +43,9 @@ namespace CSVRender bool mDragging; int mDragX; int mDragY; + double mDragFactor; + double mDragWheelFactor; + double mDragShiftFactor; public: From 4b0fa370e38f6791c5f48df9caf3d77719b62ad8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 2 Oct 2015 15:06:42 +0200 Subject: [PATCH 1133/1812] made WorldspaceWidget::getDocument public (EditModes will need the document later) --- apps/opencs/view/render/worldspacewidget.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 338ebcc971..f5e7970b67 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -112,6 +112,8 @@ namespace CSVRender virtual void setEditLock (bool locked); + CSMDoc::Document& getDocument(); + /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; @@ -121,8 +123,6 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - CSMDoc::Document& getDocument(); - virtual void updateOverlay(); virtual void mouseMoveEvent (QMouseEvent *event); From 0a8e2c0b215af1287f1d250a7f48fa2852e75610 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Sat, 3 Oct 2015 00:07:08 -0500 Subject: [PATCH 1134/1812] Fix building OpenCS with Qt 5. --- apps/opencs/view/render/worldspacewidget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2789cd9d5d..75dd800ebc 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -528,8 +528,13 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) if (mDragging) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + mDragX = event->localPos().x(); + mDragY = height() - event->localPos().y(); +#else mDragX = event->posF().x(); mDragY = height() - event->posF().y(); +#endif } } } From b4132faaea34d1d153735c80e84dcea715523b34 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 4 Oct 2015 16:27:05 +0200 Subject: [PATCH 1135/1812] Update editmode.cpp Fixes builds on Windows --- apps/opencs/view/render/editmode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index c35b4f3549..4235faf768 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -1,5 +1,6 @@ #include "editmode.hpp" +#include "tagbase.hpp" #include "worldspacewidget.hpp" CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget() From ec4fff588dd4c1222a1435e348a7e499482bdc92 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Mon, 5 Oct 2015 23:07:13 +1000 Subject: [PATCH 1136/1812] uncomment updateActor call in buildPlayer for magicka recalc --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 12927101d8..761c5ece9e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -295,7 +295,7 @@ namespace MWMechanics creatureStats.getSpells().add(*it); // forced update and current value adjustments - //mActors.updateActor (ptr, 0); + mActors.updateActor (ptr, 0); for (int i=0; i<3; ++i) { From 77cb438714963b70cee791ec5d592cf1c5fda2fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Oct 2015 15:41:07 +0200 Subject: [PATCH 1137/1812] Fix potential case smashing issue --- apps/openmw/mwmechanics/spells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 6d7673a591..330d78a201 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -312,7 +312,7 @@ namespace MWMechanics bool Spells::canUsePower(const std::string &power) const { - std::map::const_iterator it = mUsedPowers.find(power); + std::map::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power)); if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) return true; else @@ -321,7 +321,7 @@ namespace MWMechanics void Spells::usePower(const std::string &power) { - mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp(); + mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp(); } void Spells::readState(const ESM::SpellState &state) From 7b6fe149f2770de7d019696b6e2f6d0bbb670c6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Oct 2015 15:41:43 +0200 Subject: [PATCH 1138/1812] getSpellSuccessChance return 0 for used powers (Fixes #2944) --- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++++ apps/openmw/mwworld/worldimp.cpp | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6d6b9d9505..70d097687e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -123,6 +123,9 @@ namespace MWMechanics } } + if (spell->mData.mType == ESM::Spell::ST_Power) + return stats.getSpells().canUsePower(spell->mId) ? 100 : 0; + if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; @@ -817,6 +820,10 @@ namespace MWMechanics sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f); return false; } + + // A power can be used once per 24h + if (spell->mData.mType == ESM::Spell::ST_Power) + stats.getSpells().usePower(spell->mId); } if (mCaster == getPlayer() && spellIncreasesSkill(spell)) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5857861366..d994a35ee7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2660,10 +2660,6 @@ namespace MWWorld { const ESM::Spell* spell = getStore().get().find(selectedSpell); - // A power can be used once per 24h - if (spell->mData.mType == ESM::Spell::ST_Power) - stats.getSpells().usePower(spell->mId); - cast.cast(spell); } else if (actor.getClass().hasInventoryStore(actor)) From e8f68973760e32e77b8488e916ff603c3edad2b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 6 Oct 2015 14:30:32 +0200 Subject: [PATCH 1139/1812] fixed a possible script bug regarding ID-access for instances that did not yet existed when the script was compiled --- apps/openmw/mwscript/compilercontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 083f463bc3..cf5eff9e7d 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/manualref.hpp" namespace MWScript { @@ -42,9 +43,9 @@ namespace MWScript } else { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - script = ptr.getClass().getScript (ptr); + script = ref.getPtr().getClass().getScript (ref.getPtr()); reference = true; } From 91bf5ae237adc7016432b20b57e600e06c6cbb17 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Oct 2015 02:43:21 +0200 Subject: [PATCH 1140/1812] Add new script instance when a container item is unstacked (Bug #2962) --- apps/openmw/mwworld/containerstore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5a26f09f5b..bcaaeff94a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -140,7 +140,11 @@ void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container) { if (ptr.getRefData().getCount() <= 1) return; - addNewStack(ptr, ptr.getRefData().getCount()-1); + MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-1); + const std::string script = it->getClass().getScript(*it); + if (!script.empty()) + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it); + remove(ptr, ptr.getRefData().getCount()-1, container); } From 944dfa53727eb0f8e93a6805cad0195093efa5f9 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Mon, 5 Oct 2015 11:53:12 +0200 Subject: [PATCH 1141/1812] a light without the carry flag can't be equipped ! it fixes Antares big mod teaching disciplines, it adds a light which should not be equipped to npcs which have learnt something. --- apps/openmw/mwclass/light.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f1dd18acca..34d93da678 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -234,6 +234,11 @@ namespace MWClass std::pair Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { + MWWorld::LiveCellRef *ref = + ptr.get(); + if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) + return std::make_pair(0,""); + MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); From b911abd7d8c1e1f14350b8155825970020957790 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 7 Oct 2015 12:25:52 +0200 Subject: [PATCH 1142/1812] add a few more possible arguments to choice this fixes some travel dialogs for "Antares Big Mod" --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index cd645f0cff..6e65c31838 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -179,7 +179,7 @@ namespace Compiler extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); - extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); + extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, opcodeForceGreetingExplicit); extensions.registerInstruction("goodbye", "", opcodeGoodbye); From 998348e606182eb171dd82b99b647e3dff798b26 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 8 Oct 2015 12:35:09 +1100 Subject: [PATCH 1143/1812] Further rationalise the use of ColumnIds - Address Zini's review comments as per https://github.com/OpenMW/openmw/pull/755 --- apps/opencs/model/world/columnbase.cpp | 3 +-- apps/opencs/model/world/columnbase.hpp | 3 +-- apps/opencs/model/world/columns.cpp | 7 +++---- apps/opencs/model/world/columns.hpp | 6 +++--- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/refidcollection.cpp | 4 ++-- apps/opencs/view/doc/viewmanager.cpp | 2 +- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 2143ec730e..39232d4423 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -77,7 +77,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Video, Display_Id, - Display_SkillImpact, + Display_SkillId, Display_EffectRange, Display_EffectId, Display_PartRefType, @@ -85,7 +85,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, - Display_RaceSkill, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 400e31333f..e2871d4d85 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -113,7 +113,7 @@ namespace CSMWorld Display_SoundGeneratorType, Display_School, Display_Id, - Display_SkillImpact, + Display_SkillId, Display_EffectRange, Display_EffectId, Display_PartRefType, @@ -121,7 +121,6 @@ namespace CSMWorld Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, - Display_RaceSkill, Display_String32, Display_LongString256, diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 2e0a697a57..78bee2195b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -268,7 +268,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, - { ColumnId_SkillImpact, "Skill" }, + { ColumnId_Skill, "Skill" }, { ColumnId_InfoList, "Info List" }, { ColumnId_InfoCondition, "Info Conditions" }, @@ -293,8 +293,7 @@ namespace CSMWorld { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, - { ColumnId_RaceMaleValue, "Male Attrib" }, - { ColumnId_RaceFemaleValue, "Female Attrib" }, + { ColumnId_Male, "Male" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, { ColumnId_RaceBonus, "Bonus" }, @@ -572,7 +571,7 @@ namespace case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes; case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; - case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; + case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fb25004ecd..b73f5e6051 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -261,7 +261,7 @@ namespace CSMWorld ColumnId_LevelledItemChanceNone = 238, ColumnId_PowerList = 239, - ColumnId_SkillImpact = 240, // impact from magic effects + ColumnId_Skill = 240, ColumnId_InfoList = 241, ColumnId_InfoCondition = 242, @@ -288,8 +288,8 @@ namespace CSMWorld ColumnId_NpcPersistence = 261, ColumnId_RaceAttributes = 262, - ColumnId_RaceMaleValue = 263, - ColumnId_RaceFemaleValue = 264, + ColumnId_Male = 263, + // unused ColumnId_RaceSkillBonus = 265, // unused ColumnId_RaceBonus = 267, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a27ab50944..8acdac84fd 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -143,15 +143,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Male, ColumnBase::Display_Integer)); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer)); // Race skill bonus mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); @@ -213,7 +213,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mSpells.getNestableColumn(index)->addColumn( @@ -329,7 +329,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index d7b7cedfab..eb4dce51e2 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mColumns.back().addColumn( @@ -491,7 +491,7 @@ CSMWorld::RefIdCollection::RefIdCollection() skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false)); + new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index ca4ad2d004..728e69a7a6 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false }, - { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, + { CSMWorld::ColumnBase::Display_SkillId, CSMWorld::Columns::ColumnId_Skill, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, From 3bbcf6a9169dc24d47c4d10e24f3818681fc34c0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 8 Oct 2015 12:47:23 +1100 Subject: [PATCH 1144/1812] Fix AiWander sub-table editing. Should resolve bugs #2888 and #2930. --- apps/opencs/model/world/columns.cpp | 11 +- apps/opencs/model/world/columns.hpp | 11 +- apps/opencs/model/world/refidadapterimp.hpp | 146 ++++++++++++-------- apps/opencs/model/world/refidcollection.cpp | 18 ++- 4 files changed, 123 insertions(+), 63 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 78bee2195b..d0d3a1671d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -249,7 +249,7 @@ namespace CSMWorld { ColumnId_AiWanderDist, "Wander Dist" }, { ColumnId_AiDuration, "Ai Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, - { ColumnId_AiWanderIdle, "Wander Idle" }, + //{ ColumnId_AiWanderIdle, "Wander Idle" }, { ColumnId_AiWanderRepeat, "Wander Repeat" }, { ColumnId_AiActivateName, "Activate" }, { ColumnId_AiTargetId, "Target ID" }, @@ -316,6 +316,15 @@ namespace CSMWorld { ColumnId_MaxAttack, "Max Attack" }, { ColumnId_CreatureMisc, "Creature Misc" }, + { ColumnId_Idle1, "Idle 1" }, + { ColumnId_Idle2, "Idle 2" }, + { ColumnId_Idle3, "Idle 3" }, + { ColumnId_Idle4, "Idle 4" }, + { ColumnId_Idle5, "Idle 5" }, + { ColumnId_Idle6, "Idle 6" }, + { ColumnId_Idle7, "Idle 7" }, + { ColumnId_Idle8, "Idle 8" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b73f5e6051..a504e5f659 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -241,7 +241,7 @@ namespace CSMWorld ColumnId_AiWanderDist = 221, ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, - ColumnId_AiWanderIdle = 224, + // unused ColumnId_AiWanderRepeat = 225, ColumnId_AiActivateName = 226, // use ColumnId_PosX, etc for AI destinations @@ -316,6 +316,15 @@ namespace CSMWorld ColumnId_MaxAttack = 284, ColumnId_CreatureMisc = 285, + ColumnId_Idle1 = 286, + ColumnId_Idle2 = 287, + ColumnId_Idle3 = 288, + ColumnId_Idle4 = 289, + ColumnId_Idle5 = 290, + ColumnId_Idle6 = 291, + ColumnId_Idle7 = 292, + ColumnId_Idle8 = 293, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 53da63806e..4ac27b6e90 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1532,6 +1532,8 @@ namespace CSMWorld virtual ~ActorAiRefIdAdapter() {} + // FIXME: should check if the AI package type is already in the list and use a default + // that wasn't used already (in extreme case do not add anything at all? virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -1615,6 +1617,7 @@ namespace CSMWorld switch (subColIndex) { case 0: + // FIXME: should more than one AI package type be allowed? Check vanilla switch (content.mType) { case ESM::AI_Wander: return 0; @@ -1642,47 +1645,52 @@ namespace CSMWorld else return QVariant(); case 4: // wander idle + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: if (content.mType == ESM::AI_Wander) - { - return static_cast(content.mWander.mIdle[0]); // FIXME: - } + return static_cast(content.mWander.mIdle[subColIndex-4]); else return QVariant(); - case 5: // wander repeat + case 12: // wander repeat if (content.mType == ESM::AI_Wander) return content.mWander.mShouldRepeat != 0; else return QVariant(); - case 6: // activate name + case 13: // activate name if (content.mType == ESM::AI_Activate) return QString(content.mActivate.mName.toString().c_str()); else return QVariant(); - case 7: // target id + case 14: // target id if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return QString(content.mTarget.mId.toString().c_str()); else return QVariant(); - case 8: // target cell + case 15: // target cell if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return QString::fromUtf8(content.mCellName.c_str()); else return QVariant(); - case 9: + case 16: if (content.mType == ESM::AI_Travel) return content.mTravel.mX; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return content.mTarget.mX; else return QVariant(); - case 10: + case 17: if (content.mType == ESM::AI_Travel) return content.mTravel.mY; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) return content.mTarget.mY; else return QVariant(); - case 11: + case 18: if (content.mType == ESM::AI_Travel) return content.mTravel.mZ; else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) @@ -1712,11 +1720,12 @@ namespace CSMWorld case 0: // ai package type switch (value.toInt()) { - case 0: content.mType = ESM::AI_Wander; - case 1: content.mType = ESM::AI_Travel; - case 2: content.mType = ESM::AI_Follow; - case 3: content.mType = ESM::AI_Escort; - case 4: content.mType = ESM::AI_Activate; + case 0: content.mType = ESM::AI_Wander; break; + case 1: content.mType = ESM::AI_Travel; break; + case 2: content.mType = ESM::AI_Follow; break; + case 3: content.mType = ESM::AI_Escort; break; + case 4: content.mType = ESM::AI_Activate; break; + default: return; // return without saving } break; // always save @@ -1725,6 +1734,8 @@ namespace CSMWorld content.mWander.mDistance = static_cast(value.toInt()); else return; // return without saving + + break; // always save case 2: if (content.mType == ESM::AI_Wander || content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) @@ -1736,62 +1747,77 @@ namespace CSMWorld content.mWander.mTimeOfDay = static_cast(value.toInt()); else return; // return without saving + + break; // always save case 4: - if (content.mType == ESM::AI_Wander) - break; // FIXME: idle - else - return; // return without saving case 5: - if (content.mType == ESM::AI_Wander) - { - content.mWander.mShouldRepeat = static_cast(value.toInt()); - break; - } - case 6: // NAME32 - if (content.mType == ESM::AI_Activate) - { - content.mActivate.mName.assign(value.toString().toUtf8().constData()); - break; - } - else - return; // return without saving - case 7: // NAME32 - if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - { - content.mTarget.mId.assign(value.toString().toUtf8().constData()); - break; - } - else - return; // return without saving + case 6: + case 7: case 8: - if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - { - content.mCellName = std::string(value.toString().toUtf8().constData()); - break; - } - else - return; // return without saving case 9: - if (content.mType == ESM::AI_Travel) - content.mTravel.mZ = value.toFloat(); - else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - content.mTarget.mZ = value.toFloat(); - else - return; // return without saving case 10: - if (content.mType == ESM::AI_Travel) - content.mTravel.mZ = value.toFloat(); - else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) - content.mTarget.mZ = value.toFloat(); - else - return; // return without saving case 11: + if (content.mType == ESM::AI_Wander) + content.mWander.mIdle[subColIndex-4] = static_cast(value.toInt()); + else + return; // return without saving + + break; // always save + case 12: + if (content.mType == ESM::AI_Wander) + content.mWander.mShouldRepeat = static_cast(value.toInt()); + else + return; // return without saving + + break; // always save + case 13: // NAME32 + if (content.mType == ESM::AI_Activate) + content.mActivate.mName.assign(value.toString().toUtf8().constData()); + else + return; // return without saving + + break; // always save + case 14: // NAME32 + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mId.assign(value.toString().toUtf8().constData()); + else + return; // return without saving + + break; // always save + case 15: + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mCellName = std::string(value.toString().toUtf8().constData()); + else + return; // return without saving + + break; // always save + case 16: if (content.mType == ESM::AI_Travel) content.mTravel.mZ = value.toFloat(); else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) content.mTarget.mZ = value.toFloat(); else return; // return without saving + + break; // always save + case 17: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + + break; // always save + case 18: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + + break; // always save default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1801,7 +1827,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - return 12; + return 19; } virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index eb4dce51e2..3b316bea3a 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -193,8 +193,24 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Idle1, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle2, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle3, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle4, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle5, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle6, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle7, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Idle8, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( From 2f808f957d6cb0f59e4eb40002c931bf1bbee60b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 8 Oct 2015 14:01:29 +0200 Subject: [PATCH 1145/1812] fixed for compiler not recognising script names in some situations --- apps/openmw/mwscript/compilercontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index cf5eff9e7d..4a7038e1cb 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -83,7 +83,8 @@ namespace MWScript store.get().search (name) || store.get().search (name) || store.get().search (name) || - store.get().search (name); + store.get().search (name) || + store.get().search (name); } bool CompilerContext::isJournalId (const std::string& name) const From e7a3f059aafb643238d95de8d34554747d7e74f2 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Wed, 7 Oct 2015 12:39:19 +1000 Subject: [PATCH 1146/1812] Implemented line and col calculations in scriptsubview --- apps/opencs/view/world/scriptsubview.cpp | 44 +++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d99f789b3a..35b9ccf0c3 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -198,26 +198,38 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (hint.empty()) return; - if (hint[0]=='l') - { - std::istringstream stream (hint.c_str()+1); - - char ignore; - int line; - int column; - - if (stream >> ignore >> line >> column) + size_t line = 0, column = 0; + std::istringstream stream (hint.c_str()+2); + switch(hint[0]){ + case 'R': + case 'r': { - QTextCursor cursor = mEditor->textCursor(); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + QString source = mModel->data (index).toString(); + size_t pos; + stream >> pos >> pos; - cursor.movePosition (QTextCursor::Start); - if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) - cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); - - mEditor->setFocus(); - mEditor->setTextCursor (cursor); + for (size_t i = 0; i <= pos; ++i){ + if (source[(unsigned) i] == '\n'){ + ++line; + column = i; + } + } + column = pos - column - (line > 0 ? 1 : 0); + break; } + case 'l': + stream >> line >> column; } + + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + + mEditor->setFocus(); + mEditor->setTextCursor (cursor); } void CSVWorld::ScriptSubView::textChanged() From 64821b0785a306f90e4f2f3be9c6a8fa61d440eb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 9 Oct 2015 06:29:50 +1100 Subject: [PATCH 1147/1812] Disable toolbar context menu. Should resolve bug #2953. --- apps/opencs/view/doc/view.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ea11bb0f9a..38088c6d70 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -435,6 +435,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); + setContextMenuPolicy(Qt::NoContextMenu); + updateTitle(); setupUi(); From 8eb6d337d556dce2f64698ac30ad0df881bf84e0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 9 Oct 2015 12:14:22 +0200 Subject: [PATCH 1148/1812] deal with script execution from within a script (Fixes #2964) --- components/interpreter/interpreter.cpp | 59 +++++++++++++++++++++----- components/interpreter/interpreter.hpp | 7 +++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 263cea9a53..1892e4a6f5 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -132,7 +132,34 @@ namespace Interpreter throw std::runtime_error (error.str()); } - Interpreter::Interpreter() + void Interpreter::begin() + { + if (mRunning) + { + mCallstack.push (mRuntime); + mRuntime.clear(); + } + else + { + mRunning = true; + } + } + + void Interpreter::end() + { + if (mCallstack.empty()) + { + mRuntime.clear(); + mRunning = false; + } + else + { + mRuntime = mCallstack.top(); + mCallstack.pop(); + } + } + + Interpreter::Interpreter() : mRunning (false) {} Interpreter::~Interpreter() @@ -202,19 +229,29 @@ namespace Interpreter { assert (codeSize>=4); - mRuntime.configure (code, codeSize, context); + begin(); - int opcodes = static_cast (code[0]); - - const Type_Code *codeBlock = code + 4; - - while (mRuntime.getPC()>=0 && mRuntime.getPC() (code[0]); + + const Type_Code *codeBlock = code + 4; + + while (mRuntime.getPC()>=0 && mRuntime.getPC() +#include #include "runtime.hpp" #include "types.hpp" @@ -14,6 +15,8 @@ namespace Interpreter class Interpreter { + std::stack mCallstack; + bool mRunning; Runtime mRuntime; std::map mSegment0; std::map mSegment1; @@ -32,6 +35,10 @@ namespace Interpreter void abortUnknownSegment (Type_Code code); + void begin(); + + void end(); + public: Interpreter(); From 4ca7b2660932efb06535f148a643a7e814f3a72d Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Fri, 9 Oct 2015 21:52:12 +1000 Subject: [PATCH 1149/1812] Stream error handling, and other minor changes. --- apps/opencs/view/world/scriptsubview.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 35b9ccf0c3..eb0c706564 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -198,28 +198,31 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (hint.empty()) return; - size_t line = 0, column = 0; - std::istringstream stream (hint.c_str()+2); + unsigned line = 0, column = 0; + char c; + std::istringstream stream (hint.c_str()+1); switch(hint[0]){ case 'R': case 'r': { QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); QString source = mModel->data (index).toString(); - size_t pos; - stream >> pos >> pos; + unsigned pos, dummy; + if (!(stream >> c >> dummy >> pos) ) + return; - for (size_t i = 0; i <= pos; ++i){ - if (source[(unsigned) i] == '\n'){ + for (unsigned i = 0; i <= pos; ++i){ + if (source[i] == '\n'){ ++line; - column = i; + column = i+1; } } - column = pos - column - (line > 0 ? 1 : 0); + column = pos - column; break; } case 'l': - stream >> line >> column; + if (!(stream >> c >> line >> column)) + return; } QTextCursor cursor = mEditor->textCursor(); From 0d35938794f161a84ff66ae587e95fae8e0f2c12 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:12:01 +0200 Subject: [PATCH 1150/1812] basic cell arrow rendering (shape is a placeholder) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 24 +++++ apps/opencs/view/render/cell.hpp | 8 ++ apps/opencs/view/render/cellarrow.cpp | 93 +++++++++++++++++++ apps/opencs/view/render/cellarrow.hpp | 70 ++++++++++++++ .../view/render/pagedworldspacewidget.cpp | 32 +++++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/render/cellarrow.cpp create mode 100644 apps/opencs/view/render/cellarrow.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 196e899b23..6af04e8fc2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase + lightingbright object cell terrainstorage tagbase cellarrow ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index c4f7445103..345bc79a73 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -9,6 +9,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" +#include "../../model/world/cellcoordinates.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -232,3 +233,26 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) } } } + +void CSVRender::Cell::setCellArrows (int mask) +{ + for (int i=0; i<4; ++i) + { + CellArrow::Direction direction = static_cast (1< mTerrain; int mX; int mY; + std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. /// @@ -86,6 +89,11 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); void setSelection (int elementMask, Selection mode); + + void setCellArrows (int mask); + + /// Returns 0, 0 in case of an unpaged cell. + CSMWorld::CellCoordinates getCoordinates() const; }; } diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp new file mode 100644 index 0000000000..ee055a0b1b --- /dev/null +++ b/apps/opencs/view/render/cellarrow.cpp @@ -0,0 +1,93 @@ + +#include "cellarrow.hpp" + +#include +#include + +#include +#include +#include + + +#include "elements.hpp" + +CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) +: TagBase (Element_CellArrow), mArrow (arrow) +{} + +CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const +{ + return mArrow; +} + + +void CSVRender::CellArrow::adjustTransform() +{ + // position + const int cellSize = 8192; + const int offset = cellSize / 2 + 400; + + int x = mXIndex*cellSize + cellSize/2; + int y = mYIndex*cellSize + cellSize/2; + + switch (mDirection) + { + case Direction_North: y += offset; break; + case Direction_West: x -= offset; break; + case Direction_South: y -= offset; break; + case Direction_East: x += offset; break; + }; + + mBaseNode->setPosition (osg::Vec3f (x, y, 0)); + + // orientation + osg::Quat xr (0, osg::Vec3f (1,0,0)); + osg::Quat yr (0, osg::Vec3f (0,1,0)); + osg::Quat zr (0, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr*yr*xr); +} + +void CSVRender::CellArrow::buildShape() +{ + /// \todo placeholder shape -> replace + osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); + osg::ref_ptr shapedrawable(new osg::ShapeDrawable); + shapedrawable->setShape(shape); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(shapedrawable); + + mBaseNode->addChild (geode); +} + +CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, + int xIndex, int yIndex) +: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) +{ + mBaseNode = new osg::PositionAttitudeTransform; + + mBaseNode->setUserData (new CellArrowTag (this)); + + mParentNode->addChild (mBaseNode); + + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask (Element_CellArrow<<1); + + adjustTransform(); + buildShape(); +} + +CSVRender::CellArrow::~CellArrow() +{ + mParentNode->removeChild (mBaseNode); +} + +int CSVRender::CellArrow::getXIndex() const +{ + return mXIndex; +} + +int CSVRender::CellArrow::getYIndex() const +{ + return mYIndex; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp new file mode 100644 index 0000000000..822e63bdc5 --- /dev/null +++ b/apps/opencs/view/render/cellarrow.hpp @@ -0,0 +1,70 @@ +#ifndef OPENCS_VIEW_CELLARROW_H +#define OPENCS_VIEW_CELLARROW_H + +#include "tagbase.hpp" + +#include + +namespace osg +{ + class PositionAttitudeTransform; + class Group; +} + +namespace CSVRender +{ + class CellArrow; + + class CellArrowTag : public TagBase + { + CellArrow *mArrow; + + public: + + CellArrowTag (CellArrow *arrow); + + CellArrow *getCellArrow() const; + }; + + + class CellArrow + { + public: + + enum Direction + { + Direction_North = 1, + Direction_West = 2, + Direction_South = 4, + Direction_East = 8 + }; + + private: + + // not implemented + CellArrow (const CellArrow&); + CellArrow& operator= (const CellArrow&); + + Direction mDirection; + osg::Group* mParentNode; + osg::ref_ptr mBaseNode; + int mXIndex; + int mYIndex; + + void adjustTransform(); + + void buildShape(); + + public: + + CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + + ~CellArrow(); + + int getXIndex() const; + + int getYIndex() const; + }; +} + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 7403113b37..070ce7d17d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,6 +21,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; + bool wasEmpty = mCells.empty(); const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); @@ -32,6 +33,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->first.getId (mWorldspace)); + /// \todo handle cells that don't exist if (!mSelection.has (iter->first) || index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) { @@ -60,6 +62,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { int index = cells.searchId (iter->getId (mWorldspace)); + /// \todo handle cells that don't exist if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { @@ -72,6 +75,35 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } if (modified) + { + for (std::map::const_iterator iter (mCells.begin()); + iter!=mCells.end(); ++iter) + { + int mask = 0; + + for (int i=CellArrow::Direction_North; i<=CellArrow::Direction_East; i *= 2) + { + CSMWorld::CellCoordinates coordinates (iter->second->getCoordinates()); + + switch (i) + { + case CellArrow::Direction_North: coordinates = coordinates.move (0, 1); break; + case CellArrow::Direction_West: coordinates = coordinates.move (-1, 0); break; + case CellArrow::Direction_South: coordinates = coordinates.move (0, -1); break; + case CellArrow::Direction_East: coordinates = coordinates.move (1, 0); break; + } + + if (!mSelection.has (coordinates)) + mask |= i; + } + + iter->second->setCellArrows (mask); + } + } + + /// \todo do not overwrite manipulator object + /// \todo move code to useViewHint function + if (modified && wasEmpty) mView->setCameraManipulator(new osgGA::TrackballManipulator); return modified; From b81ee606c831f3a7b700165716f0df568d0a6ad3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 14:31:55 +0200 Subject: [PATCH 1151/1812] use CellCoordinates instead of a pair of ints for cell coordinates --- apps/opencs/view/render/cell.cpp | 9 ++++----- apps/opencs/view/render/cell.hpp | 3 +-- apps/opencs/view/render/cellarrow.cpp | 18 ++++++------------ apps/opencs/view/render/cellarrow.hpp | 12 ++++++------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 345bc79a73..e0e63c8c9e 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -52,7 +52,7 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) +: mData (data), mId (Misc::StringUtils::lowerCase (id)) { mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -76,8 +76,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain->loadCell(esmLand.mX, esmLand.mY); - mX = esmLand.mX; - mY = esmLand.mY; + mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } @@ -245,7 +244,7 @@ void CSVRender::Cell::setCellArrows (int mask) if (enable!=(mCellArrows[i].get()!=0)) { if (enable) - mCellArrows[i].reset (new CellArrow (mCellNode, direction, mX, mY)); + mCellArrows[i].reset (new CellArrow (mCellNode, direction, mCoordinates)); else mCellArrows[i].reset (0); } @@ -254,5 +253,5 @@ void CSVRender::Cell::setCellArrows (int mask) CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { - return CSMWorld::CellCoordinates (mX, mY); + return mCoordinates; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5b1badcbe9..7cced4fe37 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -38,8 +38,7 @@ namespace CSVRender osg::ref_ptr mCellNode; std::map mObjects; std::auto_ptr mTerrain; - int mX; - int mY; + CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; /// Ignored if cell does not have an object with the given ID. diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index ee055a0b1b..443d398dd8 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -8,7 +8,6 @@ #include #include - #include "elements.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) @@ -27,8 +26,8 @@ void CSVRender::CellArrow::adjustTransform() const int cellSize = 8192; const int offset = cellSize / 2 + 400; - int x = mXIndex*cellSize + cellSize/2; - int y = mYIndex*cellSize + cellSize/2; + int x = mCoordinates.getX()*cellSize + cellSize/2; + int y = mCoordinates.getY()*cellSize + cellSize/2; switch (mDirection) { @@ -61,8 +60,8 @@ void CSVRender::CellArrow::buildShape() } CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, - int xIndex, int yIndex) -: mDirection (direction), mParentNode (cellNode), mXIndex (xIndex), mYIndex (yIndex) + const CSMWorld::CellCoordinates& coordinates) +: mDirection (direction), mParentNode (cellNode), mCoordinates (coordinates) { mBaseNode = new osg::PositionAttitudeTransform; @@ -82,12 +81,7 @@ CSVRender::CellArrow::~CellArrow() mParentNode->removeChild (mBaseNode); } -int CSVRender::CellArrow::getXIndex() const +CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { - return mXIndex; -} - -int CSVRender::CellArrow::getYIndex() const -{ - return mYIndex; + return mCoordinates; } diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 822e63bdc5..4422ec890f 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/cellcoordinates.hpp" + namespace osg { class PositionAttitudeTransform; @@ -48,8 +50,7 @@ namespace CSVRender Direction mDirection; osg::Group* mParentNode; osg::ref_ptr mBaseNode; - int mXIndex; - int mYIndex; + CSMWorld::CellCoordinates mCoordinates; void adjustTransform(); @@ -57,13 +58,12 @@ namespace CSVRender public: - CellArrow (osg::Group *cellNode, Direction direction, int xIndex, int yIndex); + CellArrow (osg::Group *cellNode, Direction direction, + const CSMWorld::CellCoordinates& coordinates); ~CellArrow(); - int getXIndex() const; - - int getYIndex() const; + CSMWorld::CellCoordinates getCoordinates() const; }; } From 3f9db7ba3cc12739a238207797c92c07b74332ab Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 12 Oct 2015 18:00:44 +0200 Subject: [PATCH 1152/1812] more reliable method of obtaining the cell coordinates in CSVRender::Cell --- apps/opencs/model/world/cellcoordinates.cpp | 17 +++++++++++++++++ apps/opencs/model/world/cellcoordinates.hpp | 6 ++++++ apps/opencs/view/render/cell.cpp | 7 +++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 95e206e2d3..3ef3e6c693 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con return stream.str(); } +std::pair CSMWorld::CellCoordinates::fromId ( + const std::string& id) +{ + // no worldspace for now, needs to be changed for 1.1 + if (!id.empty() && id[0]=='#') + { + int x, y; + char ignore; + + std::istringstream stream (id); + if (stream >> ignore >> x >> y) + return std::make_pair (CellCoordinates (x, y), true); + } + + return std::make_pair (CellCoordinates(), false); +} + bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) { return left.getX()==right.getX() && left.getY()==right.getY(); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index ee395ea7ee..63db60c29d 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -28,6 +28,12 @@ namespace CSMWorld std::string getId (const std::string& worldspace) const; ///< Return the ID for the cell at these coordinates. + + /// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates), + /// second: is cell paged? + /// + /// \note The worldspace part of \a id is ignored + static std::pair fromId (const std::string& id); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e0e63c8c9e..5ec69a5f26 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -54,6 +54,11 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) : mData (data), mId (Misc::StringUtils::lowerCase (id)) { + std::pair result = CSMWorld::CellCoordinates::fromId (id); + + if (result.second) + mCoordinates = result.first; + mCellNode = new osg::Group; rootNode->addChild(mCellNode); @@ -75,8 +80,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand.mX, esmLand.mY); - - mCoordinates = CSMWorld::CellCoordinates (esmLand.mX, esmLand.mY); } } } From 6e140c9cb1c3cb3406295a57488f32e5d6acc288 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 11:43:33 +0200 Subject: [PATCH 1153/1812] proper shape for cell arrows (kinda) --- apps/opencs/view/render/cellarrow.cpp | 95 ++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 443d398dd8..8f03b489f2 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -3,10 +3,9 @@ #include #include - -#include -#include #include +#include +#include #include "elements.hpp" @@ -24,37 +23,99 @@ void CSVRender::CellArrow::adjustTransform() { // position const int cellSize = 8192; - const int offset = cellSize / 2 + 400; + const int offset = cellSize / 2 + 800; int x = mCoordinates.getX()*cellSize + cellSize/2; int y = mCoordinates.getY()*cellSize + cellSize/2; + float xr = 0; + float yr = 0; + float zr = 0; + + float angle = osg::DegreesToRadians (90.0f); + switch (mDirection) { - case Direction_North: y += offset; break; - case Direction_West: x -= offset; break; - case Direction_South: y -= offset; break; - case Direction_East: x += offset; break; + case Direction_North: y += offset; xr = -angle; zr = angle; break; + case Direction_West: x -= offset; yr = -angle; break; + case Direction_South: y -= offset; xr = angle; zr = angle; break; + case Direction_East: x += offset; yr = angle; break; }; mBaseNode->setPosition (osg::Vec3f (x, y, 0)); // orientation - osg::Quat xr (0, osg::Vec3f (1,0,0)); - osg::Quat yr (0, osg::Vec3f (0,1,0)); - osg::Quat zr (0, osg::Vec3f (0,0,1)); - mBaseNode->setAttitude (zr*yr*xr); + osg::Quat xr2 (xr, osg::Vec3f (1,0,0)); + osg::Quat yr2 (yr, osg::Vec3f (0,1,0)); + osg::Quat zr2 (zr, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr2*yr2*xr2); } void CSVRender::CellArrow::buildShape() { - /// \todo placeholder shape -> replace - osg::ref_ptr shape(new osg::Box(osg::Vec3f(0,0,0), 200)); - osg::ref_ptr shapedrawable(new osg::ShapeDrawable); - shapedrawable->setShape(shape); + osg::ref_ptr geometry (new osg::Geometry); + + const int arrowWidth = 4000; + const int arrowLength = 1500; + const int arrowHeight = 500; + + osg::Vec3Array *vertices = new osg::Vec3Array; + for (int i2=0; i2<2; ++i2) + for (int i=0; i<2; ++i) + { + float height = i ? -arrowHeight/2 : arrowHeight/2; + vertices->push_back (osg::Vec3f (height, -arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, 0, arrowLength)); + } + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + top->push_back (0); + top->push_back (1); + top->push_back (2); + geometry->addPrimitiveSet (top); + + osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + bottom->push_back (5); + bottom->push_back (4); + bottom->push_back (3); + geometry->addPrimitiveSet (bottom); + + osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + back->push_back (3+6); + back->push_back (4+6); + back->push_back (1+6); + back->push_back (0+6); + geometry->addPrimitiveSet (back); + + osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side1->push_back (0+6); + side1->push_back (2+6); + side1->push_back (5+6); + side1->push_back (3+6); + geometry->addPrimitiveSet (side1); + + osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); + side2->push_back (4+6); + side2->push_back (5+6); + side2->push_back (2+6); + side2->push_back (1+6); + geometry->addPrimitiveSet (side2); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + + geometry->setColorArray (colours); + geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(shapedrawable); + geode->addDrawable (geometry); mBaseNode->addChild (geode); } From 0b1d6bddc8b1f2f16b61d51be7bc4fd09e618049 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:11:47 +0200 Subject: [PATCH 1154/1812] merged primitives arrays --- apps/opencs/view/render/cellarrow.cpp | 63 +++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 8f03b489f2..526c9a24ca 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -71,38 +71,45 @@ void CSVRender::CellArrow::buildShape() geometry->setVertexArray (vertices); - osg::DrawElementsUShort *top = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - top->push_back (0); - top->push_back (1); - top->push_back (2); - geometry->addPrimitiveSet (top); + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - osg::DrawElementsUShort *bottom = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); - bottom->push_back (5); - bottom->push_back (4); - bottom->push_back (3); - geometry->addPrimitiveSet (bottom); + // top + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); - osg::DrawElementsUShort *back = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - back->push_back (3+6); - back->push_back (4+6); - back->push_back (1+6); - back->push_back (0+6); - geometry->addPrimitiveSet (back); + // bottom + primitives->push_back (5); + primitives->push_back (4); + primitives->push_back (3); - osg::DrawElementsUShort *side1 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side1->push_back (0+6); - side1->push_back (2+6); - side1->push_back (5+6); - side1->push_back (3+6); - geometry->addPrimitiveSet (side1); + // back + primitives->push_back (3+6); + primitives->push_back (4+6); + primitives->push_back (1+6); - osg::DrawElementsUShort *side2 = new osg::DrawElementsUShort (osg::PrimitiveSet::QUADS, 0); - side2->push_back (4+6); - side2->push_back (5+6); - side2->push_back (2+6); - side2->push_back (1+6); - geometry->addPrimitiveSet (side2); + primitives->push_back (3+6); + primitives->push_back (1+6); + primitives->push_back (0+6); + + // sides + primitives->push_back (0+6); + primitives->push_back (2+6); + primitives->push_back (5+6); + + primitives->push_back (0+6); + primitives->push_back (5+6); + primitives->push_back (3+6); + + primitives->push_back (4+6); + primitives->push_back (5+6); + primitives->push_back (2+6); + + primitives->push_back (4+6); + primitives->push_back (2+6); + primitives->push_back (1+6); + + geometry->addPrimitiveSet (primitives); osg::Vec4Array *colours = new osg::Vec4Array; From 68115c4e8aa3447e8848528b816c3fd4a8253e64 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:15:53 +0200 Subject: [PATCH 1155/1812] (somewhat) improved the colour scheme --- apps/opencs/view/render/cellarrow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 526c9a24ca..59460b6269 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -116,7 +116,7 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); for (int i=0; i<6; ++i) - colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.4f, 1.0f)); + colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); geometry->setColorArray (colours); geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); From a88d56148b45a6ddb1c4cb95ab75f112550fac58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 16:35:31 +0200 Subject: [PATCH 1156/1812] Read the Sun Glare Fader ini settings --- apps/openmw/mwrender/sky.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6f1b26733e..a8aeeb9307 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -724,7 +724,17 @@ private: , mTimeOfDayFade(1.f) , mGlareView(1.f) { + const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); + mColor = fallback->getFallbackColour("Weather_Sun_Glare_Fader_Color"); + mSunGlareFaderMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Max"); + mSunGlareFaderAngleMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Angle_Max"); + // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, + // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, + // so the resulting color looks more orange than red. + mColor *= 2; + for (int i=0; i<3; ++i) + mColor[i] = std::min(1.f, mColor[i]); } virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv) @@ -734,12 +744,10 @@ private: float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); - const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max + const float angleMaxRadians = osg::DegreesToRadians(mSunGlareFaderAngleMax); float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians); - - const float sunGlareFaderMax = 0.5f; - float fade = value * sunGlareFaderMax; + float fade = value * mSunGlareFaderMax; fade *= mTimeOfDayFade * mGlareView * visibleRatio; @@ -754,17 +762,8 @@ private: osg::ref_ptr mat (createUnlitMaterial()); - osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1); - - // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, - // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, - // so the resulting color looks more orange than red. - sunGlareFaderColor *= 2; - for (int i=0; i<3; ++i) - sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); - mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); + mat->setEmission(osg::Material::FRONT_AND_BACK, mColor); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); @@ -802,6 +801,9 @@ private: osg::ref_ptr mSunTransform; float mTimeOfDayFade; float mGlareView; + osg::Vec4f mColor; + float mSunGlareFaderMax; + float mSunGlareFaderAngleMax; }; osg::ref_ptr mUpdater; From 773df6fd22e756ec39f0ad516edd47286914eef0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 13 Oct 2015 16:53:40 +0200 Subject: [PATCH 1157/1812] some OSG fixes --- apps/opencs/view/render/cellarrow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 59460b6269..720db53278 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -118,8 +118,9 @@ void CSVRender::CellArrow::buildShape() for (int i=0; i<6; ++i) colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); - geometry->setColorArray (colours); - geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); osg::ref_ptr geode (new osg::Geode); geode->addDrawable (geometry); From ee450471fdf4dbb276bbf6f3f7e7662237d84652 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 17:55:57 +0200 Subject: [PATCH 1158/1812] Disable head controller for non-bipedal creatures (Fixes #2843, Fixes #2966) --- apps/openmw/mwrender/animation.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 37ec4c2139..a0704a59a2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1320,13 +1320,16 @@ namespace MWRender { mHeadController = NULL; - NodeMap::iterator found = mNodeMap.find("bip01 head"); - if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + if (mPtr.getClass().isBipedal(mPtr)) { - osg::Node* node = found->second; - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); + NodeMap::iterator found = mNodeMap.find("bip01 head"); + if (found != mNodeMap.end() && dynamic_cast(found->second.get())) + { + osg::Node* node = found->second; + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } } } From f36d463617b0b9f29dd9edaf19bb122882b8b7e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 18:13:52 +0200 Subject: [PATCH 1159/1812] Enchantment error handling fix (Fixes #2959) Catch errors about missing enchantments before they propagate up the stack and interrupt the whole frame update. --- apps/openmw/mwgui/spellmodel.cpp | 11 +++++++++-- apps/openmw/mwworld/inventorystore.cpp | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 91512a0116..58ec057948 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -1,5 +1,7 @@ #include "spellmodel.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -79,8 +81,13 @@ namespace MWGui const std::string enchantId = item.getClass().getEnchantment(item); if (enchantId.empty()) continue; - const ESM::Enchantment* enchant = - esmStore.get().find(item.getClass().getEnchantment(item)); + const ESM::Enchantment* enchant = esmStore.get().search(enchantId); + if (!enchant) + { + std::cerr << "Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId() << std::endl; + continue; + } + if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce) continue; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 0755c1555e..ebba4ae30d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -645,8 +645,15 @@ void MWWorld::InventoryStore::updateRechargingItems() { if (it->getClass().getEnchantment(*it) != "") { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( - it->getClass().getEnchantment(*it)); + std::string enchantmentId = it->getClass().getEnchantment(*it); + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().search( + enchantmentId); + if (!enchantment) + { + std::cerr << "Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId() << std::endl; + continue; + } + if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) mRechargingItems.push_back(std::make_pair(it, static_cast(enchantment->mData.mCharge))); From 8459a79a2c1da69e3f215fb3d29b4999ad0a8b6f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Oct 2015 19:05:17 +0200 Subject: [PATCH 1160/1812] Fix AI being able to open locked doors (Fixes #2948) --- apps/openmw/mwmechanics/aipackage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1cd9649f76..bedff8bcdc 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -88,7 +88,8 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur MWWorld::Ptr door = getNearbyDoor(actor); if (door != MWWorld::Ptr()) // NOTE: checks interior cells only { - if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() + && door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) { MWBase::Environment::get().getWorld()->activateDoor(door, 1); } } From 33e12a99fad15ced87a9996c42ffeb84983be2a4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Sun, 11 Oct 2015 21:49:10 +1000 Subject: [PATCH 1161/1812] If table dont use any filter, filter update now dont cause a reapply of empty filter --- apps/opencs/view/filter/editwidget.cpp | 12 +++++++++++- apps/opencs/view/filter/editwidget.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 657a47750d..5fbc66464c 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -7,7 +7,7 @@ #include "../../model/world/data.hpp" CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) -: QLineEdit (parent), mParser (data) +: QLineEdit (parent), mParser (data), mIsEmpty(true) { mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); @@ -27,6 +27,16 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) void CSVFilter::EditWidget::textChanged (const QString& text) { + //no need to parse and apply filter if it was empty and now is empty too. + //e.g. - we modifiing content of filter with already opened some other (big) tables. + if (text.length() == 0){ + if (mIsEmpty) + return; + else + mIsEmpty = true; + }else + mIsEmpty = false; + if (mParser.parse (text.toUtf8().constData())) { setPalette (mPalette); diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index a0f9f8919a..5c3f1b09eb 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -25,6 +25,7 @@ namespace CSVFilter CSMFilter::Parser mParser; QPalette mPalette; + bool mIsEmpty; public: From 361634489ed7a1286919bef02b687fe3682cd619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Oct 2015 14:46:08 +0200 Subject: [PATCH 1162/1812] properly handle cells that don't exist --- apps/opencs/view/render/cell.cpp | 52 +++++++++++++------ apps/opencs/view/render/cell.hpp | 8 ++- .../view/render/pagedworldspacewidget.cpp | 47 +++++++++++------ 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 5ec69a5f26..da40f7e7cb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,8 +51,9 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -62,24 +63,27 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCellNode = new osg::Group; rootNode->addChild(mCellNode); - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int rows = references.rowCount(); - - addObjects (0, rows-1); - - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) + if (!mDeleted) { - const ESM::Land& esmLand = land.getRecord(mId).get(); + CSMWorld::IdTable& references = dynamic_cast ( + *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + int rows = references.rowCount(); + + addObjects (0, rows-1); + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); + } } } } @@ -125,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -192,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int if (parent.isValid()) return false; + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -212,6 +222,9 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int if (parent.isValid()) return false; + if (mDeleted) + return false; + return addObjects (start, end); } @@ -258,3 +271,8 @@ CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { return mCoordinates; } + +bool CSVRender::Cell::isDeleted() const +{ + return mDeleted; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 7cced4fe37..59f4cafee4 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -40,6 +40,7 @@ namespace CSVRender std::auto_ptr mTerrain; CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; + bool mDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -62,7 +63,10 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); + /// \note Deleted covers both cells that are deleted and cells that don't exist in + /// the first place. + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted = false); ~Cell(); @@ -93,6 +97,8 @@ namespace CSVRender /// Returns 0, 0 in case of an unpaged cell. CSMWorld::CellCoordinates getCoordinates() const; + + bool isDeleted() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 070ce7d17d..dd740ab9ae 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,5 +1,6 @@ #include "pagedworldspacewidget.hpp" +#include #include #include @@ -26,17 +27,14 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); { - // remove (or name/region modified) + // remove/update std::map::iterator iter (mCells.begin()); while (iter!=mCells.end()) { - int index = cells.searchId (iter->first.getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (!mSelection.has (iter->first) || index==-1 || - cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) + if (!mSelection.has (iter->first)) { + // remove delete iter->second; mCells.erase (iter++); @@ -44,12 +42,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } else { - // check if name or region field has changed - // FIXME: config setting - //std::string name = cells.getRecord(index).get().mName; - //std::string region = cells.getRecord(index).get().mRegion; + // update + int index = cells.searchId (iter->first.getId (mWorldspace)); - // cell marker update goes here + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + if (deleted!=iter->second->isDeleted()) + { + modified = true; + + std::auto_ptr cell (new Cell (mDocument.getData(), mRootNode, + iter->first.getId (mWorldspace), deleted)); + + delete iter->second; + iter->second = cell.release(); + } + else if (!deleted) + { + // delete state has not changed -> just update + + // TODO check if name or region field has changed (cell marker) + // FIXME: config setting + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + modified = true; + } ++iter; } @@ -60,11 +79,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) { - int index = cells.searchId (iter->getId (mWorldspace)); - - /// \todo handle cells that don't exist - if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && - mCells.find (*iter)==mCells.end()) + if (mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), mRootNode, iter->getId (mWorldspace)); From eae36f800585a9347e778b36a1010b2a05f576c4 Mon Sep 17 00:00:00 2001 From: "artemutin@yandex.ru" Date: Tue, 13 Oct 2015 23:44:23 +1000 Subject: [PATCH 1163/1812] Fixed filter reapplication on Description column change and on State column change. Moved column index search to widget constructor, rewrite slot with respect to multiple columns data change. --- apps/opencs/view/filter/editwidget.cpp | 12 ++++++++++-- apps/opencs/view/filter/editwidget.hpp | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 5fbc66464c..600fa4f3bf 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -5,6 +5,8 @@ #include #include "../../model/world/data.hpp" +#include "../../model/world/idtablebase.hpp" +#include "../../model/world/columns.hpp" CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) : QLineEdit (parent), mParser (data), mIsEmpty(true) @@ -12,7 +14,8 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); - QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters); + const CSMWorld::IdTableBase *model = + static_cast (data.getTableModel (CSMWorld::UniversalId::Type_Filters)); connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)), this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)), @@ -23,6 +26,9 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (filterRowsInserted (const QModelIndex&, int, int)), Qt::QueuedConnection); + + mStateColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Modification); + mDescColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Description); } void CSVFilter::EditWidget::textChanged (const QString& text) @@ -55,7 +61,9 @@ void CSVFilter::EditWidget::textChanged (const QString& text) void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - textChanged (text()); + for (int i = topLeft.column(); i <= bottomRight.column(); ++i) + if (i != mStateColumnIndex && i != mDescColumnIndex) + textChanged (text()); } void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end) diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 5c3f1b09eb..f672877d94 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -26,6 +26,8 @@ namespace CSVFilter CSMFilter::Parser mParser; QPalette mPalette; bool mIsEmpty; + int mStateColumnIndex; + int mDescColumnIndex; public: From 04df656f54e9eda44cc1ff68b4f23678089d02f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Oct 2015 21:39:53 +0200 Subject: [PATCH 1164/1812] Remove some junk --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 993dde6e45..1f06940c6b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -420,7 +420,6 @@ namespace MWDialogue { if(mDialogueMap.find(keyword) != mDialogueMap.end()) { - ESM::Dialogue ndialogue = mDialogueMap[keyword]; if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) { executeTopic (keyword); From 93565eccbff87bb3ef8beef9da7250611195a825 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Oct 2015 21:40:16 +0200 Subject: [PATCH 1165/1812] Update the dialogue topic list after running greeting script --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1f06940c6b..f8c9bb38e4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,9 +139,6 @@ namespace MWDialogue win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); - //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI - updateTopics(); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -165,12 +162,19 @@ namespace MWDialogue // TODO play sound } + // first topics update so that parseText knows the keywords to highlight + updateTopics(); + parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); mLastTopic = Misc::StringUtils::lowerCase(it->mId); + + // update topics again to accomodate changes resulting from executeScript + updateTopics(); + return; } } From 2ee6b41887b8dff5231f9925c6a0205a75d67159 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Oct 2015 15:46:53 +0200 Subject: [PATCH 1166/1812] Handle NiAlphaProperty on a drawable basis Removes the RenderBin nesting complication. Also results in leaner StateSets, so the cull phase should be a bit faster. --- components/nifosg/nifloader.cpp | 92 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 75a427c5a8..2b73f779f6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -57,8 +57,8 @@ namespace } } - // Collect all properties affecting the given node that should be applied to an osg::Material. - void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) + // Collect all properties affecting the given drawable that should be handled on drawable basis rather than on the node hierarchy above it. + void collectDrawableProperties(const Nif::Node* nifNode, std::vector& out) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i parent) - collectMaterialProperties(nifNode->parent, out); + collectDrawableProperties(nifNode->parent, out); } class FrameSwitch : public osg::Group @@ -872,9 +873,9 @@ namespace NifOsg osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); - std::vector materialProps; - collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, true, animflags); + std::vector drawableProps; + collectDrawableProperties(nifNode, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); // Particles don't have normals, so can't be diffuse lit. osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); @@ -934,9 +935,9 @@ namespace NifOsg // - if there are no vertex colors, we need to disable colorMode. // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them // above the actual renderable would be tedious. - std::vector materialProps; - collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags); + std::vector drawableProps; + collectDrawableProperties(triShape, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, !data->colors->empty(), animflags); } void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -1223,42 +1224,12 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: case Nif::RC_NiSpecularProperty: { - // Handled in handleTriShape so we know whether vertex colors are available + // Handled on drawable level so we know whether vertex colors are available break; } case Nif::RC_NiAlphaProperty: { - const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; - osg::StateSet* stateset = node->getOrCreateStateSet(); - if (alphaprop->flags&1) - { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); - - bool noSort = (alphaprop->flags>>13)&1; - if (!noSort) - { - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - } - } - else - { - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF); - stateset->setNestRenderBins(false); - stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); - } - - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; - if((alphaprop->flags>>9)&1) - { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); - } - else - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF); + // Handled on drawable level to prevent RenderBin nesting issues break; } case Nif::RC_NiTexturingProperty: @@ -1388,7 +1359,7 @@ namespace NifOsg } } - void applyMaterialProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, + void applyDrawableProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, bool hasVertexColors, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1444,6 +1415,43 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); break; } + break; + } + case Nif::RC_NiAlphaProperty: + { + const Nif::NiAlphaProperty* alphaprop = static_cast(property); + osg::BlendFunc* blendfunc = new osg::BlendFunc; + if (alphaprop->flags&1) + { + blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + + bool noSort = (alphaprop->flags>>13)&1; + if (!noSort) + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + else + stateset->setRenderBinToInherit(); + } + else + { + stateset->removeAttribute(osg::StateAttribute::BLENDFUNC); + stateset->removeMode(GL_BLEND); + stateset->setRenderBinToInherit(); + } + + osg::AlphaFunc* alphafunc = new osg::AlphaFunc; + if((alphaprop->flags>>9)&1) + { + alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); + stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + } + else + { + stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC); + stateset->removeMode(GL_ALPHA_TEST); + } + break; } } } From 6ef139e1d7de6f0a952009c523ccfc4ac9d20768 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Oct 2015 22:17:04 +0200 Subject: [PATCH 1167/1812] Implement a custom RenderBin for first person models (Fixes #1612) --- apps/openmw/mwrender/animation.cpp | 17 ++++++++-- apps/openmw/mwrender/animation.hpp | 3 ++ apps/openmw/mwrender/npcanimation.cpp | 48 +++++++++++++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 2 ++ apps/openmw/mwrender/renderbin.hpp | 9 ++--- 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a0704a59a2..b2fa873102 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1275,15 +1275,26 @@ namespace MWRender material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); - stateset->setNestRenderBins(false); mObjectRoot->setStateSet(stateset); } else { mObjectRoot->setStateSet(NULL); } + + setRenderBin(); + } + + void Animation::setRenderBin() + { + if (mAlpha != 1.f) + { + osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet(); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + } + else if (osg::StateSet* stateset = mObjectRoot->getStateSet()) + stateset->setRenderBinToInherit(); } void Animation::setLightEffect(float effect) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 94b792c0da..1e46cc71a5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -307,6 +307,9 @@ protected: void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); + /// Set the render bin for this animation's object root. May be customized by subclasses. + virtual void setRenderBin(); + public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 99ee886e16..cba6c56962 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,9 @@ #include #include +#include + +#include #include @@ -28,6 +31,7 @@ #include "camera.hpp" #include "rotatecontroller.hpp" +#include "renderbin.hpp" namespace { @@ -303,6 +307,50 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) mViewMode = viewMode; rebuild(); + + setRenderBin(); +} + +/// @brief A RenderBin callback to clear the depth buffer before rendering. +class DepthClearCallback : public osgUtil::RenderBin::DrawCallback +{ +public: + DepthClearCallback() + { + mDepth = new osg::Depth; + mDepth->setWriteMask(true); + } + + virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) + { + renderInfo.getState()->applyAttribute(mDepth); + + glClear(GL_DEPTH_BUFFER_BIT); + + bin->drawImplementation(renderInfo, previous); + } + + osg::ref_ptr mDepth; +}; + +void NpcAnimation::setRenderBin() +{ + if (mViewMode == VM_FirstPerson) + { + static bool prototypeAdded = false; + if (!prototypeAdded) + { + osg::ref_ptr depthClearBin (new osgUtil::RenderBin); + depthClearBin->setDrawCallback(new DepthClearCallback); + osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin); + prototypeAdded = true; + } + + osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet(); + stateset->setRenderBinDetails(RenderBin_FirstPerson, "DepthClear", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + } + else + Animation::setRenderBin(); } void NpcAnimation::rebuild() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 06f40f8475..b4272226d9 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -81,6 +81,8 @@ private: void addPartGroup(int group, int priority, const std::vector &parts, bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); + virtual void setRenderBin(); + osg::ref_ptr mFirstPersonNeckController; protected: diff --git a/apps/openmw/mwrender/renderbin.hpp b/apps/openmw/mwrender/renderbin.hpp index 63ccdd2599..c14f611426 100644 --- a/apps/openmw/mwrender/renderbin.hpp +++ b/apps/openmw/mwrender/renderbin.hpp @@ -5,14 +5,15 @@ namespace MWRender { /// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first. - /// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false). enum RenderBins { RenderBin_Sky = -1, - RenderBin_Default = 0, + RenderBin_Default = 0, // osg::StateSet::OPAQUE_BIN RenderBin_Water = 9, - RenderBin_OcclusionQuery = 10, - RenderBin_SunGlare = 11 + RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN + RenderBin_OcclusionQuery = 11, + RenderBin_FirstPerson = 12, + RenderBin_SunGlare = 13 }; } From 8552a9d82c8e9f01e9d843745664788f9d460976 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 01:58:22 +0200 Subject: [PATCH 1168/1812] Add multiple camera support to LightManager --- components/sceneutil/lightmanager.cpp | 56 ++++++++++++++------------- components/sceneutil/lightmanager.hpp | 16 +++++--- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 07ec0aff6c..77551e006d 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -126,15 +126,13 @@ namespace SceneUtil }; LightManager::LightManager() - : mLightsInViewSpace(false) - , mStartLight(0) + : mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); } LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) - , mLightsInViewSpace(false) , mStartLight(copy.mStartLight) { @@ -142,8 +140,8 @@ namespace SceneUtil void LightManager::update() { - mLightsInViewSpace = false; mLights.clear(); + mLightsInViewSpace.clear(); // do an occasional cleanup for orphaned lights if (mStateSetCache.size() > 5000) @@ -161,22 +159,6 @@ namespace SceneUtil mLights.push_back(l); } - void LightManager::prepareForCamera(osg::Camera *cam) - { - // later on we need to store this per camera - if (!mLightsInViewSpace) - { - for (std::vector::iterator it = mLights.begin(); it != mLights.end(); ++it) - { - LightSourceTransform& l = *it; - osg::Matrix worldViewMat = l.mWorldMatrix * cam->getViewMatrix(); - l.mViewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), l.mLightSource->getRadius()); - transformBoundingSphere(worldViewMat, l.mViewBound); - } - mLightsInViewSpace = true; - } - } - osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) { // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) @@ -212,6 +194,30 @@ namespace SceneUtil return mLights; } + const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera) + { + osg::observer_ptr camPtr (camera); + std::map, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr); + + if (it == mLightsInViewSpace.end()) + { + it = mLightsInViewSpace.insert(std::make_pair(camPtr, LightSourceViewBoundCollection())).first; + + for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) + { + osg::Matrix worldViewMat = lightIt->mWorldMatrix * camera->getViewMatrix(); + osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); + transformBoundingSphere(worldViewMat, viewBound); + + LightSourceViewBound l; + l.mLightSource = lightIt->mLightSource; + l.mViewBound = viewBound; + it->second.push_back(l); + } + } + return it->second; + } + void LightManager::setStartLight(int start) { mStartLight = start; @@ -241,7 +247,7 @@ namespace SceneUtil } - bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right) + bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right) { return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f; } @@ -273,13 +279,11 @@ namespace SceneUtil } } - mLightManager->prepareForCamera(cv->getCurrentCamera()); - // Possible optimizations: // - cull list of lights by the camera frustum // - organize lights in a quad tree - const std::vector& lights = mLightManager->getLights(); + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera()); if (lights.size()) { @@ -288,10 +292,10 @@ namespace SceneUtil osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - std::vector lightList; + LightManager::LightList lightList; for (unsigned int i=0; i& getLights() const; - typedef std::vector LightList; + struct LightSourceViewBound + { + LightSource* mLightSource; + osg::BoundingSphere mViewBound; + }; + + const std::vector& getLightsInViewSpace(osg::Camera* camera); + + typedef std::vector LightList; osg::ref_ptr getLightListStateSet(const LightList& lightList); @@ -98,7 +103,8 @@ namespace SceneUtil // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; - bool mLightsInViewSpace; + typedef std::vector LightSourceViewBoundCollection; + std::map, LightSourceViewBoundCollection> mLightsInViewSpace; // < Light list hash , StateSet > typedef std::map > LightStateSetMap; From 69f234d97b04f2263455a65c221c981f3482cb53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 16:50:08 +0200 Subject: [PATCH 1169/1812] Small delay before the loading screen shows Kinda irritating to have the loading bar pop up for a fraction of a second. --- apps/openmw/mwgui/loadingscreen.cpp | 84 ++++++++++++++++++----------- apps/openmw/mwgui/loadingscreen.hpp | 1 + 2 files changed, 55 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9b99ad7bf6..9afce68735 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -235,40 +235,64 @@ namespace MWGui draw(); } + bool LoadingScreen::needToDrawLoadingScreen() + { + if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + return false; + + // the minimal delay before a loading screen shows + const float initialDelay = 0.05; + + bool alreadyShown = (mLastRenderTime > mLoadingOnTime); + float diff = (mTimer.time_m() - mLoadingOnTime); + + if (!alreadyShown) + { + // bump the delay by the current progress - i.e. if during the initial delay the loading + // has almost finished, no point showing the loading screen now + diff -= mProgress / static_cast(mProgressBar->getScrollRange()) * 100.f; + } + + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + if (!showWallpaper && diff < initialDelay*1000) + return false; + return true; + } + void LoadingScreen::draw() { - if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + if (!needToDrawLoadingScreen()) + return; + + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) { - bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() - == MWBase::StateManager::State_NoGame); - - if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) - { - mLastWallpaperChangeTime = mTimer.time_m(); - changeWallpaper(); - } - - // Turn off rendering except the GUI - int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); - int oldCullMask = mViewer->getCamera()->getCullMask(); - mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); - mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); - - MWBase::Environment::get().getInputManager()->update(0, true, true); - - //osg::Timer timer; - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); - //std::cout << "frame took " << timer.time_m() << std::endl; - - //if (mViewer->getIncrementalCompileOperation()) - //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; - - // resume 3d rendering - mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); - mViewer->getCamera()->setCullMask(oldCullMask); - - mLastRenderTime = mTimer.time_m(); + mLastWallpaperChangeTime = mTimer.time_m(); + changeWallpaper(); } + + // Turn off rendering except the GUI + int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); + int oldCullMask = mViewer->getCamera()->getCullMask(); + mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); + mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); + + MWBase::Environment::get().getInputManager()->update(0, true, true); + + //osg::Timer timer; + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + //std::cout << "frame took " << timer.time_m() << std::endl; + + //if (mViewer->getIncrementalCompileOperation()) + //std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl; + + // resume 3d rendering + mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask); + mViewer->getCamera()->setCullMask(oldCullMask); + + mLastRenderTime = mTimer.time_m(); } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 194535eeed..f0f3542233 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -52,6 +52,7 @@ namespace MWGui private: void findSplashScreens(); + bool needToDrawLoadingScreen(); const VFS::Manager* mVFS; osg::ref_ptr mViewer; From 6dff11f8475c7dbc5aea5d7307e79d5e8d807e98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 18:16:26 +0200 Subject: [PATCH 1170/1812] Duplicate code fix --- components/sceneutil/lightmanager.cpp | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 77551e006d..92fa835374 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -64,6 +64,16 @@ namespace SceneUtil std::vector > mLights; }; + LightManager* findLightManager(const osg::NodePath& path) + { + for (unsigned int i=0;i(path[i])) + return lightManager; + } + return NULL; + } + // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -82,14 +92,8 @@ namespace SceneUtil { if (!mLightManager) { - for (unsigned int i=0;igetNodePath().size(); ++i) - { - if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) - { - mLightManager = lightManager; - break; - } - } + mLightManager = findLightManager(nv->getNodePath()); + if (!mLightManager) throw std::runtime_error("can't find parent LightManager"); } @@ -264,14 +268,7 @@ namespace SceneUtil if (!mLightManager) { - for (unsigned int i=0;igetNodePath().size(); ++i) - { - if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) - { - mLightManager = lightManager; - break; - } - } + mLightManager = findLightManager(nv->getNodePath()); if (!mLightManager) { traverse(node, nv); From 49df6b7450cc46e6d895d58d0a7a0701a5513f52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Oct 2015 21:25:56 +0200 Subject: [PATCH 1171/1812] LightManager: fix incorrect view matrix for RELATIVE_RF cameras --- components/sceneutil/lightmanager.cpp | 9 ++++++--- components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 92fa835374..18d7ddd46b 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -198,7 +198,7 @@ namespace SceneUtil return mLights; } - const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera) + const std::vector& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix) { osg::observer_ptr camPtr (camera); std::map, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr); @@ -209,7 +209,7 @@ namespace SceneUtil for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) { - osg::Matrix worldViewMat = lightIt->mWorldMatrix * camera->getViewMatrix(); + osg::Matrix worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); transformBoundingSphere(worldViewMat, viewBound); @@ -280,7 +280,10 @@ namespace SceneUtil // - cull list of lights by the camera frustum // - organize lights in a quad tree - const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera()); + // Don't use Camera::getViewMatrix, that one might be relative to another camera! + const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); + + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); if (lights.size()) { diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 454eeeefeb..3e0329c8bf 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -88,7 +88,7 @@ namespace SceneUtil osg::BoundingSphere mViewBound; }; - const std::vector& getLightsInViewSpace(osg::Camera* camera); + const std::vector& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix); typedef std::vector LightList; From ef5838df7eb70fb9eddeef448244171dac548caa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Oct 2015 15:46:15 +0200 Subject: [PATCH 1172/1812] SunGlareCallback: Fix incorrect view matrix for RELATIVE_RF cameras --- apps/openmw/mwrender/sky.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a8aeeb9307..8de8a61fc1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -741,7 +741,7 @@ private: { osgUtil::CullVisitor* cv = static_cast(nv); - float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); + float angleRadians = getAngleToSunInRadians(*cv->getCurrentRenderStage()->getInitialViewMatrix()); float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); const float angleMaxRadians = osg::DegreesToRadians(mSunGlareFaderAngleMax); @@ -784,10 +784,10 @@ private: } private: - float getAngleToSunInRadians(osg::Camera* camera) const + float getAngleToSunInRadians(const osg::Matrix& viewMatrix) const { osg::Vec3d eye, center, up; - camera->getViewMatrixAsLookAt(eye, center, up); + viewMatrix.getLookAt(eye, center, up); osg::Vec3d forward = center - eye; osg::Vec3d sun = mSunTransform->getPosition(); From 7b954e8cc30bbceb33bacfea42726694d40807ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Oct 2015 16:04:08 +0200 Subject: [PATCH 1173/1812] Remove unnecessary dependency on MWScrollBar --- apps/openmw/mwgui/waitdialog.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index e8f58c574d..13df1f8aec 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -8,11 +8,6 @@ namespace MWGui { - namespace Widgets - { - class MWScrollBar; - } - class WaitDialogProgressBar : public WindowBase { public: @@ -51,7 +46,7 @@ namespace MWGui MyGUI::Button* mUntilHealedButton; MyGUI::Button* mWaitButton; MyGUI::Button* mCancelButton; - MWGui::Widgets::MWScrollBar* mHourSlider; + MyGUI::ScrollBar* mHourSlider; TimeAdvancer mTimeAdvancer; bool mSleeping; From e34af4c4b5fe860c033dd4f55cd7aae0279d4bbc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Oct 2015 15:16:22 +0100 Subject: [PATCH 1174/1812] handle primary and secondary edit button clicks on cell arrows --- apps/opencs/view/render/cellarrow.cpp | 5 + apps/opencs/view/render/cellarrow.hpp | 2 + .../view/render/pagedworldspacewidget.cpp | 142 +++++++++++++++++- .../view/render/pagedworldspacewidget.hpp | 16 ++ apps/opencs/view/render/worldspacewidget.cpp | 21 ++- apps/opencs/view/render/worldspacewidget.hpp | 3 + 6 files changed, 177 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 720db53278..fce5ffda5c 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -154,3 +154,8 @@ CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const { return mCoordinates; } + +CSVRender::CellArrow::Direction CSVRender::CellArrow::getDirection() const +{ + return mDirection; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index 4422ec890f..cbbcc9d5ee 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -64,6 +64,8 @@ namespace CSVRender ~CellArrow(); CSMWorld::CellCoordinates getCoordinates() const; + + Direction getDirection() const; }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dd740ab9ae..6e5c2587d0 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -81,10 +82,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { if (mCells.find (*iter)==mCells.end()) { - Cell *cell = new Cell (mDocument.getData(), mRootNode, - iter->getId (mWorldspace)); - mCells.insert (std::make_pair (*iter, cell)); - + addCellToScene (*iter); modified = true; } } @@ -152,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + if (tag && tag->getElement()==Element_CellArrow) + { + if (button=="p-edit" || button=="s-edit") + { + if (CellArrowTag *cellArrowTag = + dynamic_cast (tag.get())) + { + CellArrow *arrow = cellArrowTag->getCellArrow(); + + CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); + + CellArrow::Direction direction = arrow->getDirection(); + + int x = 0; + int y = 0; + + switch (direction) + { + case CellArrow::Direction_North: y = 1; break; + case CellArrow::Direction_West: x = -1; break; + case CellArrow::Direction_South: y = -1; break; + case CellArrow::Direction_East: x = 1; break; + } + + bool modified = false; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + { + if (button=="p-edit") + addCellSelection (x, y); + else + moveCellSelection (x, y); + + modified = true; + } + else + { + CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); + + if (mCells.find (newCoordinates)==mCells.end()) + { + addCellToScene (newCoordinates); + mSelection.add (newCoordinates); + modified = true; + } + + if (button=="s-edit") + { + if (mCells.find (coordinates)!=mCells.end()) + { + removeCellFromScene (coordinates); + mSelection.remove (coordinates); + modified = true; + } + } + } + + if (modified) + adjustCells(); + + return; + } + } + } + + WorldspaceWidget::handleMouseClick (tag, button); +} + void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -231,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() return stream.str(); } +void CSVRender::PagedWorldspaceWidget::addCellToScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); + + int index = cells.searchId (coordinates.getId (mWorldspace)); + + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted); + + mCells.insert (std::make_pair (coordinates, cell)); +} + +void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + std::map::iterator iter = mCells.find (coordinates); + + if (iter!=mCells.end()) + { + delete iter->second; + mCells.erase (iter); + } +} + +void CSVRender::PagedWorldspaceWidget::addCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (mCells.find (*iter)==mCells.end()) + { + addCellToScene (*iter); + mSelection.add (*iter); + } + } +} + +void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); + ++iter) + { + if (!newSelection.has (*iter)) + removeCellFromScene (*iter); + } + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (!mSelection.has (*iter)) + addCellToScene (*iter); + } + + mSelection = newSelection; +} + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index d52efd90e4..e1a43ba7c5 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -53,6 +53,20 @@ namespace CSVRender virtual std::string getStartupInstruction(); + /// \note Does not update the view or any cell marker + void addCellToScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + /// + /// \note Calling this function for a cell that is not in the selection is a no-op. + void removeCellFromScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + void addCellSelection (int x, int y); + + /// \note Does not update the view or any cell marker + void moveCellSelection (int x, int y); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -88,6 +102,8 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 75dd800ebc..a542a3c592 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -574,14 +574,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - if (button=="p-edit") - editMode.primaryEditPressed (tag); - else if (button=="s-edit") - editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + handleMouseClick (tag, button); } } @@ -650,3 +643,15 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else RenderWidget::keyPressEvent(event); } + +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f5e7970b67..fe766cf87f 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -27,6 +27,7 @@ namespace CSVWidget namespace CSVRender { class TagBase; + class CellArrow; class WorldspaceWidget : public SceneWidget { @@ -132,6 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + private: void dragEnterEvent(QDragEnterEvent *event); From 515c52211e9bce049d6412e8e434ce7c907ca8ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 Oct 2015 18:28:50 +0100 Subject: [PATCH 1175/1812] Disable mipmaps for temporary screenshot texture --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f4b8aa451e..cae6541af1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -493,6 +493,8 @@ namespace MWRender texture->setInternalFormat(GL_RGB); texture->setTextureSize(w, h); texture->setResizeNonPowerOfTwoHint(false); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); rttCamera->attach(osg::Camera::COLOR_BUFFER, texture); image->setDataType(GL_UNSIGNED_BYTE); From 944e6d0844158d67c3a6041db1b29c4685ef2797 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 Oct 2015 14:25:44 +0100 Subject: [PATCH 1176/1812] Fix adjustment of inventory preview size when guimode changes (Fixes #2973) --- apps/openmw/mwgui/inventorywindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index f5a5f023f0..c1e202bc02 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -167,11 +167,12 @@ namespace MWGui MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); + mMainWidget->setPosition(pos); + mMainWidget->setSize(size); + if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) updatePreviewSize(); - mMainWidget->setPosition(pos); - mMainWidget->setSize(size); adjustPanes(); } From f3ee3f5be1d529698177655ebc6103a8f9847cde Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:25:46 +0100 Subject: [PATCH 1177/1812] Do not call base class event functions in WorldspaceWidget This avoids some event function being triggered twice. I do not fully understand why calling the base class function causes this problem, which is more than a bit disconcerting, but let's roll with it for now. --- apps/opencs/view/render/worldspacewidget.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a542a3c592..e539c14b92 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -555,8 +555,6 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) editMode.drag (diffX, diffY, factor); } - - RenderWidget::mouseMoveEvent(event); } void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) @@ -598,8 +596,6 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } mDragMode.clear(); - - RenderWidget::mouseReleaseEvent(event); } void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -608,7 +604,6 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { //mMouse->mouseDoubleClickEvent(event); } - //SceneWidget::mouseDoubleClickEvent(event); } void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) @@ -624,8 +619,6 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) editMode.dragWheel (event->delta(), factor); } - - RenderWidget::wheelEvent(event); } void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) From d2e92fd36f8bd6bb54724abf36acd918edcf6875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:30:51 +0100 Subject: [PATCH 1178/1812] trigger mouse click actions on release instead of on press (avoids problems with dragging) --- apps/opencs/view/render/worldspacewidget.cpp | 28 +++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e539c14b92..3f4b773835 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -563,25 +563,14 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) if (!mDragging) mDragMode = button; - - if (button=="p-navi" || button=="s-navi") - { - - } - else if (button=="p-edit" || button=="s-edit" || button=="select") - { - osg::ref_ptr tag = mousePick (event); - - handleMouseClick (tag, button); - } } void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { + std::string button = mapButton (event); + if (mDragging) { - std::string button = mapButton (event); - if (mDragMode=="p-navi" || mDragMode=="s-navi") { @@ -594,6 +583,19 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) mDragging = false; } } + else + { + if (button=="p-navi" || button=="s-navi") + { + + } + else if (button=="p-edit" || button=="s-edit" || button=="select") + { + osg::ref_ptr tag = mousePick (event); + + handleMouseClick (tag, button); + } + } mDragMode.clear(); } From 843225996cc4d8573be7d4a70b71333ab2baf319 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Oct 2015 15:43:52 +0100 Subject: [PATCH 1179/1812] get modifiers from event instead of from the application --- apps/opencs/view/render/pagedworldspacewidget.cpp | 6 +++--- apps/opencs/view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 10 +++++----- apps/opencs/view/render/worldspacewidget.hpp | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 6e5c2587d0..dae5990e6f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -150,7 +150,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift) { if (tag && tag->getElement()==Element_CellArrow) { @@ -178,7 +178,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr t bool modified = false; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (shift) { if (button=="p-edit") addCellSelection (x, y); @@ -217,7 +217,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr t } } - WorldspaceWidget::handleMouseClick (tag, button); + WorldspaceWidget::handleMouseClick (tag, button, shift); } void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e1a43ba7c5..e983fddd55 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -102,7 +102,7 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift); signals: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3f4b773835..46c5867ebf 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -413,7 +413,7 @@ osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseE std::string CSVRender::WorldspaceWidget::mapButton (QMouseEvent *event) { std::pair phyiscal ( - event->button(), QApplication::keyboardModifiers() & Qt::ControlModifier); + event->button(), event->modifiers() & Qt::ControlModifier); std::map, std::string>::const_iterator iter = mButtonMapping.find (phyiscal); @@ -548,7 +548,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) double factor = mDragFactor; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (event->modifiers() & Qt::ShiftModifier) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -593,7 +593,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - handleMouseClick (tag, button); + handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier); } } @@ -614,7 +614,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { double factor = mDragWheelFactor; - if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + if (event->modifiers() & Qt::ShiftModifier) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -639,7 +639,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) RenderWidget::keyPressEvent(event); } -void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index fe766cf87f..c2d61e75be 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -133,7 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); - virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, + bool shift); private: From 9f0e059a15106eb5fa8f1174eadd91076623e7d3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:18:48 +1100 Subject: [PATCH 1180/1812] Fix editing ingredient effects sub-table. Should resolve bug #2978. --- apps/opencs/model/world/refidadapterimp.cpp | 127 ++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 60 +++++++++ apps/opencs/model/world/refidcollection.cpp | 17 ++- 3 files changed, 203 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index da0cc07600..d4fa91bd5e 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -52,6 +52,133 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData } +CSMWorld::IngredientColumns::IngredientColumns (const InventoryColumns& columns) +: InventoryColumns (columns) {} + +CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumns& columns) +: InventoryRefIdAdapter (UniversalId::Type_Ingredient, columns), + mColumns(columns) +{} + +QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, + int index) const +{ + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); + + if (column==mColumns.mEffects) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + + return InventoryRefIdAdapter::getData (column, data, index); +} + +void CSMWorld::IngredientRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const +{ + InventoryRefIdAdapter::setData (column, data, index, value); + + return; +} + + +CSMWorld::IngredEffectRefIdAdapter::IngredEffectRefIdAdapter() +: mType(UniversalId::Type_Ingredient) +{} + +CSMWorld::IngredEffectRefIdAdapter::~IngredEffectRefIdAdapter() +{} + +void CSMWorld::IngredEffectRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::IngredEffectRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::IngredEffectRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESM::Ingredient ingredient = record.get(); + + ingredient.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (ingredient); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::IngredEffectRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + if (subRowIndex < 0 || subRowIndex >= 4) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return record.get().mData.mEffectID[subRowIndex]; + case 1: return record.get().mData.mSkills[subRowIndex]; + case 2: return record.get().mData.mAttributes[subRowIndex]; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } +} + +void CSMWorld::IngredEffectRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESM::Ingredient ingredient = record.get(); + + if (subRowIndex < 0 || subRowIndex >= 4) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: ingredient.mData.mEffectID[subRowIndex] = value.toInt(); break; + case 1: ingredient.mData.mSkills[subRowIndex] = value.toInt(); break; + case 2: ingredient.mData.mAttributes[subRowIndex] = value.toInt(); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (ingredient); +} + +int CSMWorld::IngredEffectRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 3; // effect, skill, attribute +} + +int CSMWorld::IngredEffectRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 4; // up to 4 effects +} + + CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *type, const RefIdColumn *quality) : InventoryRefIdAdapter (UniversalId::Type_Apparatus, columns), diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4ac27b6e90..93d4ce8940 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -340,6 +340,66 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; + struct IngredientColumns : public InventoryColumns + { + const RefIdColumn *mEffects; + + IngredientColumns (const InventoryColumns& columns); + }; + + class IngredientRefIdAdapter : public InventoryRefIdAdapter + { + IngredientColumns mColumns; + + public: + + IngredientRefIdAdapter (const IngredientColumns& columns); + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) + const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const; + ///< If the data type does not match an exception is thrown. + }; + + class IngredEffectRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + IngredEffectRefIdAdapter (const IngredEffectRefIdAdapter&); + IngredEffectRefIdAdapter& operator= (const IngredEffectRefIdAdapter&); + + public: + + IngredEffectRefIdAdapter(); + + virtual ~IngredEffectRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + struct EnchantableColumns : public InventoryColumns { const RefIdColumn *mEnchantment; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3b316bea3a..76694027b5 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -71,6 +71,21 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)); inventoryColumns.mValue = &mColumns.back(); + IngredientColumns ingredientColumns (inventoryColumns); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + ingredientColumns.mEffects = &mColumns.back(); + std::map ingredientEffectsMap; + ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient, + new IngredEffectRefIdAdapter ())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + // nested table PotionColumns potionColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, @@ -651,7 +666,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Door, new DoorRefIdAdapter (nameColumns, openSound, closeSound))); mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient, - new InventoryRefIdAdapter (UniversalId::Type_Ingredient, inventoryColumns))); + new IngredientRefIdAdapter (ingredientColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList, new LevelledListRefIdAdapter ( UniversalId::Type_CreatureLevelledList, levListColumns))); From 1a64b4072570e09a75e2ac250576589244ed8a3e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:30:36 +1100 Subject: [PATCH 1181/1812] Fix skills and attributes being possible to add to irrelevant effects. Should resolve bug #2980. --- .../model/world/nestedcoladapterimp.hpp | 30 +++++++++++++++++-- apps/opencs/model/world/refidadapterimp.cpp | 30 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 81c52588bb..2fd569bd0d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -317,8 +317,34 @@ namespace CSMWorld else throw std::runtime_error("Magic effects ID unexpected value"); } - case 1: return effect.mSkill; - case 2: return effect.mAttribute; + case 1: + { + switch (effect.mEffectID) + { + case ESM::MagicEffect::DrainSkill: + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::AbsorbSkill: + return effect.mSkill; + default: + return QVariant(); + } + } + case 2: + { + switch (effect.mEffectID) + { + case ESM::MagicEffect::DrainAttribute: + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::RestoreAttribute: + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::AbsorbAttribute: + return effect.mAttribute; + default: + return QVariant(); + } + } case 3: { if (effect.mRange >=0 && effect.mRange <=2) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d4fa91bd5e..319c6ef5a6 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -139,8 +139,34 @@ QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData (const RefIdColumn *c switch (subColIndex) { case 0: return record.get().mData.mEffectID[subRowIndex]; - case 1: return record.get().mData.mSkills[subRowIndex]; - case 2: return record.get().mData.mAttributes[subRowIndex]; + case 1: + { + switch (record.get().mData.mEffectID[subRowIndex]) + { + case ESM::MagicEffect::DrainSkill: + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::AbsorbSkill: + return record.get().mData.mSkills[subRowIndex]; + default: + return QVariant(); + } + } + case 2: + { + switch (record.get().mData.mEffectID[subRowIndex]) + { + case ESM::MagicEffect::DrainAttribute: + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::RestoreAttribute: + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::AbsorbAttribute: + return record.get().mData.mAttributes[subRowIndex]; + default: + return QVariant(); + } + } default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } From 972193c7ebcb597dfdd5b38e72965efa1bb4e70f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:49:24 +1100 Subject: [PATCH 1182/1812] Fix issue where mandatory effects field was allowed to be empty (and vice versa) --- apps/opencs/model/world/columnbase.cpp | 4 ++++ apps/opencs/model/world/columnbase.hpp | 4 ++++ apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 10 +++++----- apps/opencs/view/doc/viewmanager.cpp | 3 +++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 39232d4423..1f16c9695b 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -86,6 +86,10 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondVar, Display_InfoCondComp, + Display_EffectSkill, + Display_EffectAttribute, + Display_IngredEffectId, + Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index e2871d4d85..67d79fdbee 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -124,6 +124,10 @@ namespace CSMWorld Display_String32, Display_LongString256, + Display_EffectSkill, // must display at least one, unlike Display_Skill + Display_EffectAttribute, // must display at least one, unlike Display_Attribute + Display_IngredEffectId, // display none allowed, unlike Display_EffectId + //top level columns that nest other columns Display_NestedHeader }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8acdac84fd..b75bd54e1f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -213,9 +213,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( @@ -329,9 +329,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 76694027b5..337580fad3 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -80,11 +80,11 @@ CSMWorld::RefIdCollection::RefIdCollection() new IngredEffectRefIdAdapter ())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); // nested table PotionColumns potionColumns (inventoryColumns); @@ -98,9 +98,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 728e69a7a6..116febae44 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -104,6 +104,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, + { CSMWorld::ColumnBase::Display_IngredEffectId, CSMWorld::Columns::ColumnId_EffectId, true }, + { CSMWorld::ColumnBase::Display_EffectSkill, CSMWorld::Columns::ColumnId_Skill, false }, + { CSMWorld::ColumnBase::Display_EffectAttribute, CSMWorld::Columns::ColumnId_Attribute, false }, }; for (std::size_t i=0; i Date: Wed, 28 Oct 2015 20:30:30 +1100 Subject: [PATCH 1183/1812] Disable context menu for fixed size sub-tables. Should resolve bug #2932. --- apps/opencs/model/world/columnbase.hpp | 22 +++++++++-- apps/opencs/model/world/data.cpp | 6 ++- apps/opencs/model/world/refidadapterimp.cpp | 23 ++++++------ apps/opencs/view/world/dialoguesubview.cpp | 19 ++++++++-- apps/opencs/view/world/nestedtable.cpp | 41 +++++++++++++++------ apps/opencs/view/world/nestedtable.hpp | 4 +- 6 files changed, 82 insertions(+), 33 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 67d79fdbee..c40bd9663d 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -12,6 +12,13 @@ namespace CSMWorld { + enum TableEditModes + { + TableEdit_None, // no editing + TableEdit_Full, // edit cells and add/remove rows + TableEdit_FixedRows // edit cells only + }; + struct ColumnBase { enum Roles @@ -190,8 +197,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, - ColumnBase::Display_NestedHeader, flags) + NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue, bool fixedRows = false) + : Column (id, ColumnBase::Display_NestedHeader, flags), mFixedRows(fixedRows) {} virtual void set (Record& record, const QVariant& data) @@ -202,13 +209,20 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return true; // required by IdTree::hasChildren() + // by default editable; also see IdTree::hasChildren() + if (mFixedRows) + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + else + return QVariant::fromValue(TableEditModes::TableEdit_Full); } virtual bool isEditable() const { return true; } + + Private: + bool mFixedRows; }; struct NestedChildColumn : public NestableColumn @@ -223,4 +237,6 @@ namespace CSMWorld }; } +Q_DECLARE_METATYPE(CSMWorld::TableEditModes) + #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b75bd54e1f..bfdab0675f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -136,7 +136,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes, + ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( @@ -147,7 +148,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer)); // Race skill bonus - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus, + ColumnBase::Flag_Dialogue, true)); // fixed rows table index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 319c6ef5a6..369a349b50 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -25,8 +25,9 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const if (column==mAutoCalc) return record.get().mData.mAutoCalc!=0; + // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mColumns.mEffects) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return InventoryRefIdAdapter::getData (column, data, index); } @@ -67,7 +68,7 @@ QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, c data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); if (column==mColumns.mEffects) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); return InventoryRefIdAdapter::getData (column, data, index); } @@ -271,7 +272,7 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mArmor; if (column==mPartRef) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -359,7 +360,7 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mType; if (column==mPartRef) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(TableEditModes::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -407,7 +408,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_Full); return NameRefIdAdapter::getData (column, data, index); } @@ -476,13 +477,13 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con return QString::fromUtf8 (record.get().mOriginal.c_str()); if (column==mColumns.mAttributes) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); if (column==mColumns.mAttacks) - return true; // Required to show nested tables in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); if (column==mColumns.mMisc) - return true; // Required to show nested items in dialogue subview + return QVariant::fromValue(TableEditModes::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -722,13 +723,13 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant(QVariant::UserType); + return QVariant::fromValue(TableEditModes::TableEdit_None); else - return true; + return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); } if (column==mColumns.mMisc) - return true; + return QVariant::fromValue(TableEditModes::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 7402f62eec..cdc50a0c64 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -564,10 +564,21 @@ void CSVWorld::EditWidget::remake(int row) static_cast (mTable->data (mTable->index (row, typeColumn)).toInt()), mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData()); - NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); - table->resizeColumnsToContents(); + bool editable = true; + bool fixedRows = false; + QVariant v = mTable->index(row, i).data(); + if (v.canConvert()) + { + assert (QString(v.typeName()) == "CSMWorld::TableEditModes"); - if(mTable->index(row, i).data().type() == QVariant::UserType) + if (v.value() == CSMWorld::TableEditModes::TableEdit_None) + editable = false; + else if (v.value() == CSMWorld::TableEditModes::TableEdit_FixedRows) + fixedRows = true; + } + + NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + if (!editable) { table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->setEnabled(false); @@ -583,7 +594,7 @@ void CSVWorld::EditWidget::remake(int row) new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); - if(mTable->index(row, i).data().type() == QVariant::UserType) + if(!editable) label->setEnabled(false); tablesLayout->addWidget(label); diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 0876b2ce78..23d5664396 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -16,8 +16,13 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, - QWidget* parent) + QWidget* parent, + bool editable, + bool fixedRows) : DragRecordTable(document, parent), + mAddNewRowAction(NULL), + mRemoveRowAction(NULL), + mEditIdAction(NULL), mModel(model) { mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); @@ -49,18 +54,24 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, setModel(model); - mAddNewRowAction = new QAction (tr ("Add new row"), this); + if (editable) + { + if (!fixedRows) + { + mAddNewRowAction = new QAction (tr ("Add new row"), this); - connect(mAddNewRowAction, SIGNAL(triggered()), - this, SLOT(addNewRowActionTriggered())); + connect(mAddNewRowAction, SIGNAL(triggered()), + this, SLOT(addNewRowActionTriggered())); - mRemoveRowAction = new QAction (tr ("Remove row"), this); + mRemoveRowAction = new QAction (tr ("Remove row"), this); - connect(mRemoveRowAction, SIGNAL(triggered()), - this, SLOT(removeRowActionTriggered())); + connect(mRemoveRowAction, SIGNAL(triggered()), + this, SLOT(removeRowActionTriggered())); + } - mEditIdAction = new TableEditIdAction(*this, this); - connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); + mEditIdAction = new TableEditIdAction(*this, this); + connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell())); + } } std::vector CSVWorld::NestedTable::getDraggedRecords() const @@ -71,6 +82,9 @@ std::vector CSVWorld::NestedTable::getDraggedRecords() co void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { + if (!mEditIdAction) + return; + QModelIndexList selectedRows = selectionModel()->selectedRows(); QMenu menu(this); @@ -84,10 +98,13 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) menu.addSeparator(); } - if (selectionModel()->selectedRows().size() == 1) - menu.addAction(mRemoveRowAction); + if (mAddNewRowAction && mRemoveRowAction) + { + if (selectionModel()->selectedRows().size() == 1) + menu.addAction(mRemoveRowAction); - menu.addAction(mAddNewRowAction); + menu.addAction(mAddNewRowAction); + } menu.exec (event->globalPos()); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index ba8b6c0e32..765060ea5b 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -38,7 +38,9 @@ namespace CSVWorld NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, - QWidget* parent = NULL); + QWidget* parent = NULL, + bool editable = true, + bool fixedRows = false); virtual std::vector getDraggedRecords() const; From 77471d1592611fe08b65e6b34b7e656d78753944 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 20:52:07 +1100 Subject: [PATCH 1184/1812] Re-add mistakenly removed line and fix a silly typo. --- apps/opencs/model/world/columnbase.hpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c40bd9663d..8a0a706448 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -221,7 +221,7 @@ namespace CSMWorld return true; } - Private: + private: bool mFixedRows; }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index cdc50a0c64..28a1942e05 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -577,7 +577,9 @@ void CSVWorld::EditWidget::remake(int row) fixedRows = true; } - NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + NestedTable* table = + new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows); + table->resizeColumnsToContents(); if (!editable) { table->setEditTriggers(QAbstractItemView::NoEditTriggers); From 107ccd84d4f411a825c2f095bae7f84e65f8609d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 23:33:24 +1100 Subject: [PATCH 1185/1812] Move TableEditModes enum inside a class scope. --- apps/opencs/model/world/columnbase.hpp | 20 +++++++-------- apps/opencs/model/world/refidadapterimp.cpp | 28 ++++++++++----------- apps/opencs/view/world/dialoguesubview.cpp | 8 +++--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 8a0a706448..c75a3c2a12 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -12,15 +12,15 @@ namespace CSMWorld { - enum TableEditModes - { - TableEdit_None, // no editing - TableEdit_Full, // edit cells and add/remove rows - TableEdit_FixedRows // edit cells only - }; - struct ColumnBase { + enum TableEditModes + { + TableEdit_None, // no editing + TableEdit_Full, // edit cells and add/remove rows + TableEdit_FixedRows // edit cells only + }; + enum Roles { Role_Flags = Qt::UserRole, @@ -211,9 +211,9 @@ namespace CSMWorld { // by default editable; also see IdTree::hasChildren() if (mFixedRows) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); else - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); } virtual bool isEditable() const @@ -237,6 +237,6 @@ namespace CSMWorld }; } -Q_DECLARE_METATYPE(CSMWorld::TableEditModes) +Q_DECLARE_METATYPE(CSMWorld::ColumnBase::TableEditModes) #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 369a349b50..860fc9bdf5 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -5,6 +5,9 @@ #include #include +#include + +#include "columnbase.hpp" #include "nestedtablewrapper.hpp" CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) @@ -27,7 +30,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mColumns.mEffects) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return InventoryRefIdAdapter::getData (column, data, index); } @@ -64,11 +67,8 @@ CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumn QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { - const Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Ingredient))); - if (column==mColumns.mEffects) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); return InventoryRefIdAdapter::getData (column, data, index); } @@ -272,7 +272,7 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mArmor; if (column==mPartRef) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -360,7 +360,7 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, return record.get().mData.mType; if (column==mPartRef) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return EnchantableRefIdAdapter::getData (column, data, index); } @@ -408,7 +408,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); return NameRefIdAdapter::getData (column, data, index); } @@ -477,13 +477,13 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con return QString::fromUtf8 (record.get().mOriginal.c_str()); if (column==mColumns.mAttributes) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); if (column==mColumns.mAttacks) - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); if (column==mColumns.mMisc) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -723,13 +723,13 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant::fromValue(TableEditModes::TableEdit_None); + return QVariant::fromValue(ColumnBase::TableEdit_None); else - return QVariant::fromValue(TableEditModes::TableEdit_FixedRows); + return QVariant::fromValue(ColumnBase::TableEdit_FixedRows); } if (column==mColumns.mMisc) - return QVariant::fromValue(TableEditModes::TableEdit_Full); + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 28a1942e05..61d3fb1caa 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -567,13 +567,13 @@ void CSVWorld::EditWidget::remake(int row) bool editable = true; bool fixedRows = false; QVariant v = mTable->index(row, i).data(); - if (v.canConvert()) + if (v.canConvert()) { - assert (QString(v.typeName()) == "CSMWorld::TableEditModes"); + assert (QString(v.typeName()) == "CSMWorld::ColumnBase::TableEditModes"); - if (v.value() == CSMWorld::TableEditModes::TableEdit_None) + if (v.value() == CSMWorld::ColumnBase::TableEdit_None) editable = false; - else if (v.value() == CSMWorld::TableEditModes::TableEdit_FixedRows) + else if (v.value() == CSMWorld::ColumnBase::TableEdit_FixedRows) fixedRows = true; } From e13eb625d38a13b47d1b6680608c69c20de6842a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 Oct 2015 21:36:19 +0100 Subject: [PATCH 1186/1812] New water WIP Changes compared to old (Ogre) water: - Uses depth-texture readback to handle the underwater fog in the water shader, instead of handling it in the object shader - Different clipping mechanism (glClipPlane instead of a skewed viewing frustum) - Fixed bug where the reflection camera would look strange when the viewer was very close to the water surface - Toned down light scattering, made the waterColor a bit darker at night - Fixed flipped water normals and strange resulting logic in the shader Still to do: see comments... --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 6 +- apps/openmw/mwrender/renderingmanager.cpp | 39 ++- apps/openmw/mwrender/renderingmanager.hpp | 3 +- apps/openmw/mwrender/sky.cpp | 53 +++- apps/openmw/mwrender/vismask.hpp | 9 +- apps/openmw/mwrender/water.cpp | 311 +++++++++++++++++++++- apps/openmw/mwrender/water.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 2 +- files/CMakeLists.txt | 1 + files/shaders/CMakeLists.txt | 11 + files/shaders/water_fragment.glsl | 189 +++++++++++++ files/shaders/water_nm.png | Bin 0 -> 24405 bytes files/shaders/water_vertex.glsl | 22 ++ 15 files changed, 642 insertions(+), 19 deletions(-) create mode 100644 files/shaders/CMakeLists.txt create mode 100644 files/shaders/water_fragment.glsl create mode 100644 files/shaders/water_nm.png create mode 100644 files/shaders/water_vertex.glsl diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 79c8c4cc98..089880fb26 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -513,7 +513,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create the world mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, - mActivationDistanceOverride, mCellName, mStartupScript)); + mActivationDistanceOverride, mCellName, mStartupScript, mResDir.string())); mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cba6c56962..17f0ce73c0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -32,6 +32,7 @@ #include "camera.hpp" #include "rotatecontroller.hpp" #include "renderbin.hpp" +#include "vismask.hpp" namespace { @@ -323,9 +324,9 @@ public: virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) { - renderInfo.getState()->applyAttribute(mDepth); + //renderInfo.getState()->applyAttribute(mDepth); - glClear(GL_DEPTH_BUFFER_BIT); + //glClear(GL_DEPTH_BUFFER_BIT); bin->drawImplementation(renderInfo, previous); } @@ -441,6 +442,7 @@ void NpcAnimation::updateNpcBase() } else { + mObjectRoot->setNodeMask(Mask_FirstPerson); if(isWerewolf) addAnimSource(smodel); else diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cae6541af1..2aaba30356 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -122,7 +122,8 @@ namespace MWRender bool mWireframe; }; - RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback) + RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, + const MWWorld::Fallback* fallback, const std::string& resourcePath) : mViewer(viewer) , mRootNode(rootNode) , mResourceSystem(resourceSystem) @@ -145,7 +146,7 @@ namespace MWRender mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); - mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback)); + mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); @@ -197,6 +198,39 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + + /* + osg::Texture2D* texture = new osg::Texture2D; + texture->setSourceFormat(GL_DEPTH_COMPONENT); + texture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + texture->setSourceType(GL_UNSIGNED_INT); + + mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, texture); + + osg::ref_ptr camera (new osg::Camera); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setViewMatrix(osg::Matrix::identity()); + camera->setClearMask(0); + camera->setRenderOrder(osg::Camera::NESTED_RENDER); + camera->setAllowEventFocus(false); + + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(0.5,0,0), osg::Vec3f(0,0.5,0)); + geode->addDrawable(geom); + + camera->addChild(geode); + + osg::StateSet* stateset = geom->getOrCreateStateSet(); + + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + stateset->setRenderBinDetails(20, "RenderBin"); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + mLightRoot->addChild(camera); + */ } RenderingManager::~RenderingManager() @@ -260,6 +294,7 @@ namespace MWRender { // need to wrap this in a StateUpdater? mSunLight->setDiffuse(colour); + mSunLight->setSpecular(colour); } void RenderingManager::setSunDirection(const osg::Vec3f &direction) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index def3ea4bba..1ddab73387 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -57,7 +57,8 @@ namespace MWRender class RenderingManager : public MWRender::RenderingInterface { public: - RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback); + RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem, + const MWWorld::Fallback* fallback, const std::string& resourcePath); ~RenderingManager(); MWRender::Objects& getObjects(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8de8a61fc1..30dc089895 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,6 +1,9 @@ #include "sky.hpp" #include +#include + +#include #include #include @@ -250,6 +253,8 @@ public: // That's not a problem though, children of this node can be culled just fine // Just make sure you do not place a CameraRelativeTransform deep in the scene graph setCullingActive(false); + + addCullCallback(new CullCallback); } CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) @@ -259,7 +264,7 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const { if (_referenceFrame==RELATIVE_RF) { @@ -277,6 +282,48 @@ public: { return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); } + + class CullCallback : public osg::NodeCallback + { + public: + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + // XXX have to remove unwanted culling plane of the water reflection camera + + // Remove all planes that aren't from the standard frustum + unsigned int numPlanes = 4; + if (cv->getCullingMode() & osg::CullSettings::NEAR_PLANE_CULLING) + ++numPlanes; + if (cv->getCullingMode() & osg::CullSettings::FAR_PLANE_CULLING) + ++numPlanes; + + int mask = 0x1; + int resultMask = cv->getProjectionCullingStack().back().getFrustum().getResultMask(); + for (unsigned int i=0; igetProjectionCullingStack().back().getFrustum().getPlaneList().size(); ++i) + { + if (i >= numPlanes) + { + // turn off this culling plane + resultMask &= (~mask); + } + + mask <<= 1; + } + + cv->getProjectionCullingStack().back().getFrustum().setResultMask(resultMask); + cv->getCurrentCullingSet().getFrustum().setResultMask(resultMask); + + cv->getProjectionCullingStack().back().pushCurrentMask(); + cv->getCurrentCullingSet().pushCurrentMask(); + + traverse(node, nv); + + cv->getProjectionCullingStack().back().popCurrentMask(); + cv->getCurrentCullingSet().popCurrentMask(); + } + }; }; class ModVertexAlphaVisitor : public osg::NodeVisitor @@ -1014,6 +1061,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSunEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); @@ -1021,6 +1069,9 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // By default render before the world is rendered mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); + + // Prevent unwanted clipping by water reflection camera's clipping plane + mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); } void SkyManager::create() diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 38fcfe6487..fc63cddbb9 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -17,16 +17,17 @@ namespace MWRender Mask_Sky = (1<<5), Mask_Water = (1<<6), Mask_Terrain = (1<<7), + Mask_FirstPerson = (1<<8), // top level masks - Mask_Scene = (1<<8), - Mask_GUI = (1<<9), + Mask_Scene = (1<<9), + Mask_GUI = (1<<10), // Set on a Geode - Mask_ParticleSystem = (1<<10), + Mask_ParticleSystem = (1<<11), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<11) + Mask_RenderToTexture = (1<<12) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 03ab58e6be..cf361a5046 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,14 +2,24 @@ #include +#include + +#include #include #include #include #include #include #include +#include +#include +#include +#include + +#include // XXX remove #include +#include #include #include @@ -17,6 +27,8 @@ #include #include +#include + #include #include "vismask.hpp" @@ -69,7 +81,7 @@ namespace return waterGeom; } - void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) + void createSimpleWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) { osg::ref_ptr stateset (new osg::StateSet); @@ -111,8 +123,152 @@ namespace MWRender // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback) +/// @brief Allows to cull and clip meshes that are below a plane. Useful for reflection & refraction camera effects. +/// Also handles flipping of the plane when the eye point goes below it. +/// To use, simply create the scene as subgraph of this node, then do setPlane(const osg::Plane& plane); +class ClipCullNode : public osg::Group +{ + class PlaneCullCallback : public osg::NodeCallback + { + public: + /// @param cullPlane The culling plane (in world space). + PlaneCullCallback(const osg::Plane* cullPlane) + : osg::NodeCallback() + , mCullPlane(cullPlane) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + osg::Polytope::PlaneList origPlaneList = cv->getProjectionCullingStack().back().getFrustum().getPlaneList(); + + // TODO: offset plane towards the viewer to fix bleeding at the water shore + + osg::Plane plane = *mCullPlane; + plane.transform(*cv->getCurrentRenderStage()->getInitialViewMatrix()); + + osg::Vec3d eyePoint = cv->getEyePoint(); + if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) + plane.flip(); + + cv->getProjectionCullingStack().back().getFrustum().add(plane); + + traverse(node, nv); + + // undo + cv->getProjectionCullingStack().back().getFrustum().set(origPlaneList); + } + + private: + const osg::Plane* mCullPlane; + }; + + class FlipCallback : public osg::NodeCallback + { + public: + FlipCallback(const osg::Plane* cullPlane) + : mCullPlane(cullPlane) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + osg::Vec3d eyePoint = cv->getEyePoint(); + // flip the below graph if the eye point is above the plane + if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) + { + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); + } + else + traverse(node, nv); + } + + private: + const osg::Plane* mCullPlane; + }; + +public: + ClipCullNode() + { + addCullCallback (new PlaneCullCallback(&mPlane)); + + mClipNodeTransform = new osg::PositionAttitudeTransform; + mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); + addChild(mClipNodeTransform); + + mClipNode = new osg::ClipNode; + + mClipNodeTransform->addChild(mClipNode); + } + + void setPlane (const osg::Plane& plane) + { + if (plane == mPlane) + return; + mPlane = plane; + + mClipNode->getClipPlaneList().clear(); + mClipNode->addClipPlane(new osg::ClipPlane(0, mPlane)); + mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); + } + +private: + osg::ref_ptr mClipNodeTransform; + osg::ref_ptr mClipNode; + + osg::Plane mPlane; +}; + +// Node callback to entirely skip the traversal. +class NoTraverseCallback : public osg::NodeCallback +{ +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + // no traverse() + } +}; + +void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) +{ + osg::ref_ptr debugCamera (new osg::Camera); + debugCamera->setProjectionMatrix(osg::Matrix::identity()); + debugCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + debugCamera->setViewMatrix(osg::Matrix::identity()); + debugCamera->setClearMask(0); + debugCamera->setRenderOrder(osg::Camera::NESTED_RENDER); + debugCamera->setAllowEventFocus(false); + + const float size = 0.5; + osg::ref_ptr debugGeode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1 + size*pos, -1, 0), osg::Vec3f(size,0,0), osg::Vec3f(0,size,0)); + debugGeode->addDrawable(geom); + + debugCamera->addChild(debugGeode); + + osg::StateSet* debugStateset = geom->getOrCreateStateSet(); + + debugStateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + debugStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + debugStateset->setRenderBinDetails(20, "RenderBin"); + debugStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + parent->addChild(debugCamera); +} + +Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, + const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) + , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) , mEnabled(true) , mToggled(true) @@ -126,17 +282,164 @@ Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUt geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); + // TODO: node mask to use simple water for local map + if (ico) ico->add(geode); - createWaterStateSet(mResourceSystem, geode); + //createSimpleWaterStateSet(mResourceSystem, geode); mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(geode); - mParent->addChild(mWaterNode); + mSceneRoot->addChild(mWaterNode); setHeight(mTop); + + const float waterLevel = -1; + + // refraction + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + osg::ref_ptr refractionCamera (new osg::Camera); + refractionCamera->setRenderOrder(osg::Camera::PRE_RENDER); + refractionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + refractionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + refractionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); + + refractionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + refractionCamera->setNodeMask(Mask_RenderToTexture); + refractionCamera->setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + refractionCamera->setUpdateCallback(new NoTraverseCallback); + + // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog + refractionCamera->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr clipNode (new ClipCullNode); + clipNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); + + refractionCamera->addChild(clipNode); + clipNode->addChild(mSceneRoot); + + // TODO: add ingame setting for texture quality + + osg::ref_ptr refractionTexture = new osg::Texture2D; + refractionTexture->setTextureSize(rttSize, rttSize); + refractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + refractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + refractionTexture->setInternalFormat(GL_RGB); + refractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + refractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + refractionCamera->attach(osg::Camera::COLOR_BUFFER, refractionTexture); + + osg::ref_ptr refractionDepthTexture = new osg::Texture2D; + refractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); + refractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + refractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + refractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + refractionDepthTexture->setSourceType(GL_UNSIGNED_INT); + refractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + refractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + refractionCamera->attach(osg::Camera::DEPTH_BUFFER, refractionDepthTexture); + + mParent->addChild(refractionCamera); + + // reflection + osg::ref_ptr reflectionCamera (new osg::Camera); + reflectionCamera->setRenderOrder(osg::Camera::PRE_RENDER); + reflectionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + reflectionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + reflectionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); + + reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + reflectionCamera->setNodeMask(Mask_RenderToTexture); + + reflectionCamera->setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + reflectionCamera->setUpdateCallback(new NoTraverseCallback); + + osg::ref_ptr reflectionTexture = new osg::Texture2D; + reflectionTexture->setInternalFormat(GL_RGB); + reflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + reflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + reflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + reflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + reflectionCamera->attach(osg::Camera::COLOR_BUFFER, reflectionTexture); + + reflectionCamera->setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); + + osg::ref_ptr reflectNode (new osg::MatrixTransform); + + // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. + osg::ref_ptr frontFace (new osg::FrontFace); + frontFace->setMode(osg::FrontFace::CLOCKWISE); + reflectNode->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + osg::ref_ptr clipNode2 (new ClipCullNode); + clipNode2->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); + + reflectNode->addChild(clipNode2); + clipNode2->addChild(mSceneRoot); + + reflectionCamera->addChild(reflectNode); + + // TODO: add to waterNode so cameras don't get updated when water is hidden? + + mParent->addChild(reflectionCamera); + + // debug overlay + addDebugOverlay(refractionTexture, 0, mParent); + addDebugOverlay(refractionDepthTexture, 1, mParent); + addDebugOverlay(reflectionTexture, 2, mParent); + + // shader + // FIXME: windows utf8 path handling? + + osg::ref_ptr vertexShader (osg::Shader::readShaderFile(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + + osg::ref_ptr fragmentShader (osg::Shader::readShaderFile(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + + osg::ref_ptr program (new osg::Program); + program->addShader(vertexShader); + program->addShader(fragmentShader); + + osg::ref_ptr normalMap (new osg::Texture2D(osgDB::readImageFile(resourcePath + "/shaders/water_nm.png"))); + normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + normalMap->setMaxAnisotropy(16); + normalMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); + normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + normalMap->getImage()->flipVertical(); + + osg::ref_ptr shaderStateset = new osg::StateSet; + shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + shaderStateset->addUniform(new osg::Uniform("reflectionMap", 0)); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 1)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); + shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); + + shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, refractionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(2, refractionDepthTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); + shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on + shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + // TODO: render after transparent bin when refraction is on + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + geode->setStateSet(shaderStateset); } Water::~Water() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 519cd51819..78e8a4927f 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,9 @@ namespace osg { class Group; class PositionAttitudeTransform; + class Texture2D; + class Image; + class Camera; } namespace osgUtil @@ -37,6 +40,7 @@ namespace MWRender static const int CELL_SIZE = 8192; osg::ref_ptr mParent; + osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; @@ -51,7 +55,9 @@ namespace MWRender void updateVisible(); public: - Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback); + Water(osg::Group* parent, osg::Group* sceneRoot, + Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, + const std::string& resourcePath); ~Water(); void setEnabled(bool enabled); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d994a35ee7..be86987e85 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -153,7 +153,8 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript) + int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, + const std::string& resourcePath) : mResourceSystem(resourceSystem), mFallback(fallbackMap), mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), @@ -163,7 +164,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); - mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); + mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 26153086a3..de9266cb2f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -167,7 +167,7 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& contentFiles, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, - int activationDistanceOverride, const std::string& startCell, const std::string& startupScript); + int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, const std::string& resourcePath); virtual ~World(); diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 00cae86d26..75cb6a9b0d 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(mygui) +add_subdirectory(shaders) diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt new file mode 100644 index 0000000000..fc4706c1f6 --- /dev/null +++ b/files/shaders/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copy resource files into the build directory +set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) + +set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png +) + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl new file mode 100644 index 0000000000..01e0816bc3 --- /dev/null +++ b/files/shaders/water_fragment.glsl @@ -0,0 +1,189 @@ +#version 120 + +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) + +#define REFRACTION 1 + +// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +const float VISIBILITY = 1200.0; // how far you can look through water + +const float BIG_WAVES_X = 0.1; // strength of big waves +const float BIG_WAVES_Y = 0.1; + +const float MID_WAVES_X = 0.1; // strength of middle sized waves +const float MID_WAVES_Y = 0.1; + +const float SMALL_WAVES_X = 0.1; // strength of small waves +const float SMALL_WAVES_Y = 0.1; + +const float WAVE_CHOPPYNESS = 0.05; // wave choppyness +const float WAVE_SCALE = 75.0; // overall wave scale + +const float BUMP = 0.5; // overall water surface bumpiness +const float REFL_BUMP = 0.15; // reflection distortion amount +const float REFR_BUMP = 0.06; // refraction distortion amount + +const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering +const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering + +const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction + +const float SPEC_HARDNESS = 256.0; // specular highlights hardness + +const vec2 WIND_DIR = vec2(0.5f, -0.8f); +const float WIND_SPEED = 0.2f; + +// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + +float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +{ + 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; +} + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +uniform sampler2D reflectionMap; +#if REFRACTION +uniform sampler2D refractionMap; +uniform sampler2D refractionDepthMap; +#endif + +uniform sampler2D normalMap; + +uniform float osg_SimulationTime; + +void main(void) +{ + // FIXME + vec3 worldPos = position.xyz; // ((wMat) * ( position)).xyz; + vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; + UV.y *= -1.0; + + float shadow = 1.0; + + vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; + screenCoords.y = (1.0-screenCoords.y); + + vec2 nCoord = vec2(0.0,0.0); + + #define waterTimer osg_SimulationTime + + nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); + vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; + vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; + vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; + + + + vec3 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); + + normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); + + normal = vec3(-normal.x, -normal.y, normal.z); + + // normal for sunlight scattering + vec3 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).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); + + + vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); + + vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; + vec3 vVec = normalize(position.xyz - cameraPos.xyz); + + float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; + + // sunlight scattering + vec3 pNormal = vec3(0,0,1); + vec3 lR = reflect(lVec, lNormal); + vec3 llR = reflect(lVec, pNormal); + + float sunHeight = lVec.z; + float sunFade = length(gl_LightModel.ambient.xyz); + + float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); + float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + + // fresnel + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float fresnel = fresnel_dielectric(vVec, normal, ior); + + fresnel = clamp(fresnel, 0.0, 1.0); + + // reflection + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + + // refraction +#if REFRACTION + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + + // brighten up the refraction underwater + refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; +#endif + + // specular + vec3 R = reflect(vVec, normal); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + +#if REFRACTION + float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; + // make linear + float zNear = 5; // FIXME + float zFar = 6666; // FIXME + float z_n = 2.0 * refractionDepth - 1.0; + refractionDepth = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)); + + float waterDepth = refractionDepth - depthPassthrough; + + vec3 waterColor = vec3(0.090195, 0.115685, 0.12745); + waterColor = waterColor * length(gl_LightModel.ambient.xyz); + if (cameraPos.z > 0.0) + refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + + gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; +#else + gl_FragData[0].xyz = mix(reflection, vec3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; +#endif + + // fog + float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); + gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + +#if REFRACTION + gl_FragData[0].w = 1.0; +#else + gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); +#endif +} diff --git a/files/shaders/water_nm.png b/files/shaders/water_nm.png new file mode 100644 index 0000000000000000000000000000000000000000..361431a0efc35882b56bab8ea407d245f27c879d GIT binary patch literal 24405 zcmV(~K+nI4P)zc5 z|C-I$7<43zLB=3!a^>X8VD@AJlVs9l!-FOovbTP(O;@uvd~NvJ!LFdUpF!yNjKLWA z`N9miMi4X^n@Ihc)lh8KDqg#IEnsbW7gSTbh=z_$braF_XgVQ={@l2N$e^x(k?c&K zkxU9kH|&54x{D?$ijJTIA{#pB+%yFQbU?R0L^rV;Xfol^#Xqw7TJTpCtApx>eg5rc z_atd5psOH)AczX0;r=lV(a9Q36FfWkD}(3u%kKdV8PL7RPDVkl&3rXka1o5!1WCrG zM-Ux)G8yDZ=GD}MO+o}6LAJhUWw0A^Cxaw_ilA%gud5gV*+3NZBw{nsGijP%1yD2) zTmOEr=so;Bn+{kNJfdI#r2`sOj0U=>E}EjED4^Ly6irh!9Zik%lVC)$Q-7VQ=jyLT z7R>R4y@M#A3Mxr_{eTKR_-50EzEW4GAt*t9|kM9~@a zN3b424EQMhxkVEZR4FR4gC@ux6i_6y280guU_x)YC&?zd$WC7txM+4LBH-5+rN7FC zp24nGRG6EhnY$sNq8JoKK^GZCcG07VYC4PFO;uCbG*F?N-vQefc>uljJkM*Zg2_)9 zRrF5X<&i59(pX@kV6kAMl%Z@3H2&Jp71BokJ}x}R}~Du^zg%P ziprprJ?IfS8L`PqsyDF`B|wN*5E10|e}`URR}n+6hlDwSA3^-4G|&v1=CKDq5?+p4 zT|rcm-Na5Z6y@}=lIWlldY8f~gCa;49fRg82j9Qr5;e&?xE0@ z9X^oB=%8va*u+*oX6xlmPB>SpuWp!7pF#f)`5D9r-NIgE4?be^MoDu85nJCU(@_Uq;iAd075dnKB3O4p zGsap~a5y{-m9D|w=kDwnupo0NE5eMXuj1=RuztY) zRQ(beekQ>fsz1g@GG34ybwykC4_)j|KR=i!8D~1ugbzS|`{HrFhyG?~(-->n2h?u? zpFz&nzc+otXm;oUM8e0`OI(-!ak}^Y7?7(KzVPkOzH?z_Qyb=1*kd>Bgx>6O;@bgH ztbk&uKAFRxE6EYeRzZ1%4t$=VZym zSd4(E@PpM~4~kBh3o3;fj7RH#I~pE!_y0PG+%?G6&8}vA!Co*{v0o4!tP&8gDj)|d zHvJgv$7YQ5F;5plL2u}h^lAYiK)~(QYHKfcnzi1O27CB0ZUu;%p;l) zg3oh_KmBF-A$)4UY1f?-vJ^;&rPr2$J>YHCfMP7x#l+i&9wUQYs zeB9+Ll6TWR80~Q0O@@96_R}pN(|5=Do2WYiW$Uo^tLPQv7qFB*UQS)Bi@FAp1*w!% zos3phojcgTD22VwRuUbhbbx@AnegeuvR>yM>cxW(Ks2#ocQW%t$RaYBQDg)iPL=+Z zqg8jz)*+c2t|VqtSFt1YJ`9pY7%V%D1IhNwk5nfTrN5pXTzl|=3e=3Cvx(mpm6QG` z>gf(^G(D2pS5SkyU<#vZOh0g=ca#c>9q>$e4i!8R%0Cs!s9?m@5AIe#b&*4qk-nn3 z)mi~*P-%B@rK)AJEB70GoJCyf7~&sAJVQ70)$El@Uu-G_)I>J}fi%4YdJPxz zJDWM2M~wjPQAFz2e-7vhzP1j)c6UMvb&IVOH!1eg8_EoNZ#se+#TBP|ErsDKY6Lx1 zE7UdM(sv#$3?OcDR?qkAzPtjuyCPP>4TEap2@BuaD*@-;V@pORY(S{7s#e7xeHPM zCvJI3Az5(>lIW9LZa6vzlxu=mD%!e?A-lM%)y&v*4fWAE=!Bg*Fhr}nOX$=MjH%D~ z@ee)hU;hofc;7}^;kl9>YCEBXIUJmIozGmlRn-dZ(JY!8I;?d1K&TfHu3_BPr!ky@ zUnQ_$SCTmd9Qp7@39SS@hY^b05nBgrz)yl#!V0~Mxm~7Y=}SbMA&kL-P_JJNmC4?H z-}>H7M(T^K;T9;ASIdoiv=4z_Zu{?Z6FZ4E+SN()I+uk$pwL0nQ=wN))^Me*-y`9g zeu2@jg4zfw-D;;OrvTKxzD6=Gw_}&n*Xd}S2GjLGxWM}L->`ncF5Uj171_#p-~V5( zn=*u+jy6oLz{O9EU6fW*9n7ep5ZI)dg%7zQ_cF#?5%_ib!VVvcm#YMJU4>cLDtY^&%xY*suv)J+e-Y9ge?-f zO`2c@?B!x}(y{IXFhYl}dsEw;#~FL{@JSgySZc?5DnP7OeGpsep-V+r`G%E?wO6JF zIRgPhMhi!)_vfU;--4b2{{!`J2cXg+J0MtuQUlSRLA>h#Tr*U_ujzt(s!bzcW%6i) zUp~aRJz-Cxw0i3@FI(hpSW=qsW>nifThly43<1|D<{`I~5?ppc?|G_Gr%q zTBp8(7|wG{ClKAXO4u*Gl)X?C=zibOp)m7|$;f68)iSe#kpfJF?`zCDjHky8;vWH5 zu>J@7X;8&o4<2%jhT&OBN4XeQUGt=P7E}f-wP*bdwR{ooRa%3natG$-Xy^Hs2bIx* zP1grK6n#6CI(F>4D_N2J?Jj2xZJ1z_H14b)jlr_ zACmM7I@o?2|5wjko)-+y&IMWs#$C{Zsur*j`Z9%vMLS?m-b0=&RlnW-749m8lkbMT zb<=jkYJpa(6{0I9jM7X#6@m`{7CC&d1ni^(-bW}()Fa@(g8g^HFM%u=vd>oJ#8nZk z89)r-_J7TA3+aj6KE*Z$-?&l4?LvGzBtJckt@LNA7L4x_X>X?%lDO)g>r`r1^Xk;p zzXMld%-RPGIMbjBtLfaPV{GU_`ioozpBw&)W*fyCQ81@lk~rtxv&8rRWpTHF-ANiK zi(0TXcnaK~XXvB6jNt7vidNy*E-IsZ07{VQ*g@}NwsPJAO%R#9C|;55(e(7JGvTp- zE7^`*S?$p#PA^6wQ@G5Jkvga!Dx7(i>x9jyVmKmnZ*r)r-Y$#Q!8Y!JkOo0f=@z-% z-xpoNyGVFt@XP}$xkbm5+n3Yr3M$PL@I^YznqLJgHQ+jsbugH*4vZS#X0R$g(se<` zg5?3rZXPrr8-B5AQZ>ZhH=aODg|RzJodLhmw=S~uaKlAfm!?y9y9B&8tPa+~VOyiw zU4~sXBGCisO;))Q763&HMx7A~y(GV~HCvb}W=F%QWImgHC0Q_Hz=5&FN%GLkHKHTZ zD~mm$RxqNuqPYTQZjXjF@QPIQ`3j}5?4)uN+hEZSW{E=(E>bx!*#+bFP0Dxq1r@$T zanC9CcGlgBk~NjXo&#PDHPUko9j2+9ID80B8MrBBTB6$d&Ev$~e0Fm+yiADbWoAwL zn)D)4dASZ^dB&*i7gk$El25SOAy@kTvtJtSu}=(Sus4jMLt9{C#`dHuPFX~bre^Rc z1P(>;ielwpT_q9+1$(esbBgf{x173Bjm7zC3Xv zfR0v^r%%7XVuC|5wO!4-^`ZF@ra2vyu1@=^e_w2xezQ96vt=Z0!K|WJ6TOtIDLP7n zkEz4;icmM{pFCn1l^hynQZ5cm#%NKkpc$jtk7CSZm8#&^C>VnkYL#k>1=U-ffjR{7 z12o)Gfty{1Tuael2epf;X1|(Tdg;@Ln=FloL!i&|1L`+FhMn+LnttYHZoypxv9Zd} zORT$~66%4W_Ml%zOY%KwOyeqt?6KGTpj5-Nl~T=9AwpHa%faIiAYd}n73(YiztO_g?~NNXY1wf*O`x>@E7zF{7_pa-b{&S5r7@QQ7ri%D#o?kGZqGg4F zppm89H=7>Cy5Q@-;5D7YY4}LS*u=jFGdymNdj{&c3-l+{nYp;%*&o4p1$^oJ=N1BZ zE+L1{<-dP*+(mIr4OdQTne6h!FWwkHHJSBBWU_9OUWZz#+06&VFI)Fm+6ibNr@ zgwjcDBU*)rDWyWCe50cDp_lV&!D|VLsV(TZ{a!T08RRn4)vV%X(KYnKJeVPZ$Px(! z9J;4zZ>hq`e75$(YxS|BZ$&FiBQi#~R;d@{v-qfH@6sT(MB7qVz3l$IG7ec|Gg^gKY@>PwSwcwD-=WQ?>{1%5XnuYu_wO{&=F$6PGG{S=Gtlq^zVs0) zpngDKiejA!8Akb>zef z*t+osQN-41mdNl#Z>}A%Len|l{&)lH3a>lfWJEOZ8E)GM9fb3HVV+wxOy&C=K`r&t z!z9Tt(^cr3Zu;I^!D^UJoND)mdHj#r{MzO|B;+dQ9>l8{t?D@Tez(M~mb1z%;Zhy6 zMI;cPVBeihx$A&pXY=!dzkV3>InO*pT)b=^8RW^!*_3$_dl>A=gY&0TTtX@Wm>fl3 zDtL3kctHJ`zLJO02CiX>H=8RFeHoBZ!^bR|v;H%#Bo5|9!trpg8T1L6-AAsf-Mt`V9VK7fBi|E=2_ zB_=UUc9(`mhaEL^2!b}-!llpHx-FNLEK|i7;rVwgJ(OBxPM_7KuERKc3>Bg^R1}r_ z!r5?z63vdh`{>!td^KZ>^QU~D`sI-k~U$eyBmsZ5j}!gxx?)FH@XZjGY(cn`Ds+03V@;yXNh zv34b-XPC9NV9FSbSRz17AKK73xUOdZ2;##zsT7_fLIq8F()FAF_a9Kdihd=X%T;{o z^jWS{-LCj?3h<}PW?VkCVQ82ldU?*U$e2`Zf03lvJP?6$E`@#01hHY&sd%9~edB~! z&YDb`StrkHDk&hwWA9h+XFDiYLp;6wG*=H(&dnzJYX&d3p#s>(T>y&o?5@e|+^EfF@M4RRT+$DQDQ+F}&98`Y zOYrD494uPf2NzutV6)119(_GjHXg!TTQEAr{>i=hdT@Ptr-%f%%u_S{t8yK@byKu9Ku+=X zj;`-Ow!h*VVbfF5?jaVDYk_W)^iNpsrfR6JNvuUkA%^Fc=e(mNEAA=M(H^L)()=c> znC5U^G>q%(37K^0V2WNnYy7k2q9_)1duwk~dvC4h5R`(59tM zWRnIShWc}#mz^zM{SBLLx|A!ghnj~hwPkx-=k{7|hvGkx%dHo_OB2DpCBypb3C{@n zl0Hz%=iou`Ig;O|h?8L?`nB}Zh31RwxsUAXpTO_%cr+j5t@%@#QdD@_mLAQT5qwy? z!Qdg4jp*w)GfF9OhgxcOzDYO6FFMCP5R(kcAwJW@Q_m9G<9jn}g64B54g9@}Y)w~j zN}M}3UkP(2{Ydx>;-Mb6Gfjj{@zcu;o_>FrZ1nJ3Bi+rA&?JIofd)hT{Uh9nJXp3K zU_|?c>O-e7g#cho$VQY^fUV5|+9A*?b1+_-L(EKd;wS(n>$;da$_!00s&0_}n z!_V}uW(;`lW;y&nXS04l{lkUs@Hn>nPJ>6g(+1C<4t){hEh7_z!^0Ru#x|8*FF8#Z zxWT9r(e`jP6!G$IQOh^IjJb^1Y}$W5Z^g73#Xkc6HQ?EGi%(v_>{-f@pTU|%W-wAs z>p<1}8Q%(o7r>llh__B#SrCKFX64|ODrO3eIy=%>w@$dYb#-({H}D*mq)iuAJ3UY- zrIt2XBkDb3$a>S-5192D@IM?{cf3!$@%^h635FxpbOAS(h`Jm2ieg{EzD(rgeSpd@ zeYmp<^qszr$itO7x1d}yTiTJk$Cfb=ey-=ct5D zWSLj1W9Vcd01II5N0ArwSQ1jiP_NxXG%R!1YkRuC#k0%hm|1yP5cJed`ZaLXne-5V z5g`x*>kf}9hiEZ-4quR^XwXHBlDug;L?X6Lzupq^n?Jb)*0iNsUkU#ndRxmA#_HrU zOCgOdR0LxnU@L{kZ!?9rTi1Q$$-Kof`q|~Q;(y%DubyH(=Mae0N1i1xD(sao`bc!c zYT+|s%%iFCK`5%Gira%wo)=syN;@T!TNICoTUPJ-Q>{J4n4zNeOGHuWCVx{amJ^G* zVf0|HO^?Ae3K%VJU9?p)b=Whm!TkGc1b*5JN0Q&!=YsdlCDh;@r@%d z=!HqhsL4~!F+wH|@$waTHe>1U^BY1~L*Z_xip-;Vcp*=M;!R`A20#QCBeX5sgkjXT@f0QatW>H}!sRB%HL#1Zm zr04rp?u8L+0v zZ1+^J2!3IrY>bF#hpE=`0#e6%{{)JE&I2c4>TuQB*-7nk*mSOBvE{)`raS7{rTVXo!4N7-?H z@1$6Mq2;;&u4P8^QShGex#@P*OGMQUg?=<~#Gj?aZqxgl8lA68s;&r_4-e*^K~0$X z8N@Gr*<9bu4mucHE*4n_&@fxg@|Gu4iD-AY&}m{pgrF|HG6o47)QtJ zNN~Kx8;%HNWdfl?Jy>=csk<5aYuQ;L_h`hIB!BQNxvNt7{JFc;vXd(scXTr7&Ne{5G0@_T=w#6JCZ_J@l$> zUiP(l)R1C%CgBdFQs7b=LXB7Pv0<7XCrn|Bku!p)PkkaHOmC}^O;L$?RF`qsMKm(6_q=TRG^AJ`QG>mR{eDuDR`L-a>8N)aOHC zOaq|9E|$7irbvBT*$m6i{@E}xc!p95M%APvP}tvVuy)WNFn+?mh8;P~h~6TCR)i)0%xxY$~@8p$@={5O4odeydJ$2#465g3Mh) zy(ew|D7lOMvIk*dDs?u!)G}@wYS5SL6}8R#_!e3jhEh z07*naR3q%&y?weJ2^(9Ca%YvA%^!Jrje~@?@d1B!UyF3hl)VmaB!<<^uCm!h`{uVT z;W}>JMW&+ZfrqgZWH!v`LB`S5)vbVG7t0dsws%`!YAIAsx~%IrSAAL*n4akEGJR_6 z5ClVXaL?k;0eDMfj(k9}s=eVW;O~^VRM@vCN6=$P>z^%}c-1Y#4$s;zPw_;a2wwKk zsfK)d@>#`p+sPJjAcxyV3p|B7+8_(T;pK{}fIq)+sb>UxTM)Bayu}^24x(S`CSr-Z z(0g0dTJEii>DM0zx;C*z<6hVi7VE~XwcSI!!7&e4!?r&a^hzR*;g^`l5|9=%>mqB} z)&w4-Ji1Nww?n{5+EufVJ4Mt{zpCvUb`+hZAxRC*;a?>w*2z1kyCA}ieciRdc^LSH z)NFnNUuBTW7H~ZWwQU76Lc)s}^eD~FQHaI_&OEX!G2K|3n*-P;a?~nh&!O5R;~m+e zE&mEj+3h|Sz}JAM(Y_JF?5`H}JDktwmcTQ&iaOHtv291t*u+(a#;q|pTOs32(D*K7$(bVp7Rq9H%!TnvV#FRSz5E7#OLL+I55l zaho@FBbE!Mjt`-9(}qYp!kU2iHYeWP@IoJNoujB}p2$~Et(hJ`-#=60klwP36~thi z!Kok)N57hB-`+0I6a34av|jF3e;iW=4Tl#IcJMmUtEa~DuYmvQV4F4;6-*OLDM{yN zOJSwXs)XS$6--s7$T*w*ENVy>k%wk)lre1M6D7cC4;#mgpv~3jOLfjj!BgEy*I+cJ z%}M)lP~Grhn4^Z-F4h3_BvRVCGY3DCm#1R; z8&z%ybBV9yf_> z_r;z`hjIK!YA2CH564IJrgzsA!7}v2MmDdhp7z(PEpd9&#CN~zhPH?@rv9DpeC4u* zTJ-HBY03AH*EtRUuoN_n6d( z8mWWOXY48y=1&uQi)Qb>ef(}?%&>;;t8WaiZ2@7_%Aj&+-&$jJr3E*kpeoFAJz|gq;ff#s7sTW%0O~Ee)qh-Z^r`dXQ2#)9srjW>z z^Touo`Y`7|{qPpai;|gu35tqyliG1+TY`m44vt-^=Acy_4Bw0(_=sjj5mOZLebh(~ z;Scdc6G^6!$JiS5ToJsi--|ACrya)ZS-g+wVZW)82@iuT$=h0nHUnu(#k(p*9yzs3 zg$mXlnk?2ag_a$BdyKI*{5hmJ<^W$Qys29reHqD^1+Qf6tsMS>c=c^q!8dw*hpcyx z9nRqpjzg&%DtOmW0Z1pg_2MPpA12Knhn8pro)BNts2N% zo*lQD#BnD!t0l?<*L~yOfvWVJ!MFt6EDw?7%+btDyLOq@R1!LTgbJ-)Dn@T^JI5sY z&~f5+Rwy=e37Q_fU#1|GBzx@$nLp%$9A<$*{g;&CS**sEDd=FRsBXw~u(d*QT4k`w@2CTDgW8V6S z=scb;M>+7O0((x}xtMt#-qH2PGCO$iJiR8vbLb&5C~x<#WY`Ob`w#DJE28(joCr2>$b2hJgsewXublh%oN0)eW4qOTU?!5l= z0);diS;grh7}hVAWmepu=lp(q;JMYOikv~dlK%4i!zPzW+yK`(*PTh%V$I-RSMdCV z_&unp=%zYG1FP#;+}zV_&r|9&_9pCI2DMCb$qj4ER=-^R*ErUA&iSF2E{F0<9!ujg z$mWO}CYHpwE%^lLAES=rF|$qz_(tuj@}>#iu!QN_yU%3I7s?!VLR&jjhLEm`12o0|8d$?&E_dUJ4X4~atZnD4 zH}QvfPjOpe^#GOj2FPezo#^BqmJe-JOe$}Eb?|H45>xf_ws#$M&uL7I+}h7$+koui zH@koReTFJMiKusrc<}Fhn;^&xQu705z^8iWdJKo`W<&}uenJ0&{MlSTH5kgDhHULk z{rn96{71+RpU@P}mUVFxHp4)Sh$0&Gv=6~@Ix&`FwQokUM|qK!(8?ZIL!oH9Wa{S9 zd+NsLG~dz+qM@!p)&}wRIIv#gY%m&?w_(>*(cpXQ0mU#czRvjGEtIO(Er-w(9HYI> zBFv2s7cksUGU?0$2qOQ&2yE{2`ovwMFdm3Yo8AZ9?ewcBUb4!;rUwiye$Y)O-0oIqZia@=8-C zw3{hyN0wf3GqcO5!XSvJQu`#Z@)XU}zUm`7Sk{^Ur+TJF+~ZjuA?$s@GmZUE>|5r) zFWbEKv1^w-UDzlv&jKfcA5r4mjnf}1l+C+L*#P7T}fOn=^#4*yKqDwOWxD3d&d ze>7Z=X8xD-`ur4TksF>-EQVOWAxc}AxR}Hd`tTqAEp-eZO|UtOH%dfLZEIN~;<9Az7eNnE-YO;^a#GC~-% zj21gY(rAe^PFvHVR;OLn%XeT)g6#!KmBFu(#Iw~hz1&b&+PO$>q6`^J^w@qdKEaMW znVLzYi^}lxNOu+zPMS-9ne7{S;~GZ`)ppJh$R(GO;|MldRINwY2Vg>cLOh!_u<1H<4QKu!D?Af1mnydh~OK zQ4aN~-HQxI@02&;@X8;hd(Uhl&VRv;PVFvPm(+0zx5v+tWvn1y2_fjSH)pAOwRLTq z-L=>8`aRRb(3(0AO@h=eoE=_EqZVq0vR<1=nl?Q&^2v7LbADKy2Re@Hs7V>|&8hHa zQg|s&4=Z#eG0N5}7;Xv2IXtIH$`U8w7RVayysb9Fx9mUqhxgAj&hp+7;?JJvg-YT* z9RY6q#b(@H(g!9<)X>duL{i}xbbIaJS)w^Lbv!Ts@REk%=9v_`%I3tyF(se=2-}5N zS8#RRhK7>!$z&;a@f_mZomqbkh58sEczt7YJLoJsFxnW6PA z!>ji4fEfMF_VadEJ9@w-)2<)W%QBA%Mp>CvZ(RiziIV^65iFnKakH%AMm-N@tQL;#i$(*9LPLzJo6=%D^{|=DQ~8@2Q>8*EI{3=;%Th>=EPDuY^Zbvs z?7=#_sShLqq zChV=Kms@Ldj0gD-xYy&94V{j-R1Ze2U|J9oJy--EYf$+%mp&;c`uH=~e?|m0W7oIs zCCk%5L=HIXPF};t#y^TH<-pZX;IAdY-CuPtIV`+x<^mqcdI-a>tO5V zw=*oony>~uCah=?E8Yu)?u8Ov!XeITSMlB6j^no*#mV{Kh9Q`bxNo-z?LQDp24PI||%d^fzD{~t&FyZl}hAlE?MQBrI#$9j)dAF^2Xx068 zFkzL~vC5cYmljQ4E%8VYJn_DQsXlv-Al%NjRc%4rsZ><=yumK}7VKlSYlG}qas>C3 z^7#0_5}WkvNTvPW5A+ho1&$2t_yfo8_vW{=Rlp|N@;Fw}*S(poTUoi89h*Iiuc39M ze7sMT3JZxAv1)61tIF$fgIV`WtK(f;!N>2&?CC1|PdYnd%|Gb-Mh}PRUU7!U3T^UIr!$!+N!fc9w>7~@yudP5i=-tw8I-YvfoxPXNYu= zx&EfN3-@Qkn>VgZ=4|p)0Dn9@*LQ8yxxMP-05ti{=-^-z-@}G~IeOa2OaFKY>hGnt zvBF!k-tNLSp4hioBE1LcY~nu5;F{WsmYl*fS(oMza={PA!)@(Mt$eE>y~Zw|Z`nFe zz5K)bpSL4w*-2etZe{b8@M{F?JH_iPgQ#I642^cj&YS8kLZjW?oyuKJSaPQHDdzWP zvq_`AJvQ^#D85X@Jfq7t#2NeBM(_OQDVm5h~g-_9BBm!E|MJV3#-BO9>}Q`EE8M(HLGc9h??Z|>%@uAxu#(B^dOK?aer9~9?nzeJ)Z{xmUg^?zH>~C#FOrLc9gXEawIw5a) z=+&+}M4rWx`#5|aq0*^Kj6u|qcGtH<;004`iBfL=pKNkZ(=>}Q+H%Fx8-QNMLuo4{J%ysD-HqC ztCQD}TI+$#!@_g1w}-ceUgiN#dEv~$%c88-ZFvpI>1y93ka?Q6wwW>JFz&o_a=^pG3)FdaJ#c^{hCjx+tVOZN~(vKWN3Ma3`i>>Nm|l*}|LlQa5g3J=kyn^}3MKSe}a?sw4Z7*+elLCFT;}W|Iz)rMeSU5(VH91m$qUz0X-|Scj%4`zr6=NDVqjNDM|kfz z=w@s~@2#Cethl25j1Z`z5 zaS)&Sj|dh-t8|!`=j}sdsO#IaDAxv!Pyr*$I%5#=t=Y?&!n-E!@*n;$Q&pj{_rg$lt+Y3`;` z!3Z&O>LYmiXKQk%(r)lh2cyLn+Q;pDD!a^hTN2s*nf}m<_jo1sk|SArhhKkFtR5>Y z`a22aeZUSM@bu*!b zJ>I(t_-OVYLH{Aw)4UXs!Zn5RnG8W5c2S?7BjF*<+_0O4s9JSPlvcx+*}eK?;|A38 zNVHELv)*5{7dGjVeC7`K!3eAszCDc@DLeF@x~~>JndIpX#{{wA>2gydBGS z!ehUwho>nZT-e6(A@J~I2!rUayH*m_(d}v7o74{Dr~D$kk^9~p(%&|w#@qcnJhe=3 zNB0!7hry#1CH^-t(s{igUs{TlwW*lGKm6TC?0eo-7TrWP>$6#ZXuh%^o?(o$&~4aS zz8K}|qeLG0q?wOMW)$NiB&kAqx=@kvJou2+FW57`O^j4Av@H)mmgi;?#bFZj9!~7d zd}3xof$17%W>#ut}R-)LzqqaXKEC~ub=ama;oixZ65C|JjOK^; zX|PW5t!?Lvw0oY0Kr!u>I-34nH@zP4nsP*Hw<31^J=r?{PBA;e+&8n zb4X}WB|o4r#9UtV*rhdSVGN+%l2sR#!Dy|Znf4V3)6DZ5gXeQ=ukQUmy}q`P=Wp11 zNYTd=kR6VMnlF?ImUsPdkj@m%{jAEVkY(f;+xp1Vzy|m+;MKC5E2E%i+`n2bYk4V+ zCGqs- z+D*K?wR;^pl_=zW*2?bkL(~vNTgoB?zz@01g#Xj_BPrfZlwtrk=>-uWy3Hw(u zj)Wdnpd;dlP+GpI5}yli1_ z|N7$#Sk=S@Yc!7u^=Rs$D5gsxv&gH09~1W1i5>!cUQS~@f_@C*6Y@h*puOkeMe-GO z)5wq3vQ86pYdei*ngJaYbG*D7_8?GaHOa&NKl6w=adPI_clKv9zo4bd<6Rn zn@F2;aN4Y`MUA;tDF0=Bi+a@w#_MegukdN#fkq^_$3`yl{%gFRRyB*L z=Cjvf>BfBs&NS|o@Rz*;I=E4=Xu+j9y$WG@oeGk7XC0IZv+u+_4r7{qHP1_&f<5I3 z(#Iy%EqCpMY)UtFZC!_al~71CmB$(Da!-531b!X!sU{wlTzju!p(^`0ndWz9l{b1s zPOowoM?fQ5+0`Da7s@VQfvXu8ds>exEDglfUA@WIEY~uKm1%)zdMM1 z#IwWd>}Yp3>8)c44zS;^aF zs5jE;*ktq4A36m2Tq*86E^4t116+}5s~uYJqAYlc$lQ^e*DHy-k((cr|V? z&}P|Q;@LMZ#w_ZsUGgMTUd7F>B*%Nz%b&oX=G9lf?J?5-IYU}_Q36Vs$K~mi8|pCn z)-6Ara@hQJ!QW@M4*gy&8 zt3Z@Ox1&**rz^uH!?Ee*R?NQ1!FNY^tnz&T?uFS~Jc5mE^Y=)42yN6xv*MX@{#>K& zS^T!srM%y#oAFQuDAiTm*1WZ$zJ?ZWAHl1?S2_&VYOlA|HquK_{s;InxiVb!4#TXY z&_aflj4Gx_(rxRvK6`?Pc?+rWv6f0W^d0dha{1~}_kO?fm^q?l963ug?2z^CF~qjN z684C^H;J(=qw{Cb%KNsAO@p$9mQ~=TS6f^-9xJJ-Tiw0yZbS<>tTRX%S^dk@xU(Fq ztWVs#nYOt-!vkR!LLak_`baN+*t3Yd*OTeub<@bQvYi2lOSDP#KW)b{)!JiMWGWXil^r4&^uF@=G-h6_(O{B4>@nM8y zwMU+=+-Zf&d*%H(1a8x;Al9}L`~75450s;mcP+Gq)yGlbe52oo|GaQyNjr~hcNoi& z?KYw`1|kV~5-;<~&(1@WMzfDPTYf_u)60w7$uyT&&h;RB!A^EBTf(e6f<+{e%gZv% z!ig>7Z0O}PU{>w_udB1$lHd-Eo%qhJPu^OB=M#KFQD&PdlDx+5nmxXLqTj<;os7dL~h zQK@Sv)!K$N4eN(CikG$wMlg{FSKYLXorGI^s})-&XL%xJL(8CE)mk~HQxd&+D#us( z$eqk?zB52D2Jq0}^!9cVYtIyR@O;4*aux{S>IX&4M+;^kaZ8)KKB}R~X%uFnRCRLi z@lzW5Z17VW@@beaQ${kq_-@+zjocHbp<@=4^X$r|ZzTg2v+z?t3o~o9O_Y|ydf1ld z3oreiHkp)-4{ipzkICj+@C|EK?u*kCzYA00*xXgvRx;v8v6!r(4FYI18C=qIf5h z6)Vk~8Nr3ZFED6gg=@SjF{syeO!xl3J)Sv9C%36q$agKKG}2x+>EUr;e9*=<2hU`` zwPvoQGwFjGfPC;>Wfp>C6!rN0iyi(j%v%E^4W*`Y=+z5f_cy!^PD>_H6;FX2jErAK z_c7QBMdbDv+Jmk1)2X`{4$Kb@-OLJj(V%)QdLSAAQc6J$U+nE6>Z|mFE;I|60aD-F5(8RF*1<(N$ z#+iT{0~qSTr3of`>kXgUX_e=MsW&?mDlwBGk-Yo)Mb8Ypb5M8dL*kRv<{bL#l9f%}QIl$9OBhd1Sl0kfvepHkgUse^g}Zyj=c^_MRQ(goySz_^Uo?y00P>tnU!PaQUI z_?-9{g&zt0Q%xH`sFV`NM=K+CT{*-OAXq9}g1!?*oMY%u+@SOzbFM8MvcP!3-F(Sf9WL% zI+_5TqVnDDjWgO88v9&Bz-T4Jg{&Q9x0lkl_i)<81nQhIk| z+e;e!Hf>COMdNfVFMVV-c)XgN>a&=HK0kr+Dc;~0zW}C;1M7oG{E)@2q%&-P@YE2@ zrD7hsdQ6eI*#S{@zIbadf&QG)4?wr5lbXgke83|2atm6rSfnIh>e;nWu@7wuT{=LV zKh#q*dS@I7EHQJSurQJj#P=#hCH|=?36*W+u+-du3&?=MS8KarfO;v9m((T>X-XVZhM8$f)Q;rFEwVj(wcpHuAuq9Z2JdfINm<3abV9p(-LGY} z?OEI{HY6ZWs9eBtumR9Nt{`j?0!w(ZNizZKg30i-8Y)o7@!OdxJiJ{^b zw$Nm0z>>*nS?0hMiRF{))+TFaKM+FMY~Ou*C9zclJIKPg&aLEU)>Ulv#!I__Y9*4k zuSmimIQimL(@0(~#p&iL@-jN-fR1RE0Rl^=Xky|ixsY`nTTgh=3prgs(Ad_a(z~mp z&DkP$b`baD3`ZQHnb_8X>qAkDS(_9LrFJg1LuOPWf)Bw9td?C1qf@MeG>7A4>GtN! zPk>&j4a_R6!I?!Cvk49}Pz2Ge4M%UOdLZss5SpD*T$jk*Q`@Colg7t_BP%Z3)SmE+jewS96ScEMg3hYY66&! zuH{sF>y4hj(QJC-I(sUx8OkcGGNyj4zUq2B{I-3Qv^z7mP_;dcAr@jE+1|k%si}m1 zUze}ZYVeBGX}2-Edkop`Rw+*o)M59Drr0eP*>3p+ikBoB&w?{$lj^;D( z2Ouf2&I4*#APXo}xz^I1*`rPy+>~KZ2~?b*HQUEqcV@}sMsOatQYdpVXAgz%DEtaO zY!0J`zL((W2>3(|=B3%B^0%P0tgB!j1^WPE7E)kn!@#h@lvvfk-h1T0g}|#Ekx9+| z_SyrH6E1Zxx12^1#una$9;ml?doN^2GCuV0EOm07=$U>CQ*Gcr0o?w8U5N#5NLl<#2it_QcaYmEy8+WHqJv@Ppnjkc)77aYqAwWP!E!Gv=- zG>UJCML(IkMvU$t>mE7*bLQ_1m+7NqC`sTOfd58eiQW;tz)*C3hbfwxZl-|)F^GJ} zqkwM)yQrDx%~ZJClxc<#a;X8W!wL^Gyn?^0t;MRpTx!|w3~XcLQmgI3l_UfULd&;@vVn7(DWSLAEtKw+7*0$( ze<#YI{zBm=>Y!g#qL+dY()7m9L=GqR{hOm62ESZ_Q(fm9t1WZ+?Y%Gu@UJW^CnkQil5AHHfvSO2gh~iy zhXGPW!HBkgOG4|<4Aa_`@u}_GqmB>wD8rZ9QRLa~MNW}ZnTS?$5|tAv(`oA_qYIRg z$YZs+0XQ6iOn!br@1hHo949t9??!sSB0i03~fry*w1Iwvoi4QJLFcsb`*Gwh_kTwW-4o$#D8p@VZO*C{$ zmop~uaKj1()(UiOb|Z0-JG5~)bO3G9OEn`|s8=b8D@Xh337qWXy+R3Kve`LD#TgEp zq>wlFk=JRL5iL*&uBRnUvMMRB3m-*_`?GzC$BBvIM`YBF-(ybjAiddeoPFl3v#Ngc2>a80a45y?_VPQ3$ROfqi~IH#s{M7_ixiySwC5`I6DQ!_n3HnCAR9fU#0k8Qz4 zTjR$B9yjp2^OZCX9V4d&{6`n4zq_i}hfni2>)fy&& z4wG37=QJ^;vRz59gdD6y$ssY}Bz@FHR4P}RDt_KfAqReZ(x`XLY4NDn5=!hG_NCK9 z89O-0H8ZT@8_mT>;kLrdCt|4bpM)gE1n*#h+_ygm!Bzu5+lMKxFcFMubr3^GU|DOZ{qQW7+# z!c1Nul7$U&a-jRHii(^P9m~?T!sZ|(_jN-R>-*FZ@2EKw(S}FgCH4N2H{j_MrKV9h z+7HwWK`lPGeO&s>*0N)(T7LKgAgO$~hBd~}i;@O!DAg03fK!q+`Q*}5Ap7_*87*9~ zHEpJlNoAACq^$A6Y|)Ge>Ek64hxQI`flRV`yq}`Z5qe|$SA}vBcvJoWK> ztp6GK`et}eYU$@E7jt$M?B78BhhuN39`OvG@<<6e3lkG`<~onLSDBfvgu1Tyh!qt?fQ1#i>@>-WU728a+M&s%nXu)2M0OSVHj5>J`K!9 ze4IKF(X)->71V;**&dgY`9-I#2g;_#x&&%Iirgd{B!J+m0-*;@Ub{K;;eshC8v2Ax=d_BuJ=a{LQD$Ma8oOEjM zFaQmdU8)cgHiVG%p)Wl#f(hUw^6X00nrwQGu`F>ngp|NvMzo2AE6nlmcFa2VB{2hn zAxVN>e4^JZ*b7@yR29n0CB>tIk}OzE9#_7i5!;^^g z^L2C0m;I&3_Wwr#k%ku>&%uW!yePOta%^gIPv^Xs?d`;E9IOghJUBM)4c0X3kp86!J-`9lu}oxBJsr%~|XVmYa{ z7-C7L;6%R`kKrhhZo|dFRh~}rEw!G2i9BUmGSFPwop=2|4L1RWHk6B7hL=+a62TxS zU(NoNwmt!~slBxn%H8ja24P;h4rovT3iaY0zc-sHF0j+DNE;SsFTWQxdALai=iY!q zR3>rZq;l_8PF;lwa%pG4)U`{wK8wo`51_u$I?vI8tmo>W=QPAmL;ma)gBDF*%x}7U z>pEtEox^H3wUCoa2J2;B@A5rLO6@kZ%C%^r+$3PGFuVfzH5kjb_tNs8`Qnm;h%vQ% z-9r`c(I!><=GnbvvZ&|*M0+p8x*%n+iDYq{G(0ii5Ufi1gvH706TQodBy1bDvkbio z_9{j;mn`e1902`uP2fLi_!{IHAv$>44y_yZ=MYA2C{*a@TSs4y-gv6JK+$+Q0DRKv z^yv9Wz1iI-AB_6Wadth`LYnFV6|7viVJztv6kusu76HK(e}EcIot#Wf zZ8Z}xR{%fFu<}jMpS|bT@+Ucs>kk83J2ISDJMiB9zC#Es2sj>RO-Yj|!OYS2DY0z^ z6eeAMOdUIo#9`Jud*$F1yA>~k4~9ASkO$_d`$lAKA0v$OhPzmM++Hv(B%D3~x_+^O zBkhQ7!0a#VX@!>!Dv=}z9o6DYrHA%-8#Kf6B&v=n(E#k+y{Qa@-!gdK^X&Ouq(`=s zn)FN7?T!t)s0UED6vA4IH&~U>DOxe`5&XH zfkp#6nYL(SA(g08frJ^N*_6qWrF6jNqUNAm*UXpsinqHe1$M~HO`UUi6$mzk=EeZ`i0I@N~)Z~RGUb? z-Z8b5%%3fJp{8v_cFwHibU$^ zurH;WH%zGotj4>NQ>#!H(uTS|tChEtK!KP$cPf{|3r{b+^ue7Eu$*Z|`hQ*d# z)e!ZpIM_}v#7v$nJswCqsV8Yj8)~t)yjo%p+o@tEzrbi3i1Dgy@3?7xZ9UtM{3A57 z-3j~#6=nNQz?L07g|qo`VAdr|lAS8p;kpHd6xzM@?8})!-+O6`k{B`H`enm1 zM`GbN!>fgl$32NhI%|0`=1H+a5ve;q2# zldWZCO*A?C6u@@N#=Q{-WEr{D)o7*fM&dUQsSYJvMewlP1vqooF3F`^gRe2|bgF5_ z`ryMQZm_q4g%h|c+ONsQ@wezx zJ09q&?Pe}h%zS4VcmD5=uxX^gVz4t3pKiFl6xqW4yRYP1j|sUTs6|i>l3Ve{nSwiG zcI}bKt6xOlOMs1?SAb;Y`SMxHxNK#UQ@Xe0(X7H_*EI~2j^zOTRSi?yTYY5XB0LAJ(U$e@vv^KqsETb=Ua!2irqUV7`dnm;lbU%e?qI7O8WI0|{xXf`&!sg#N z*okk%CR(Rz>ie8Elu*a3G*@>vl8$9-`cDDJsqBzq_|LKKbYkSQWdqVPc(!aFTjW~e zG?GBJ5G&zRISfsYZsQP$)W3#fjxKWQ;8BKdWyhAh?qLavDV630`(7AV;{KViUx{3a zmz1h&4y=((-9{km675@gx{66-a+vMS8c%vTfcpe!9B-bM(yUO!u&i(o(y|MK>|S*T zHK>bE?K_58{Pv<1Y^=n8dEuV{+^GbU4qfVnaQl3IHLDp6}nWvsYdp<57k>K;48DIWw!hAY4L&JFh--9Z#oyebfKCB{gsmAZa3 zCQw^0U>qK0m_EiIY9DWLxfv}{c9vlK=t$aUj60hHh42BYxrSAP(J^l@> z$z_LY$Ye`u5B;+M$5LYUI$W5|hmrDEmbg`p=QQ@UT?CaOG}sBTg0ee`nDC{115Gv` zMkmd`XQIk+4?ciP5iIx{@J|xQhRJ-Q`T8uDhhwYxcXPTidywI_kVwU?Ib=Syfly~~ zZH~)PTlC!FLm7YNg*B8eTA{q?5WSSge+I>#v5HjEbwHNg5vJP~j?Tuz_!d8mJxH*| zjVojs*fR%i?L^6(pz3CP(C8O3MWj}%s6eg@RyWx{FtXZf9`D;8A$K3%!Hn2>JrGc_ z3Ru(eWkI-tOqu-uh?q?b%q6kuqWjqwr+in4B&x;Ne|h0I3~O?#c8@}Sr_~HYZ;qR+ ziPTK!w$PD{%|oD_D{*Ob@Cxh{mY%lIa_)Kvq_U9QY_IZok)Q)yuQaZ*SEFh*s8UD= zSJw5p|L>29!2tMt%$Jp1gFM}evB%oTbL#}kV=MoxvVl_LY&*y_sF zvowsG3#?HC(^4s*2ckR&@Hv4mXM4LooUZCYEl4`8RS)e3P?ENz6TPVe^J42bx5tMc z>x!;{0;oxZz7-u;Vh_aN&c0x0Dky@uSK-5x^7qNi<8qF>8|zt?JBt}8+}g^v8!dxV gMoYrLm+F-N1M82l_OpCl^Z)<=07*qoM6N<$g1e6Q^Z)<= literal 0 HcmV?d00001 diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl new file mode 100644 index 0000000000..7d7b7b18aa --- /dev/null +++ b/files/shaders/water_vertex.glsl @@ -0,0 +1,22 @@ +#version 120 + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + 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); + + vec4 texcoordProj = ((scalemat) * ( gl_Position)); + screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + position = gl_Vertex; + + depthPassthrough = gl_Position.z; +} From 700a0099c3737f9cb1c976459a6cfa2073667908 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 16:13:40 +0100 Subject: [PATCH 1187/1812] Remove debug code --- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwrender/renderingmanager.cpp | 33 ----------------------- apps/openmw/mwrender/sky.cpp | 5 +--- apps/openmw/mwrender/water.cpp | 2 -- apps/openmw/mwrender/water.hpp | 3 --- 5 files changed, 3 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 17f0ce73c0..0b3838a33b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -324,9 +324,9 @@ public: virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) { - //renderInfo.getState()->applyAttribute(mDepth); + renderInfo.getState()->applyAttribute(mDepth); - //glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); bin->drawImplementation(renderInfo, previous); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2aaba30356..b9132dc8c7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -198,39 +198,6 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); - - /* - osg::Texture2D* texture = new osg::Texture2D; - texture->setSourceFormat(GL_DEPTH_COMPONENT); - texture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); - texture->setSourceType(GL_UNSIGNED_INT); - - mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, texture); - - osg::ref_ptr camera (new osg::Camera); - camera->setProjectionMatrix(osg::Matrix::identity()); - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setViewMatrix(osg::Matrix::identity()); - camera->setClearMask(0); - camera->setRenderOrder(osg::Camera::NESTED_RENDER); - camera->setAllowEventFocus(false); - - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(0.5,0,0), osg::Vec3f(0,0.5,0)); - geode->addDrawable(geom); - - camera->addChild(geode); - - osg::StateSet* stateset = geom->getOrCreateStateSet(); - - stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - stateset->setRenderBinDetails(20, "RenderBin"); - stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - - mLightRoot->addChild(camera); - */ } RenderingManager::~RenderingManager() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 30dc089895..5938fb13c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,9 +1,6 @@ #include "sky.hpp" #include -#include - -#include #include #include @@ -264,7 +261,7 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cf361a5046..b2354924a8 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 78e8a4927f..a754646128 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,9 +9,6 @@ namespace osg { class Group; class PositionAttitudeTransform; - class Texture2D; - class Image; - class Camera; } namespace osgUtil From 37c9c12962f74fd26543b7cdf8b0063928c78e1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 18:54:49 +0100 Subject: [PATCH 1188/1812] Water: clipping plane offset --- apps/openmw/mwrender/water.cpp | 19 ++++++++++--------- files/shaders/water_fragment.glsl | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b2354924a8..97e0df1b65 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -142,8 +142,6 @@ class ClipCullNode : public osg::Group osg::Polytope::PlaneList origPlaneList = cv->getProjectionCullingStack().back().getFrustum().getPlaneList(); - // TODO: offset plane towards the viewer to fix bleeding at the water shore - osg::Plane plane = *mCullPlane; plane.transform(*cv->getCurrentRenderStage()->getInitialViewMatrix()); @@ -175,18 +173,21 @@ class ClipCullNode : public osg::Group { osgUtil::CullVisitor* cv = static_cast(nv); osg::Vec3d eyePoint = cv->getEyePoint(); + + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) { - osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); - - cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); - traverse(node, nv); - cv->popModelViewMatrix(); } - else - traverse(node, nv); + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = 5; + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * (-clipFudge)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); } private: diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 01e0816bc3..5860120abc 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -21,8 +21,8 @@ const float WAVE_CHOPPYNESS = 0.05; // wave choppyness const float WAVE_SCALE = 75.0; // overall wave scale const float BUMP = 0.5; // overall water surface bumpiness -const float REFL_BUMP = 0.15; // reflection distortion amount -const float REFR_BUMP = 0.06; // refraction distortion amount +const float REFL_BUMP = 0.10; // reflection distortion amount +const float REFR_BUMP = 0.07; // refraction distortion amount const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering From 9f2f503d3747533b6ea223829b998b1f0bd93c51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 18:59:35 +0100 Subject: [PATCH 1189/1812] Water: pass the near and far planes --- apps/openmw/mwrender/renderingmanager.cpp | 3 +++ files/shaders/water_fragment.glsl | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b9132dc8c7..dcf4406bbe 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -198,6 +198,9 @@ namespace MWRender mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } RenderingManager::~RenderingManager() diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 5860120abc..994d74964b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -68,6 +68,9 @@ uniform sampler2D normalMap; uniform float osg_SimulationTime; +uniform float near; +uniform float far; + void main(void) { // FIXME @@ -160,10 +163,8 @@ void main(void) #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; // make linear - float zNear = 5; // FIXME - float zFar = 6666; // FIXME float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)); + refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); float waterDepth = refractionDepth - depthPassthrough; From d485dd0782d95bca5f16a8841ca37c5677ea4efd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:11:32 +0100 Subject: [PATCH 1190/1812] Water: fix world UV coords --- apps/openmw/mwrender/water.cpp | 5 +++++ files/shaders/water_fragment.glsl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 97e0df1b65..b56f217540 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -458,6 +458,11 @@ void Water::changeCell(const MWWorld::CellStore* store) mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); else mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); + + // create a new StateSet to prevent threading issues + osg::ref_ptr nodeStateSet (new osg::StateSet); + nodeStateSet->addUniform(new osg::Uniform("nodePosition", osg::Vec3f(mWaterNode->getPosition()))); + mWaterNode->setStateSet(nodeStateSet); } void Water::setHeight(const float height) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 994d74964b..d7c0e1e6b6 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -70,11 +70,11 @@ uniform float osg_SimulationTime; uniform float near; uniform float far; +uniform vec3 nodePosition; void main(void) { - // FIXME - vec3 worldPos = position.xyz; // ((wMat) * ( position)).xyz; + vec3 worldPos = position.xyz + nodePosition.xyz; vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; From 51e40cf1b853e7aa6653750715eae9082b63c48d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:13:55 +0100 Subject: [PATCH 1191/1812] Water: minor shader cleanup --- files/shaders/water_fragment.glsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index d7c0e1e6b6..8dcd73faba 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -34,6 +34,8 @@ const float SPEC_HARDNESS = 256.0; // specular highlights hardne const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; +const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) @@ -160,6 +162,8 @@ void main(void) vec3 R = reflect(vVec, normal); float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + vec3 waterColor = WATER_COLOR; + waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; // make linear @@ -168,14 +172,12 @@ void main(void) float waterDepth = refractionDepth - depthPassthrough; - vec3 waterColor = vec3(0.090195, 0.115685, 0.12745); - waterColor = waterColor * length(gl_LightModel.ambient.xyz); if (cameraPos.z > 0.0) refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; #else - gl_FragData[0].xyz = mix(reflection, vec3(0.090195, 0.115685, 0.12745), (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; + gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; #endif // fog From 09631385c37f76821461d37e54623434fb9830f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:25:46 +0100 Subject: [PATCH 1192/1812] Use boost ifstream for water resources --- apps/openmw/mwrender/water.cpp | 45 ++++++++++++++++++++++++++++--- files/shaders/water_fragment.glsl | 1 - 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b56f217540..af9fae04a2 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -16,6 +16,9 @@ #include // XXX remove +#include +#include + #include #include @@ -264,6 +267,41 @@ void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) parent->addChild(debugCamera); } +osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) +{ + osg::ref_ptr shader (new osg::Shader(type)); + + // use boost in favor of osg::Shader::readShaderFile, to handle utf-8 path issues on Windows + boost::filesystem::ifstream inStream; + inStream.open(boost::filesystem::path(file)); + std::stringstream strstream; + strstream << inStream.rdbuf(); + shader->setShaderSource(strstream.str()); + return shader; +} + +osg::ref_ptr readPngImage (const std::string& file) +{ + // use boost in favor of osgDB::readImage, to handle utf-8 path issues on Windows + boost::filesystem::ifstream inStream; + inStream.open(file, std::ios_base::in | std::ios_base::binary); + if (inStream.fail()) + std::cerr << "Failed to open " << file << std::endl; + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!reader) + { + std::cerr << "Failed to read " << file << ", no png readerwriter found" << std::endl; + return osg::ref_ptr(); + } + osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream); + if (!result.success()) + std::cerr << "Failed to read " << file << ": " << result.message() << " code " << result.status() << std::endl; + + return result.getImage(); +} + + + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -399,17 +437,16 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem addDebugOverlay(reflectionTexture, 2, mParent); // shader - // FIXME: windows utf8 path handling? - osg::ref_ptr vertexShader (osg::Shader::readShaderFile(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); - osg::ref_ptr fragmentShader (osg::Shader::readShaderFile(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); - osg::ref_ptr normalMap (new osg::Texture2D(osgDB::readImageFile(resourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(resourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 8dcd73faba..c11c18a2d3 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -166,7 +166,6 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - // make linear float z_n = 2.0 * refractionDepth - 1.0; refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); From 6ba9f561ea9656034912075654b78c93605b59aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:39:22 +0100 Subject: [PATCH 1193/1812] Use simple water for the local map --- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/vismask.hpp | 13 +++++++------ apps/openmw/mwrender/water.cpp | 11 ++++++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index fe685f97c0..e479119ee1 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -173,7 +173,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene|Mask_Water|Mask_Terrain); + camera->setCullMask(Mask_Scene|Mask_SimpleWater|Mask_Terrain); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dcf4406bbe..b0fe98565e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -191,7 +191,7 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor)); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index fc63cddbb9..7faae46027 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -16,18 +16,19 @@ namespace MWRender Mask_Player = (1<<4), Mask_Sky = (1<<5), Mask_Water = (1<<6), - Mask_Terrain = (1<<7), - Mask_FirstPerson = (1<<8), + Mask_SimpleWater = (1<<7), + Mask_Terrain = (1<<8), + Mask_FirstPerson = (1<<9), // top level masks - Mask_Scene = (1<<9), - Mask_GUI = (1<<10), + Mask_Scene = (1<<10), + Mask_GUI = (1<<11), // Set on a Geode - Mask_ParticleSystem = (1<<11), + Mask_ParticleSystem = (1<<12), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<12) + Mask_RenderToTexture = (1<<13) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index af9fae04a2..c090dfbfe6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -301,7 +301,6 @@ osg::ref_ptr readPngImage (const std::string& file) } - Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -319,16 +318,18 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem geode->addDrawable(waterGeom); geode->setNodeMask(Mask_Water); - // TODO: node mask to use simple water for local map - if (ico) ico->add(geode); - //createSimpleWaterStateSet(mResourceSystem, geode); - mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(geode); + // simple water fallback for the local map + osg::ref_ptr geode2 (osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES)); + createSimpleWaterStateSet(mResourceSystem, geode2); + geode2->setNodeMask(Mask_SimpleWater); + mWaterNode->addChild(geode2); + mSceneRoot->addChild(mWaterNode); setHeight(mTop); From 7bbdb131383f566ba63f93f8533aad5af1931c32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:57:20 +0100 Subject: [PATCH 1194/1812] Remove debug code --- apps/openmw/mwrender/water.cpp | 35 +--------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c090dfbfe6..58e80a2714 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -14,7 +14,7 @@ #include #include -#include // XXX remove +#include #include #include @@ -239,34 +239,6 @@ public: } }; -void addDebugOverlay(osg::Texture2D* texture, int pos, osg::Group* parent) -{ - osg::ref_ptr debugCamera (new osg::Camera); - debugCamera->setProjectionMatrix(osg::Matrix::identity()); - debugCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - debugCamera->setViewMatrix(osg::Matrix::identity()); - debugCamera->setClearMask(0); - debugCamera->setRenderOrder(osg::Camera::NESTED_RENDER); - debugCamera->setAllowEventFocus(false); - - const float size = 0.5; - osg::ref_ptr debugGeode (new osg::Geode); - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1 + size*pos, -1, 0), osg::Vec3f(size,0,0), osg::Vec3f(0,size,0)); - debugGeode->addDrawable(geom); - - debugCamera->addChild(debugGeode); - - osg::StateSet* debugStateset = geom->getOrCreateStateSet(); - - debugStateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - debugStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - debugStateset->setRenderBinDetails(20, "RenderBin"); - debugStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - - parent->addChild(debugCamera); -} - osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) { osg::ref_ptr shader (new osg::Shader(type)); @@ -432,11 +404,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mParent->addChild(reflectionCamera); - // debug overlay - addDebugOverlay(refractionTexture, 0, mParent); - addDebugOverlay(refractionDepthTexture, 1, mParent); - addDebugOverlay(reflectionTexture, 2, mParent); - // shader osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); From ebdf25ccb942b0128facd18a06d36fb120d98ecf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 19:57:58 +0100 Subject: [PATCH 1195/1812] Water: move refraction code to a new class --- apps/openmw/mwrender/water.cpp | 136 +++++++++++++++++++++------------ apps/openmw/mwrender/water.hpp | 5 ++ 2 files changed, 94 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 58e80a2714..17e804052e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -273,6 +273,88 @@ osg::ref_ptr readPngImage (const std::string& file) } +class Refraction : public osg::Camera +{ +public: + Refraction() + { + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + setRenderOrder(osg::Camera::PRE_RENDER); + setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + setReferenceFrame(osg::Camera::RELATIVE_RF); + + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setNodeMask(Mask_RenderToTexture); + setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the scene is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + setUpdateCallback(new NoTraverseCallback); + + // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog + getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + mClipCullNode = new ClipCullNode; + addChild(mClipCullNode); + + mRefractionTexture = new osg::Texture2D; + mRefractionTexture->setTextureSize(rttSize, rttSize); + mRefractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mRefractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mRefractionTexture->setInternalFormat(GL_RGB); + mRefractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mRefractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + attach(osg::Camera::COLOR_BUFFER, mRefractionTexture); + + mRefractionDepthTexture = new osg::Texture2D; + mRefractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); + mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + mRefractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mRefractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT); + mRefractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); + } + + void setScene(osg::Node* scene) + { + if (mScene) + mClipCullNode->removeChild(mScene); + mScene = scene; + mClipCullNode->addChild(scene); + } + + void setWaterLevel(float waterLevel) + { + mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); + } + + osg::Texture2D* getRefractionTexture() const + { + return mRefractionTexture.get(); + } + + osg::Texture2D* getRefractionDepthTexture() const + { + return mRefractionDepthTexture.get(); + } + +private: + osg::ref_ptr mClipCullNode; + osg::ref_ptr mRefractionTexture; + osg::ref_ptr mRefractionDepthTexture; + osg::ref_ptr mScene; +}; + +class Reflection : public osg::Camera +{ + +}; + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -309,54 +391,13 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem const float waterLevel = -1; // refraction - unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); - osg::ref_ptr refractionCamera (new osg::Camera); - refractionCamera->setRenderOrder(osg::Camera::PRE_RENDER); - refractionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - refractionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - refractionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - refractionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); - refractionCamera->setNodeMask(Mask_RenderToTexture); - refractionCamera->setViewport(0, 0, rttSize, rttSize); - - // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph - // A double update would mess with the light collection (in addition to being plain redundant) - refractionCamera->setUpdateCallback(new NoTraverseCallback); - - // No need for fog here, we are already applying fog on the water surface itself as well as underwater fog - refractionCamera->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); - - osg::ref_ptr clipNode (new ClipCullNode); - clipNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel))); - - refractionCamera->addChild(clipNode); - clipNode->addChild(mSceneRoot); + mRefraction = new Refraction(); + mRefraction->setWaterLevel(waterLevel); + mRefraction->setScene(mSceneRoot); // TODO: add ingame setting for texture quality - osg::ref_ptr refractionTexture = new osg::Texture2D; - refractionTexture->setTextureSize(rttSize, rttSize); - refractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - refractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - refractionTexture->setInternalFormat(GL_RGB); - refractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - refractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - - refractionCamera->attach(osg::Camera::COLOR_BUFFER, refractionTexture); - - osg::ref_ptr refractionDepthTexture = new osg::Texture2D; - refractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); - refractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); - refractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - refractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - refractionDepthTexture->setSourceType(GL_UNSIGNED_INT); - refractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - refractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - - refractionCamera->attach(osg::Camera::DEPTH_BUFFER, refractionDepthTexture); - - mParent->addChild(refractionCamera); + mParent->addChild(mRefraction); // reflection osg::ref_ptr reflectionCamera (new osg::Camera); @@ -368,6 +409,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); reflectionCamera->setNodeMask(Mask_RenderToTexture); + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); reflectionCamera->setViewport(0, 0, rttSize, rttSize); // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph @@ -430,8 +472,8 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(1, refractionTexture, osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(2, refractionDepthTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index a754646128..46b6382e7b 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -29,6 +29,8 @@ namespace MWWorld namespace MWRender { + class Refraction; + class Reflection; class RippleSimulation; /// Water rendering @@ -44,6 +46,9 @@ namespace MWRender std::auto_ptr mSimulation; + osg::ref_ptr mRefraction; + osg::ref_ptr mReflection; + bool mEnabled; bool mToggled; float mTop; From 11c997d09d59ef846c566bf65e862e5aff36946b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 20:09:44 +0100 Subject: [PATCH 1196/1812] Water: move reflection code to a new class --- apps/openmw/mwrender/water.cpp | 107 ++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 17e804052e..f8a39f40b3 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -352,7 +352,66 @@ private: class Reflection : public osg::Camera { +public: + Reflection() + { + setRenderOrder(osg::Camera::PRE_RENDER); + setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + setReferenceFrame(osg::Camera::RELATIVE_RF); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setNodeMask(Mask_RenderToTexture); + + unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); + setViewport(0, 0, rttSize, rttSize); + + // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph + // A double update would mess with the light collection (in addition to being plain redundant) + setUpdateCallback(new NoTraverseCallback); + + mReflectionTexture = new osg::Texture2D; + mReflectionTexture->setInternalFormat(GL_RGB); + mReflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mReflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mReflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mReflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + attach(osg::Camera::COLOR_BUFFER, mReflectionTexture); + + // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. + osg::ref_ptr frontFace (new osg::FrontFace); + frontFace->setMode(osg::FrontFace::CLOCKWISE); + getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + + mClipCullNode = new ClipCullNode; + addChild(mClipCullNode); + } + + void setWaterLevel(float waterLevel) + { + setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); + + mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); + } + + void setScene(osg::Node* scene) + { + if (mScene) + mClipCullNode->removeChild(mScene); + mScene = scene; + mClipCullNode->addChild(scene); + } + + osg::Texture2D* getReflectionTexture() const + { + return mReflectionTexture.get(); + } + +private: + osg::ref_ptr mReflectionTexture; + osg::ref_ptr mClipCullNode; + osg::ref_ptr mScene; }; Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, @@ -400,51 +459,13 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mParent->addChild(mRefraction); // reflection - osg::ref_ptr reflectionCamera (new osg::Camera); - reflectionCamera->setRenderOrder(osg::Camera::PRE_RENDER); - reflectionCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - reflectionCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - reflectionCamera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - reflectionCamera->setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); - reflectionCamera->setNodeMask(Mask_RenderToTexture); - - unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); - reflectionCamera->setViewport(0, 0, rttSize, rttSize); - - // No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph - // A double update would mess with the light collection (in addition to being plain redundant) - reflectionCamera->setUpdateCallback(new NoTraverseCallback); - - osg::ref_ptr reflectionTexture = new osg::Texture2D; - reflectionTexture->setInternalFormat(GL_RGB); - reflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - reflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - reflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - reflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - - reflectionCamera->attach(osg::Camera::COLOR_BUFFER, reflectionTexture); - - reflectionCamera->setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); - - osg::ref_ptr reflectNode (new osg::MatrixTransform); - - // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. - osg::ref_ptr frontFace (new osg::FrontFace); - frontFace->setMode(osg::FrontFace::CLOCKWISE); - reflectNode->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); - - osg::ref_ptr clipNode2 (new ClipCullNode); - clipNode2->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); - - reflectNode->addChild(clipNode2); - clipNode2->addChild(mSceneRoot); - - reflectionCamera->addChild(reflectNode); + mReflection = new Reflection(); + mReflection->setWaterLevel(waterLevel); + mReflection->setScene(mSceneRoot); // TODO: add to waterNode so cameras don't get updated when water is hidden? - mParent->addChild(reflectionCamera); + mParent->addChild(mReflection); // shader @@ -471,7 +492,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); - shaderStateset->setTextureAttributeAndModes(0, reflectionTexture, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(0, mReflection->getReflectionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); From 9f8d36b57332c039f1850942aa435958cd5049d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 20:24:52 +0100 Subject: [PATCH 1197/1812] Water code cleanup --- apps/openmw/mwrender/water.cpp | 152 ++++++++++++++++-------------- apps/openmw/mwrender/water.hpp | 11 +++ files/shaders/water_fragment.glsl | 4 +- 3 files changed, 95 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f8a39f40b3..121b076541 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -82,41 +82,6 @@ namespace return waterGeom; } - void createSimpleWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) - { - osg::ref_ptr stateset (new osg::StateSet); - - osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setColorMode(osg::Material::OFF); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - - std::vector > textures; - for (int i=0; i<32; ++i) - { - std::ostringstream texname; - texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; - textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); - } - - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); - controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); - node->setStateSet(stateset); - stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); - } - } namespace MWRender @@ -419,6 +384,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) , mTop(0) @@ -427,19 +393,19 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(waterGeom); - geode->setNodeMask(Mask_Water); + mWaterGeode = new osg::Geode; + mWaterGeode->addDrawable(waterGeom); + mWaterGeode->setNodeMask(Mask_Water); if (ico) - ico->add(geode); + ico->add(mWaterGeode); mWaterNode = new osg::PositionAttitudeTransform; - mWaterNode->addChild(geode); + mWaterNode->addChild(mWaterGeode); // simple water fallback for the local map - osg::ref_ptr geode2 (osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(mResourceSystem, geode2); + osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); + createSimpleWaterStateSet(geode2); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -453,31 +419,65 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mRefraction = new Refraction(); mRefraction->setWaterLevel(waterLevel); mRefraction->setScene(mSceneRoot); - - // TODO: add ingame setting for texture quality - mParent->addChild(mRefraction); // reflection mReflection = new Reflection(); mReflection->setWaterLevel(waterLevel); mReflection->setScene(mSceneRoot); - - // TODO: add to waterNode so cameras don't get updated when water is hidden? - mParent->addChild(mReflection); - // shader + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + // TODO: add ingame setting for texture quality +} - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); +void Water::createSimpleWaterStateSet(osg::Node* node) +{ + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); + + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); +} + +void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) +{ + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); - osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(resourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); @@ -487,26 +487,33 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr shaderStateset = new osg::StateSet; shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - shaderStateset->addUniform(new osg::Uniform("reflectionMap", 0)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); - shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); + shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); + shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); + + shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); + if (refraction) + { + shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); + shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); + } + else + { + shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); + + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + } - shaderStateset->setTextureAttributeAndModes(0, mReflection->getReflectionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); - shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - // TODO: render after transparent bin when refraction is on - shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - - geode->setStateSet(shaderStateset); + node->setStateSet(shaderStateset); } Water::~Water() @@ -551,7 +558,12 @@ void Water::update(float dt) void Water::updateVisible() { - mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); + unsigned int mask = mEnabled && mToggled ? ~0 : 0; + mWaterNode->setNodeMask(mask); + if (mRefraction) + mRefraction->setNodeMask(mask); + if (mReflection) + mReflection->setNodeMask(mask); } bool Water::toggle() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 46b6382e7b..857f7fbb09 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,8 @@ namespace osg { class Group; class PositionAttitudeTransform; + class Geode; + class Node; } namespace osgUtil @@ -41,6 +43,7 @@ namespace MWRender osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; + osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; @@ -49,6 +52,8 @@ namespace MWRender osg::ref_ptr mRefraction; osg::ref_ptr mReflection; + const std::string mResourcePath; + bool mEnabled; bool mToggled; float mTop; @@ -56,6 +61,12 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); + void createSimpleWaterStateSet(osg::Node* node); + + /// @param reflection the reflection camera (required) + /// @param refraction the refraction camera (optional) + void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c11c18a2d3..6f7b173bfd 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -60,13 +60,13 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +uniform sampler2D normalMap; + uniform sampler2D reflectionMap; #if REFRACTION uniform sampler2D refractionMap; uniform sampler2D refractionDepthMap; #endif - -uniform sampler2D normalMap; uniform float osg_SimulationTime; From 8433e0679f0b0c8bbb2fb8625d83196b9586eee1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:22:14 +0100 Subject: [PATCH 1198/1812] Water: connect to settings window --- apps/openmw/mwrender/renderingmanager.cpp | 2 + apps/openmw/mwrender/water.cpp | 80 +++++++++++++++++++---- apps/openmw/mwrender/water.hpp | 5 ++ files/shaders/water_fragment.glsl | 4 +- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b0fe98565e..1370631bc0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -785,6 +785,8 @@ namespace MWRender } else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) updateTextureFiltering(); + else if (it->first == "Water") + mWater->processChangedSettings(changed); } } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 121b076541..4b936ba303 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -204,7 +204,7 @@ public: } }; -osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) +osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -213,7 +213,17 @@ osg::ref_ptr readShader (osg::Shader::Type type, const std::string& inStream.open(boost::filesystem::path(file)); std::stringstream strstream; strstream << inStream.rdbuf(); - shader->setShaderSource(strstream.str()); + + std::string shaderSource = strstream.str(); + + for (std::map::const_iterator it = defineMap.begin(); it != defineMap.end(); ++it) + { + size_t pos = shaderSource.find(it->first); + if (pos != std::string::npos) + shaderSource.replace(pos, it->first.length(), it->second); + } + + shader->setShaderSource(shaderSource); return shader; } @@ -429,7 +439,44 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + updateWaterMaterial(); +} + +void Water::updateWaterMaterial() +{ // TODO: add ingame setting for texture quality + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } + + if (Settings::Manager::getBool("shader", "Water")) + { + mReflection = new Reflection; + mReflection->setWaterLevel(mTop); + mReflection->setScene(mSceneRoot); + mParent->addChild(mReflection); + + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction; + mRefraction->setWaterLevel(mTop); + mRefraction->setScene(mSceneRoot); + mParent->addChild(mRefraction); + } + + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + } + else + createSimpleWaterStateSet(mWaterGeode); + + updateVisible(); } void Water::createSimpleWaterStateSet(osg::Node* node) @@ -462,20 +509,19 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); + node->setUpdateCallback(controller); node->setStateSet(stateset); stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); } void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) { - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + // use a define map to conditionally compile the shader + std::map defineMap; + defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); - - osg::ref_ptr program (new osg::Program); - program->addShader(vertexShader); - program->addShader(fragmentShader); + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); @@ -486,11 +532,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R normalMap->getImage()->flipVertical(); osg::ref_ptr shaderStateset = new osg::StateSet; - shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); @@ -498,6 +541,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R { shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else @@ -513,7 +558,18 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + osg::ref_ptr program (new osg::Program); + program->addShader(vertexShader); + program->addShader(fragmentShader); + shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + node->setStateSet(shaderStateset); + node->setUpdateCallback(NULL); +} + +void Water::processChangedSettings(const Settings::CategorySettingVector& settings) +{ + updateWaterMaterial(); } Water::~Water() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 857f7fbb09..f77afbfee8 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/cellstore.hpp" namespace osg @@ -67,6 +69,8 @@ namespace MWRender /// @param refraction the refraction camera (optional) void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + void updateWaterMaterial(); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, @@ -92,6 +96,7 @@ namespace MWRender void update(float dt); + void processChangedSettings(const Settings::CategorySettingVector& settings); }; } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6f7b173bfd..c04233fcf0 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,8 +1,8 @@ #version 120 -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +#define REFRACTION @refraction_enabled -#define REFRACTION 1 +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- From 8cb2c7a9fbb55b7748867b2a48598c891821a12a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:25:16 +0100 Subject: [PATCH 1199/1812] Water: remove defunct "reflect " settings Not really useful --- files/mygui/openmw_settings_window.layout | 30 ----------------------- files/settings-default.cfg | 3 --- 2 files changed, 33 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 19e3bcf886..4b2e1cc27d 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -369,36 +369,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 274a31315c..7c809b9266 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -129,9 +129,6 @@ shader = false refraction = false rtt size = 512 -reflect terrain = true -reflect statics = false -reflect actors = false [Sound] # Device name. Blank means default From 60bc7dbabcc9f1819419f1356837f6278ce295cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:38:34 +0100 Subject: [PATCH 1200/1812] Improve MW_ComboBox skin --- files/mygui/openmw_resources.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 305cb0c0da..ab68993417 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -101,7 +101,7 @@ - + From c9d7078b4b0e648e5aa4c544f4d2390563a0b2d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 21:49:01 +0100 Subject: [PATCH 1201/1812] Water: add texture quality setting to the settings window --- apps/openmw/mwgui/settingswindow.cpp | 35 ++++++++++++++++------- apps/openmw/mwgui/settingswindow.hpp | 5 +++- apps/openmw/mwrender/water.cpp | 2 +- files/mygui/openmw_settings_window.layout | 29 +++++++++++++------ 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 3ab2a6ce3f..667dc0c285 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -177,10 +177,10 @@ namespace MWGui getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); - getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); + getWidget(mWaterTextureSize, "WaterTextureSize"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -204,6 +204,8 @@ namespace MWGui mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); + mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); + mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); @@ -239,11 +241,18 @@ namespace MWGui mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); + int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); + if (waterTextureSize >= 512) + mWaterTextureSize->setIndexSelected(0); + if (waterTextureSize >= 1024) + mWaterTextureSize->setIndexSelected(1); + if (waterTextureSize >= 2048) + mWaterTextureSize->setIndexSelected(2); + mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); if (!Settings::Manager::getBool("shaders", "Objects")) { - mRefractionButton->setEnabled(false); mShadowsEnabledButton->setEnabled(false); } @@ -324,6 +333,19 @@ namespace MWGui } } + void SettingsWindow::onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos) + { + int size = 0; + if (pos == 0) + size = 512; + else if (pos == 1) + size = 1024; + else if (pos == 2) + size = 2048; + Settings::Manager::setInt("rtt size", "Water", size); + apply(); + } + void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos) { Settings::Manager::setString("texture size", "Shadows", _sender->getItemNameAt(pos)); @@ -350,12 +372,6 @@ namespace MWGui { if (newState == false) { - // refraction needs shaders to display underwater fog - mRefractionButton->setCaptionWithReplacing("#{sOff}"); - mRefractionButton->setEnabled(false); - - Settings::Manager::setBool("refraction", "Water", false); - // shadows not supported mShadowsEnabledButton->setEnabled(false); mShadowsEnabledButton->setCaptionWithReplacing("#{sOff}"); @@ -363,9 +379,6 @@ namespace MWGui } else { - // re-enable - mRefractionButton->setEnabled(true); - mShadowsEnabledButton->setEnabled(true); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 79487c54b8..0369eb40ec 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -38,7 +38,8 @@ namespace MWGui MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; - MyGUI::Button* mRefractionButton; + + MyGUI::ComboBox* mWaterTextureSize; MyGUI::Button* mShadowsEnabledButton; MyGUI::ComboBox* mShadowsTextureSize; @@ -61,6 +62,8 @@ namespace MWGui void onResolutionCancel(); void highlightCurrentResolution(); + void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); + void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4b936ba303..8ab29c3a72 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -444,7 +444,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem void Water::updateWaterMaterial() { - // TODO: add ingame setting for texture quality if (mReflection) { mParent->removeChild(mReflection); @@ -543,6 +542,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); + // FIXME: zfighting with ripples shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 4b2e1cc27d..e76c3a7dbc 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -365,21 +365,32 @@ - + - - - - - - + + + + + + + + + - - + + + + + + + + + + From d394b0793f8b9918d2b5f0a74533877229f3b7fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 23:31:59 +0100 Subject: [PATCH 1202/1812] waterLevel fix --- apps/openmw/mwrender/water.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8ab29c3a72..f1ec66f4ba 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -423,22 +423,6 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - const float waterLevel = -1; - - // refraction - mRefraction = new Refraction(); - mRefraction->setWaterLevel(waterLevel); - mRefraction->setScene(mSceneRoot); - mParent->addChild(mRefraction); - - // reflection - mReflection = new Reflection(); - mReflection->setWaterLevel(waterLevel); - mReflection->setScene(mSceneRoot); - mParent->addChild(mReflection); - - createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); - updateWaterMaterial(); } @@ -605,6 +589,11 @@ void Water::setHeight(const float height) osg::Vec3f pos = mWaterNode->getPosition(); pos.z() = height; mWaterNode->setPosition(pos); + + if (mReflection) + mReflection->setWaterLevel(mTop); + if (mRefraction) + mRefraction->setWaterLevel(mTop); } void Water::update(float dt) From 9b8e45fc01405e15e1d7d61764f0af762f87aff7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Oct 2015 23:34:37 +0100 Subject: [PATCH 1203/1812] Fix ripple particles z-fighting with the water surface --- apps/openmw/mwrender/ripplesimulation.cpp | 6 ++++++ apps/openmw/mwrender/water.cpp | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index a7637f2e1a..5caee80462 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -55,6 +56,11 @@ namespace depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + osg::ref_ptr polygonOffset (new osg::PolygonOffset); + polygonOffset->setUnits(-1); + polygonOffset->setFactor(-1); + stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON); + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::ref_ptr mat (new osg::Material); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f1ec66f4ba..81f7c4e116 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -526,7 +526,6 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); - // FIXME: zfighting with ripples shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else From f336c6db87be04903c0a92ab0c749bfe290bb5f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 00:51:35 +0100 Subject: [PATCH 1204/1812] Fix LightSource crash --- components/sceneutil/lightmanager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 3e0329c8bf..c2a1779ede 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -76,7 +76,7 @@ namespace SceneUtil struct LightSourceTransform { - LightSource* mLightSource; + osg::ref_ptr mLightSource; osg::Matrix mWorldMatrix; }; @@ -84,7 +84,7 @@ namespace SceneUtil struct LightSourceViewBound { - LightSource* mLightSource; + osg::ref_ptr mLightSource; osg::BoundingSphere mViewBound; }; From 7692ae175a45b0d6f3b1db5ca4b94696cf7eb174 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 01:17:23 +0100 Subject: [PATCH 1205/1812] Disable sun rendering on the reflection camera Not needed, we have specular highlights. --- apps/openmw/mwrender/sky.cpp | 1 + apps/openmw/mwrender/vismask.hpp | 17 +++++++++-------- apps/openmw/mwrender/water.cpp | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5938fb13c6..b0af85c0b6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -411,6 +411,7 @@ public: , mUpdater(new Updater) { mTransform->addUpdateCallback(mUpdater); + mTransform->setNodeMask(Mask_Sun); osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", osg::Texture::CLAMP, diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 7faae46027..b1329e9588 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,20 +15,21 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Water = (1<<6), - Mask_SimpleWater = (1<<7), - Mask_Terrain = (1<<8), - Mask_FirstPerson = (1<<9), + Mask_Sun = (1<<6), + Mask_Water = (1<<7), + Mask_SimpleWater = (1<<8), + Mask_Terrain = (1<<9), + Mask_FirstPerson = (1<<10), // top level masks - Mask_Scene = (1<<10), - Mask_GUI = (1<<11), + Mask_Scene = (1<<11), + Mask_GUI = (1<<12), // Set on a Geode - Mask_ParticleSystem = (1<<12), + Mask_ParticleSystem = (1<<13), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<13) + Mask_RenderToTexture = (1<<14) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 81f7c4e116..09143a3bd6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -259,7 +259,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); From ad4e0e3b971d4eb0203fe11b0adc7b1fea0ed6cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Oct 2015 11:20:06 +0100 Subject: [PATCH 1206/1812] split virtual select button into two buttons (primary select and seconadry select) --- apps/opencs/model/settings/usersettings.cpp | 10 ++++++--- apps/opencs/view/render/editmode.cpp | 11 ++++++++-- apps/opencs/view/render/editmode.hpp | 12 +++++++++-- apps/opencs/view/render/instancemode.cpp | 22 +++++++++++++++++--- apps/opencs/view/render/instancemode.hpp | 4 +++- apps/opencs/view/render/worldspacewidget.cpp | 22 +++++++++++++------- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 3e5ab24d13..e8568cac10 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -399,9 +399,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() secondaryEditing->setDeclaredValues (values); secondaryEditing->setDefaultValue (cRight); - Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button"); - selection->setDeclaredValues (values); - selection->setDefaultValue (middle); + Setting *primarySelection = createSetting (Type_ComboBox, "p-select", "Selection Button"); + primarySelection->setDeclaredValues (values); + primarySelection->setDefaultValue (middle); + + Setting *secondarySelection = createSetting (Type_ComboBox, "s-select", "Selection Button"); + secondarySelection->setDeclaredValues (values); + secondarySelection->setDefaultValue (cMiddle); Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); contextSensitive->setDefaultValue ("false"); diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 4235faf768..4c6f2bd438 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -38,7 +38,9 @@ void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr tag) {} void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr tag) {} -void CSVRender::EditMode::selectPressed (osg::ref_ptr tag) {} +void CSVRender::EditMode::primarySelectPressed (osg::ref_ptr tag) {} + +void CSVRender::EditMode::secondarySelectPressed (osg::ref_ptr tag) {} bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr tag) { @@ -50,7 +52,12 @@ bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr tag) return false; } -bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr tag) +bool CSVRender::EditMode::primarySelectStartDrag (osg::ref_ptr tag) +{ + return false; +} + +bool CSVRender::EditMode::secondarySelectStartDrag (osg::ref_ptr tag) { return false; } diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 77676d6a3f..c17616b569 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -43,7 +43,10 @@ namespace CSVRender virtual void secondaryEditPressed (osg::ref_ptr tag); /// Default-implementation: Ignored. - virtual void selectPressed (osg::ref_ptr tag); + virtual void primarySelectPressed (osg::ref_ptr tag); + + /// Default-implementation: Ignored. + virtual void secondarySelectPressed (osg::ref_ptr tag); /// Default-implementation: ignore and return false /// @@ -58,7 +61,12 @@ namespace CSVRender /// Default-implementation: ignore and return false /// /// \return Drag accepted? - virtual bool selectStartDrag (osg::ref_ptr tag); + virtual bool primarySelectStartDrag (osg::ref_ptr tag); + + /// Default-implementation: ignore and return false + /// + /// \return Drag accepted? + virtual bool secondarySelectStartDrag (osg::ref_ptr tag); /// Default-implementation: ignored virtual void drag (int diffX, int diffY, double speedFactor); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 333d916565..fdd031ad46 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -30,16 +30,32 @@ void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStr void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { if (mContextSelect) - selectPressed (tag); + primarySelectPressed (tag); } void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) { if (mContextSelect) - selectPressed (tag); + secondarySelectPressed (tag); } -void CSVRender::InstanceMode::selectPressed (osg::ref_ptr tag) +void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr tag) +{ + if (tag) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected (!object->getSelected()); + return; + } + } + + getWorldspaceWidget().clearSelection (Element_Reference); +} + +void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) { if (tag) { diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index cc4fd54349..50bd8243d3 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -23,7 +23,9 @@ namespace CSVRender virtual void secondaryEditPressed (osg::ref_ptr tag); - virtual void selectPressed (osg::ref_ptr tag); + virtual void primarySelectPressed (osg::ref_ptr tag); + + virtual void secondarySelectPressed (osg::ref_ptr tag); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 46c5867ebf..e76582b945 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -36,7 +36,7 @@ namespace { "p-navi", "s-navi", "p-edit", "s-edit", - "select", + "p-select", "s-select", 0 }; } @@ -513,7 +513,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { } - else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select") { osg::ref_ptr tag = mousePick (event); @@ -523,8 +523,10 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragging = editMode.primaryEditStartDrag (tag); else if (mDragMode=="s-edit") mDragging = editMode.secondaryEditStartDrag (tag); - else if (mDragMode=="select") - mDragging = editMode.selectStartDrag (tag); + else if (mDragMode=="p-select") + mDragging = editMode.primarySelectStartDrag (tag); + else if (mDragMode=="s-select") + mDragging = editMode.secondarySelectStartDrag (tag); if (mDragging) { @@ -575,7 +577,8 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { } - else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select") + else if (mDragMode=="p-edit" || mDragMode=="s-edit" || + mDragMode=="p-select" || mDragMode=="s-select") { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -589,7 +592,8 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { } - else if (button=="p-edit" || button=="s-edit" || button=="select") + else if (button=="p-edit" || button=="s-edit" || + button=="p-select" || button=="s-select") { osg::ref_ptr tag = mousePick (event); @@ -647,6 +651,8 @@ void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, c editMode.primaryEditPressed (tag); else if (button=="s-edit") editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + else if (button=="p-select") + editMode.primarySelectPressed (tag); + else if (button=="s-select") + editMode.secondarySelectPressed (tag); } From 655b40267b9aa24587620694866e244a2a44023d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Oct 2015 11:27:01 +0100 Subject: [PATCH 1207/1812] changed instance selection model (primary selects, secondary toggles selection) --- apps/opencs/view/render/instancemode.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index fdd031ad46..8f0526443a 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -41,18 +41,18 @@ void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) void CSVRender::InstanceMode::primarySelectPressed (osg::ref_ptr tag) { + getWorldspaceWidget().clearSelection (Element_Reference); + if (tag) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) { - // hit an Object, toggle its selection state + // hit an Object, select it CSVRender::Object* object = objectTag->mObject; - object->setSelected (!object->getSelected()); + object->setSelected (true); return; } } - - getWorldspaceWidget().clearSelection (Element_Reference); } void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) @@ -67,6 +67,4 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) return; } } - - getWorldspaceWidget().clearSelection (Element_Reference); } From d90fa977e8ac58656d123113970dc7121a371c85 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 Oct 2015 13:52:48 +0100 Subject: [PATCH 1208/1812] GL_DEPTH_COMPONEN24 fix --- apps/openmw/mwrender/water.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 09143a3bd6..8c50fbde13 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -285,7 +285,7 @@ public: mRefractionDepthTexture = new osg::Texture2D; mRefractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT); - mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24_ARB); + mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24); mRefractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); mRefractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT); From b9b154a01598e62f01e474e5c295501d8aa0f8d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 00:01:12 +0100 Subject: [PATCH 1209/1812] Minor cleanup --- apps/openmw/mwrender/renderingmanager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1370631bc0..03a44a4e61 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -487,12 +487,9 @@ namespace MWRender rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); - rttCamera->setClearColor(mViewer->getCamera()->getClearColor()); - rttCamera->setClearMask(mViewer->getCamera()->getClearMask()); rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); rttCamera->setViewport(0, 0, w, h); - rttCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); osg::ref_ptr texture (new osg::Texture2D); texture->setInternalFormat(GL_RGB); From 93f4d31cf94047bf9f0c72e52c072816b20975db Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 01:30:02 +0100 Subject: [PATCH 1210/1812] Raytest mask fix (Fixes #2984) --- apps/openmw/mwrender/renderingmanager.cpp | 38 ++++++++++------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 03a44a4e61..da81b23b1a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -588,23 +588,27 @@ namespace MWRender } + osg::ref_ptr createIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors) + { + osg::ref_ptr intersectionVisitor( new osgUtil::IntersectionVisitor(intersector)); + int mask = intersectionVisitor->getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water|Mask_SimpleWater); + if (ignorePlayer) + mask &= ~(Mask_Player); + if (ignoreActors) + mask &= ~(Mask_Actor|Mask_Player); + + intersectionVisitor->setTraversalMask(mask); + return intersectionVisitor; + } + RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest)); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - osgUtil::IntersectionVisitor intersectionVisitor(intersector); - int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); - if (ignorePlayer) - mask &= ~(Mask_Player); - if (ignoreActors) - mask &= ~(Mask_Actor|Mask_Player); - - intersectionVisitor.setTraversalMask(mask); - - mRootNode->accept(intersectionVisitor); + mRootNode->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); return getIntersectionResult(intersector); } @@ -623,17 +627,7 @@ namespace MWRender intersector->setEnd(end); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - osgUtil::IntersectionVisitor intersectionVisitor(intersector); - int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); - if (ignorePlayer) - mask &= ~(Mask_Player); - if (ignoreActors) - mask &= ~(Mask_Actor|Mask_Player); - - intersectionVisitor.setTraversalMask(mask); - - mViewer->getCamera()->accept(intersectionVisitor); + mViewer->getCamera()->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); return getIntersectionResult(intersector); } From 7b817ba010c9b643e81d0060be71b85e8170c81e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Oct 2015 03:14:05 +0100 Subject: [PATCH 1211/1812] Fix the node masks of water cameras being reset (Bug #2984) Node mask needs to remain Mask_RenderToTexture so the raytesting visitor won't go through the reflection graph. --- apps/openmw/mwrender/water.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8c50fbde13..251a1232cd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -602,12 +602,12 @@ void Water::update(float dt) void Water::updateVisible() { - unsigned int mask = mEnabled && mToggled ? ~0 : 0; - mWaterNode->setNodeMask(mask); + bool visible = mEnabled && mToggled; + mWaterNode->setNodeMask(visible ? ~0 : 0); if (mRefraction) - mRefraction->setNodeMask(mask); + mRefraction->setNodeMask(visible ? Mask_RenderToTexture : 0); if (mReflection) - mReflection->setNodeMask(mask); + mReflection->setNodeMask(visible ? Mask_RenderToTexture : 0); } bool Water::toggle() From 78c735adc609dda06954746b31cea4289a7060ad Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 31 Oct 2015 20:42:42 +1100 Subject: [PATCH 1212/1812] Fix saving when only topic info was modified (topic itself unchanged) --- apps/opencs/model/doc/savingstages.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index c6d8a8cb34..138e84b9a4 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -134,10 +134,21 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message state==CSMWorld::RecordBase::State_ModifiedOnly || infoModified) { - mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); - topic.mModified.save (mState.getWriter()); - mState.getWriter().endRecord (topic.mModified.sRecordId); + if (infoModified && state != CSMWorld::RecordBase::State_Modified + && state != CSMWorld::RecordBase::State_ModifiedOnly) + { + mState.getWriter().startRecord (topic.mBase.sRecordId); + mState.getWriter().writeHNCString ("NAME", topic.mBase.mId); + topic.mBase.save (mState.getWriter()); + mState.getWriter().endRecord (topic.mBase.sRecordId); + } + else + { + mState.getWriter().startRecord (topic.mModified.sRecordId); + mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); + topic.mModified.save (mState.getWriter()); + mState.getWriter().endRecord (topic.mModified.sRecordId); + } // write modified selected info records for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; From 7c007d9c6d530126075165766a8c497bd3de7d62 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 31 Oct 2015 20:45:16 +1100 Subject: [PATCH 1213/1812] Rename a variable to make it less confusing. --- apps/opencs/model/doc/savingstages.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 138e84b9a4..3fba2cd85c 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -154,14 +154,14 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) { - CSMWorld::RecordBase::State state = iter->mState; + CSMWorld::RecordBase::State infoState = iter->mState; - if (state==CSMWorld::RecordBase::State_Deleted) + if (infoState==CSMWorld::RecordBase::State_Deleted) { /// \todo wrote record with delete flag } - else if (state==CSMWorld::RecordBase::State_Modified || - state==CSMWorld::RecordBase::State_ModifiedOnly) + else if (infoState==CSMWorld::RecordBase::State_Modified || + infoState==CSMWorld::RecordBase::State_ModifiedOnly) { ESM::DialInfo info = iter->get(); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); From 819fecd08ec163e3f6b94ca40330f68214d54579 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Nov 2015 11:23:28 +1100 Subject: [PATCH 1214/1812] Add a check for scale value of 0. Should resolve bug #2880. --- apps/opencs/model/tools/referenceablecheck.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 6b323547f0..336a5e7132 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -468,6 +468,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures messages.push_back (std::make_pair (id, creature.mId + " has negative gold ")); + if (creature.mScale == 0) + messages.push_back (std::make_pair (id, creature.mId + " has zero scale value")); + // Check that mentioned scripts exist scriptCheck(creature, messages, id.toString()); } From 4af469511da373c48d7b3eaa0b4e1eb37971558c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Nov 2015 06:43:20 +1100 Subject: [PATCH 1215/1812] Fix some sub-tables becoming uneditable since commit 80869d --- apps/opencs/model/world/refidadapterimp.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 93d4ce8940..b1004da989 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -596,16 +596,16 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mSpells) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mDestinations) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); if (column==mActors.mAiPackages) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); std::map::const_iterator iter = mActors.mServices.find (column); @@ -2080,7 +2080,7 @@ namespace CSMWorld int index) const { if (column==mLevList.mLevList || column == mLevList.mNestedListLevList) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return QVariant::fromValue(ColumnBase::TableEdit_Full); return BaseRefIdAdapter::getData (column, data, index); } From 7f477e2fae47bdfe78ac17b2622ed2fdd844fd98 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Nov 2015 06:57:24 +1100 Subject: [PATCH 1216/1812] Fix include file issue. --- apps/opencs/model/world/refidadapterimp.cpp | 1 - apps/opencs/model/world/refidadapterimp.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 860fc9bdf5..90a710fc89 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -7,7 +7,6 @@ #include #include -#include "columnbase.hpp" #include "nestedtablewrapper.hpp" CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index b1004da989..eff7167def 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -11,6 +11,7 @@ #include #include +#include "columnbase.hpp" #include "record.hpp" #include "refiddata.hpp" #include "universalid.hpp" From bd9dc5856030763aa49a412fc5942288d2e5a2af Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 21:45:58 +0100 Subject: [PATCH 1217/1812] Use the correct scale for actor swim height (Fixes #2833) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 3 ++- apps/openmw/mwclass/npc.cpp | 6 +++++- apps/openmw/mwclass/npc.hpp | 3 ++- apps/openmw/mwphysics/actor.cpp | 13 ++++++++++--- apps/openmw/mwphysics/actor.hpp | 10 +++++++++- apps/openmw/mwphysics/physicssystem.cpp | 11 ++++++++++- apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 13 files changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 450889eb2a..95bc429e3b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -774,7 +774,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const + void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const { MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255e..55127eefcf 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -133,7 +133,8 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9fa2cc6037..5679dc3e9e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1012,8 +1012,12 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const + void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const { + if (!rendering) + return; // collision meshes are not scaled based on race height + // having the same collision extents for all races makes the environments easier to test + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d919131db9..c2d2ca8fa6 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -109,7 +109,8 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const; + virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 94d93e7d7a..a681c79452 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -110,12 +110,14 @@ void Actor::updateScale() float scale = mPtr.getCellRef().getScale(); osg::Vec3f scaleVec(scale,scale,scale); - if (!mPtr.getClass().isNpc()) - mPtr.getClass().adjustScale(mPtr, scaleVec); - + mPtr.getClass().adjustScale(mPtr, scaleVec, false); mScale = scaleVec; mShape->setLocalScaling(toBullet(mScale)); + scaleVec = osg::Vec3f(scale,scale,scale); + mPtr.getClass().adjustScale(mPtr, scaleVec, true); + mRenderingScale = scaleVec; + updatePosition(); } @@ -124,6 +126,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getRenderingHalfExtents() const +{ + return osg::componentMultiply(mHalfExtents, mRenderingScale); +} + void Actor::setInertialForce(const osg::Vec3f &force) { mForce = force; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 7a12f549d4..a4afa48a11 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,10 +66,17 @@ namespace MWPhysics void updatePosition(); /** - * Returns the (scaled) half extents + * Returns the half extents of the collision body (scaled according to collision scale) */ osg::Vec3f getHalfExtents() const; + /** + * Returns the half extents of the collision body (scaled according to rendering scale) + * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, + * most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale. + */ + osg::Vec3f getRenderingHalfExtents() const; + /** * Sets the current amount of inertial force (incl. gravity) affecting this physic actor */ @@ -118,6 +125,7 @@ namespace MWPhysics osg::Quat mRotation; osg::Vec3f mScale; + osg::Vec3f mRenderingScale; osg::Vec3f mPosition; osg::Vec3f mForce; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e666161da9..80a63bf1b5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -261,7 +261,7 @@ namespace MWPhysics static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -878,6 +878,15 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if (physactor) + return physactor->getRenderingHalfExtents(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index db8da2886f..6f38653c89 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -110,6 +110,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + /// @see MWPhysics::Actor::getRenderingHalfExtents + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 93afeda25b..eb950ea795 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -287,7 +287,7 @@ namespace MWRender void InventoryPreview::onSetup() { osg::Vec3f scale (1.f, 1.f, 1.f); - mCharacter.getClass().adjustScale(mCharacter, scale); + mCharacter.getClass().adjustScale(mCharacter, scale, true); mNode->setScale(scale); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4c73c603bc..30fd42527b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -287,7 +287,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const + void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1157db6704..b2d3453af6 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -258,7 +258,8 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 459b3b6ca0..33e2ba17c9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -72,7 +72,7 @@ namespace { float scale = ptr.getCellRef().getScale(); osg::Vec3f scaleVec (scale, scale, scale); - ptr.getClass().adjustScale(ptr, scaleVec); + ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be86987e85..17118e169b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1969,7 +1969,7 @@ namespace MWWorld { osg::Vec3f pos (object.getRefData().getPosition().asVec3()); - pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z(); + pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); return isUnderwater(object.getCell(), pos); } From 8da4530957f1e64b031c513486cceeba311a8044 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:09:02 +0100 Subject: [PATCH 1218/1812] Use INI-imported underwater fog settings (Fixes #2907, Fixes #1511) --- apps/openmw/mwrender/renderingmanager.cpp | 17 +++++--- apps/openmw/mwrender/renderingmanager.hpp | 6 ++- apps/openmw/mwworld/weather.cpp | 53 ++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 7 +++ 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index da81b23b1a..e1c0ea666a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,6 +31,8 @@ #include +#include "../mwworld/fallback.hpp" + #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" @@ -199,6 +201,10 @@ namespace MWRender updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); + mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor"); + mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight"); + mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog"); + mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } @@ -349,13 +355,14 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - configureFog (cell->mAmbi.mFogDensity, color); + configureFog (cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, color); } - void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, float underwaterFog, const osg::Vec4f &color) { mFogDepth = fogDepth; mFogColor = color; + mUnderwaterFog = underwaterFog; } SkyManager* RenderingManager::getSkyManager() @@ -378,9 +385,9 @@ namespace MWRender mCamera->getPosition(focal, cameraPos); if (mWater->isUnderwater(cameraPos)) { - setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); - mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(1000); + setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); + mStateUpdater->setFogStart(mViewDistance * (1 - mUnderwaterFog)); + mStateUpdater->setFogEnd(mViewDistance); } else { diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1ddab73387..3e17ef4137 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -79,7 +79,7 @@ namespace MWRender void configureAmbient(const ESM::Cell* cell); void configureFog(const ESM::Cell* cell); - void configureFog(float fogDepth, const osg::Vec4f& colour); + void configureFog(float fogDepth, float underwaterFog, const osg::Vec4f& colour); void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); @@ -192,6 +192,10 @@ namespace MWRender osg::ref_ptr mStateUpdater; float mFogDepth; + osg::Vec4f mUnderwaterColor; + float mUnderwaterWeight; + float mUnderwaterFog; + float mUnderwaterIndoorFog; osg::Vec4f mFogColor; osg::Vec4f mAmbientColor; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5008d8fbfc..8920c17b41 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -438,6 +438,10 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mDayEnd(mSunsetTime) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) + , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) + , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) + , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -624,6 +628,53 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + // TODO: use pre/post sunset/sunrise time values in [Weather] section + // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() + float gameHour = time.getHour(); + float underwaterFog; + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + underwaterFog = mUnderwaterNightFog; + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); + } + } + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + underwaterFog = mUnderwaterDayFog; + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); + } + } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) mRendering.getSkyManager()->setGlareTimeOfDayFade(0); @@ -635,7 +686,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7ce7c1bf84..a1a7d30774 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -249,6 +249,13 @@ namespace MWWorld float mDayEnd; float mHoursBetweenWeatherChanges; float mRainSpeed; + + // underwater fog not really related to weather, but we handle it here because it's convenient + float mUnderwaterSunriseFog; + float mUnderwaterDayFog; + float mUnderwaterSunsetFog; + float mUnderwaterNightFog; + std::vector mWeatherSettings; MoonModel mMasser; MoonModel mSecunda; From 45bf3e6788a8d6649c0bb5e7771bcbe8abc6f8d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:47:40 +0100 Subject: [PATCH 1219/1812] Create TimeOfDayInterpolator class to refactor time handling in WeatherManager --- apps/openmw/mwworld/weather.cpp | 243 +++++++++++++------------------- apps/openmw/mwworld/weather.hpp | 73 ++++++---- 2 files changed, 138 insertions(+), 178 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8920c17b41..ed43059f4f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -31,17 +31,74 @@ namespace { static const int invalidWeatherID = -1; + // linear interpolate between x and y based on factor. float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; } - + // linear interpolate between x and y based on factor. osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } } +template +T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings) const +{ + // TODO: use pre/post sunset/sunrise time values in [Weather] section + + // night + if (gameHour <= timeSettings.mNightEnd || gameHour >= timeSettings.mNightStart + 1) + return mNightValue; + // sunrise + else if (gameHour >= timeSettings.mNightEnd && gameHour <= timeSettings.mDayStart + 1) + { + if (gameHour <= timeSettings.mSunriseTime) + { + // fade in + float advance = timeSettings.mSunriseTime - gameHour; + float factor = advance / 0.5f; + return lerp(mSunriseValue, mNightValue, factor); + } + else + { + // fade out + float advance = gameHour - timeSettings.mSunriseTime; + float factor = advance / 3.f; + return lerp(mSunriseValue, mDayValue, factor); + } + } + // day + else if (gameHour >= timeSettings.mDayStart + 1 && gameHour <= timeSettings.mDayEnd - 1) + return mDayValue; + // sunset + else if (gameHour >= timeSettings.mDayEnd - 1 && gameHour <= timeSettings.mNightStart + 1) + { + if (gameHour <= timeSettings.mDayEnd + 1) + { + // fade in + float advance = (timeSettings.mDayEnd + 1) - gameHour; + float factor = (advance / 2); + return lerp(mSunsetValue, mDayValue, factor); + } + else + { + // fade out + float advance = gameHour - (timeSettings.mDayEnd + 1); + float factor = advance / 2.f; + return lerp(mSunsetValue, mNightValue, factor); + } + } + // shut up compiler + return T(); +} + + + +template class TimeOfDayInterpolator; +template class TimeOfDayInterpolator; + Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, @@ -49,22 +106,22 @@ Weather::Weather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) - , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) - , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) - , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) - , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) - , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) - , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) - , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) - , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) - , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) - , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) - , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) - , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) - , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) - , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) - , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) - , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) @@ -432,16 +489,13 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) - , mNightStart(mSunsetTime + mSunsetDuration) - , mNightEnd(mSunriseTime - 0.5f) - , mDayStart(mSunriseTime + mSunriseDuration) - , mDayEnd(mSunsetTime) + , mNightFade(0, 0, 0, 1) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) - , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) - , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) - , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) - , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) + , mUnderwaterFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog"), + fallback.getFallbackFloat("Water_UnderwaterDayFog"), + fallback.getFallbackFloat("Water_UnderwaterSunsetFog"), + fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -461,6 +515,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mAmbientSound() , mPlayingSoundID() { + mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; + mTimeSettings.mNightEnd = mSunriseTime - 0.5f; + mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration; + mTimeSettings.mDayEnd = mSunsetTime; + mTimeSettings.mSunriseTime = mSunriseTime; + mWeatherSettings.reserve(10); addWeather("Clear", fallback); // 0 addWeather("Cloudy", fallback); // 1 @@ -593,7 +653,7 @@ void WeatherManager::update(float duration, bool paused) } // disable sun during night - if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); else mRendering.getSkyManager()->sunEnable(); @@ -604,10 +664,10 @@ void WeatherManager::update(float duration, bool paused) { // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = time.getHour(); - float adjustedNightStart = mNightStart; + float adjustedNightStart = mTimeSettings.mNightStart; if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; - if ( mNightStart < mSunriseTime ) + if ( mTimeSettings.mNightStart < mSunriseTime ) adjustedNightStart += 24.f; const bool is_night = adjustedHour >= adjustedNightStart; @@ -628,52 +688,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() - float gameHour = time.getHour(); - float underwaterFog; - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - underwaterFog = mUnderwaterNightFog; - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); - } - } - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - underwaterFog = mUnderwaterDayFog; - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); - } - } + float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) @@ -748,7 +763,7 @@ bool WeatherManager::isDark() const TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1); } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) @@ -1026,81 +1041,15 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); - } - } - - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - } + mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); + mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); + mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); + mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings); + mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings); if (gameHour >= mSunsetTime - mSunPreSunsetTime) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a1a7d30774..86d1898fa9 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -34,6 +34,33 @@ namespace MWWorld class Fallback; class TimeStamp; + + struct TimeOfDaySettings + { + float mNightStart; + float mNightEnd; + float mDayStart; + float mDayEnd; + float mSunriseTime; + }; + + /// Interpolates between 4 data points (sunrise, day, sunset, night) based on the time of day. + /// The template value could be a floating point number, or a color. + template + class TimeOfDayInterpolator + { + public: + TimeOfDayInterpolator(const T& sunrise, const T& day, const T& sunset, const T& night) + : mSunriseValue(sunrise), mDayValue(day), mSunsetValue(sunset), mNightValue(night) + { + } + + T getValue (const float gameHour, const TimeOfDaySettings& timeSettings) const; + + private: + T mSunriseValue, mDayValue, mSunsetValue, mNightValue; + }; + /// Defines a single weather setting (according to INI) class Weather { @@ -47,29 +74,14 @@ namespace MWWorld std::string mCloudTexture; - // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor; - osg::Vec4f mSkyDayColor; - osg::Vec4f mSkySunsetColor; - osg::Vec4f mSkyNightColor; - - // Fog colors - osg::Vec4f mFogSunriseColor; - osg::Vec4f mFogDayColor; - osg::Vec4f mFogSunsetColor; - osg::Vec4f mFogNightColor; - - // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor; - osg::Vec4f mAmbientDayColor; - osg::Vec4f mAmbientSunsetColor; - osg::Vec4f mAmbientNightColor; - - // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor; - osg::Vec4f mSunDayColor; - osg::Vec4f mSunSunsetColor; - osg::Vec4f mSunNightColor; + // Sky (atmosphere) color + TimeOfDayInterpolator mSkyColor; + // Fog color + TimeOfDayInterpolator mFogColor; + // Ambient lighting color + TimeOfDayInterpolator mAmbientColor; + // Sun (directional) lighting color + TimeOfDayInterpolator mSunColor; // Fog depth/density float mLandFogDayDepth; @@ -243,18 +255,17 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mSunPreSunsetTime; - float mNightStart; - float mNightEnd; - float mDayStart; - float mDayEnd; + + TimeOfDaySettings mTimeSettings; + + // fading of night skydome + TimeOfDayInterpolator mNightFade; + float mHoursBetweenWeatherChanges; float mRainSpeed; // underwater fog not really related to weather, but we handle it here because it's convenient - float mUnderwaterSunriseFog; - float mUnderwaterDayFog; - float mUnderwaterSunsetFog; - float mUnderwaterNightFog; + TimeOfDayInterpolator mUnderwaterFog; std::vector mWeatherSettings; MoonModel mMasser; From 802620a86b08850f07a88b1eea1120d0b5ac1ea0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 23:03:16 +0100 Subject: [PATCH 1220/1812] Use TimeOfDayInterpolator for Land Fog Depth Fixes the sudden fog jump at nightfall. --- apps/openmw/mwworld/weather.cpp | 9 +++++---- apps/openmw/mwworld/weather.hpp | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ed43059f4f..24b45fcea6 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -122,8 +122,10 @@ Weather::Weather(const std::string& name, fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) - , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) - , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mLandFogDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) @@ -1043,8 +1045,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - + mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 86d1898fa9..4a78350fe4 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -84,8 +84,7 @@ namespace MWWorld TimeOfDayInterpolator mSunColor; // Fog depth/density - float mLandFogDayDepth; - float mLandFogNightDepth; + TimeOfDayInterpolator mLandFogDepth; // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; From 4690ec12cc80cada2d026caa6b1c6c560d8a7689 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:29:09 +0100 Subject: [PATCH 1221/1812] Render the water plane with GL_DEPTH_CLAMP if supported (Fixes #996) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 251a1232cd..20710ab7e9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -389,6 +390,24 @@ private: osg::ref_ptr mScene; }; +/// DepthClampCallback enables GL_DEPTH_CLAMP for the current draw, if supported. +class DepthClampCallback : public osg::Drawable::DrawCallback +{ +public: + virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const + { + if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + drawable->drawImplementation(renderInfo); + + glEnable(GL_DEPTH_CLAMP); + + drawable->drawImplementation(renderInfo); + + // restore default + glDisable(GL_DEPTH_CLAMP); + } +}; + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -402,6 +421,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); + waterGeom->setDrawCallback(new DepthClampCallback); mWaterGeode = new osg::Geode; mWaterGeode->addDrawable(waterGeom); From c60388afb68afa22d433f7d9dfaa4ea3e0a95a0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:30:18 +0100 Subject: [PATCH 1222/1812] Add fudge factor to move the water mesh away from camera when the camera gets too close --- apps/openmw/mwrender/water.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 20710ab7e9..c44f480f8d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -205,6 +205,36 @@ public: } }; +/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). +/// Must be added as a Cull callback. +class FudgeCallback : public osg::NodeCallback +{ +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + const float fudge = 0.1; + if (std::abs(cv->getEyeLocal().z()) < fudge) + { + float diff = fudge - cv->getEyeLocal().z(); + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + + if (cv->getEyeLocal().z() > 0) + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,-diff)); + else + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,diff)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); + } + else + traverse(node, nv); + } +}; + osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -432,6 +462,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(mWaterGeode); + mWaterNode->addCullCallback(new FudgeCallback); // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); From 913bbe347b0b0704800d61b3470d11fc69e36ab7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:52:20 +0100 Subject: [PATCH 1223/1812] Don't check the extension string every frame --- apps/openmw/mwrender/water.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c44f480f8d..c6061b40aa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -426,8 +426,12 @@ class DepthClampCallback : public osg::Drawable::DrawCallback public: virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { - if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + static bool supported = osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3); + if (!supported) + { drawable->drawImplementation(renderInfo); + return; + } glEnable(GL_DEPTH_CLAMP); From 3f988327c7178d3c6a106c1366e9a23bd0084104 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:57:59 +0100 Subject: [PATCH 1224/1812] Destructor fix --- apps/openmw/mwrender/water.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c6061b40aa..046164698d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -613,6 +613,17 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin Water::~Water() { mParent->removeChild(mWaterNode); + + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } } void Water::setEnabled(bool enabled) From 0348b8df1c25b5134ee28c0f6c25d1682fd03000 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 01:23:21 +0100 Subject: [PATCH 1225/1812] Fix applying of plane height in ClipCullNode (Fixes #2985) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 046164698d..bb6d549e04 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -145,14 +145,18 @@ class ClipCullNode : public osg::Group osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = -5; + // now apply the height of the plane + // we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well + float translate = clipFudge + ((*mCullPlane)[3] * -1); + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate); + // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) { modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); } - // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = 5; - modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * (-clipFudge)); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); traverse(node, nv); @@ -168,7 +172,7 @@ public: { addCullCallback (new PlaneCullCallback(&mPlane)); - mClipNodeTransform = new osg::PositionAttitudeTransform; + mClipNodeTransform = new osg::Group; mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); addChild(mClipNodeTransform); @@ -184,12 +188,12 @@ public: mPlane = plane; mClipNode->getClipPlaneList().clear(); - mClipNode->addClipPlane(new osg::ClipPlane(0, mPlane)); + mClipNode->addClipPlane(new osg::ClipPlane(0, osg::Plane(mPlane.getNormal(), 0))); // mPlane.d() applied in FlipCallback mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); } private: - osg::ref_ptr mClipNodeTransform; + osg::ref_ptr mClipNodeTransform; osg::ref_ptr mClipNode; osg::Plane mPlane; @@ -205,7 +209,7 @@ public: } }; -/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// Moves water mesh away from the camera slightly if the camera gets too close on the Z axis. /// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). /// Must be added as a Cull callback. class FudgeCallback : public osg::NodeCallback @@ -215,7 +219,7 @@ public: { osgUtil::CullVisitor* cv = static_cast(nv); - const float fudge = 0.1; + const float fudge = 0.2; if (std::abs(cv->getEyeLocal().z()) < fudge) { float diff = fudge - cv->getEyeLocal().z(); From bd1f3493d76cf2ab3b2b5ca2dc1e90c062e6ca38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:35:03 +0100 Subject: [PATCH 1226/1812] Fix weather particles not being cleared when changing from one particle effect to another --- apps/openmw/mwrender/sky.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b0af85c0b6..240dff7fd1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1432,6 +1432,14 @@ void SkyManager::setWeather(const WeatherResult& weather) { mCurrentParticleEffect = weather.mParticleEffect; + // cleanup old particles + if (mParticleEffect) + { + mParticleNode->removeChild(mParticleEffect); + mParticleEffect = NULL; + mParticleFader = NULL; + } + if (mCurrentParticleEffect.empty()) { if (mParticleNode) @@ -1439,8 +1447,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mRootNode->removeChild(mParticleNode); mParticleNode = NULL; } - mParticleEffect = NULL; - mParticleFader = NULL; } else { From d6f45c33906072aad42f29a59d835a031ebb14bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:51:01 +0100 Subject: [PATCH 1227/1812] Fix the renderbin for weather particles Regression from commit 2ee6b41887b8dff5231f9925c6a0205a75d67159 --- apps/openmw/mwrender/sky.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 240dff7fd1..7d67d38f08 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1453,6 +1453,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); + mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 5ca0ae52321380e7b5850b9b1ee37dd378fa7ab6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:38:34 +0100 Subject: [PATCH 1228/1812] Don't add the same AlphaFader to multiple nodes --- apps/openmw/mwrender/sky.cpp | 25 +++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 +- components/sceneutil/statesetupdater.hpp | 1 + 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d67d38f08..a4f3573227 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1196,14 +1196,13 @@ public: mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); } - // Helper for adding AlphaFader to a subgraph + // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: SetupVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - mAlphaFader = new AlphaFader; } virtual void apply(osg::Node &node) @@ -1225,22 +1224,26 @@ public: callback = callback->getNestedCallback(); } + osg::ref_ptr alphaFader (new AlphaFader); + if (composite) - composite->addController(mAlphaFader); + composite->addController(alphaFader); else - node.addUpdateCallback(mAlphaFader); + node.addUpdateCallback(alphaFader); + + mAlphaFaders.push_back(alphaFader); } } traverse(node); } - osg::ref_ptr getAlphaFader() + std::vector > getAlphaFaders() { - return mAlphaFader; + return mAlphaFaders; } private: - osg::ref_ptr mAlphaFader; + std::vector > mAlphaFaders; }; private: @@ -1437,7 +1440,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode->removeChild(mParticleEffect); mParticleEffect = NULL; - mParticleFader = NULL; + mParticleFaders.clear(); } if (mCurrentParticleEffect.empty()) @@ -1464,7 +1467,7 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); - mParticleFader = alphaFaderSetupVisitor.getAlphaFader(); + mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); } } @@ -1545,8 +1548,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? - if (mParticleFader) - mParticleFader->setAlpha(weather.mEffectFade); + for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) + (*it)->setAlpha(weather.mEffectFade); } void SkyManager::sunEnable() diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 072083d270..a4eeb861c2 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -158,7 +158,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; - osg::ref_ptr mParticleFader; + std::vector > mParticleFaders; osg::ref_ptr mCloudNode; diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 37d08e025c..34b8da848a 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -15,6 +15,7 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. + /// @note Do not add the same StateSetUpdater to multiple nodes. /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. class StateSetUpdater : public osg::NodeCallback { From fd1ccd21ff587c96cbd5e1cc83a09cb66e871e5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:49:22 +0100 Subject: [PATCH 1229/1812] Disable freezeOnCull for weather particles --- apps/openmw/mwrender/animation.cpp | 21 +------------------- apps/openmw/mwrender/sky.cpp | 4 ++++ components/sceneutil/visitor.cpp | 32 ++++++++++++++++++++++++++++++ components/sceneutil/visitor.hpp | 26 ++++++++++++++---------- 4 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 components/sceneutil/visitor.cpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b2fa873102..06065c566d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1111,25 +1111,6 @@ namespace MWRender attachTo->addChild(lightSource); } - class DisableFreezeOnCullVisitor : public osg::NodeVisitor - { - public: - DisableFreezeOnCullVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - virtual void apply(osg::Geode &geode) - { - for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } - } - }; - void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { if (!mObjectRoot.get()) @@ -1163,7 +1144,7 @@ namespace MWRender node->accept(findMaxLengthVisitor); // FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters - DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; node->accept(disableFreezeOnCullVisitor); params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4f3573227..0f00b5a4c8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1468,6 +1469,9 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); + + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + mParticleEffect->accept(disableFreezeOnCullVisitor); } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp new file mode 100644 index 0000000000..3738be08d1 --- /dev/null +++ b/components/sceneutil/visitor.cpp @@ -0,0 +1,32 @@ +#include "visitor.hpp" + +#include + +#include + +#include + +namespace SceneUtil +{ + + void FindByNameVisitor::apply(osg::Group &group) + { + if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) + { + mFoundNode = &group; + return; + } + traverse(group); + } + + void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) + { + for (unsigned int i=0; i(drw)) + partsys->setFreezeOnCull(false); + } + } + +} diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index b9342b884e..6560849407 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -3,12 +3,12 @@ #include -#include - // Commonly used scene graph visitors namespace SceneUtil { + // Find a Group by name, case-insensitive + // If not found, mFoundNode will be NULL class FindByNameVisitor : public osg::NodeVisitor { public: @@ -19,20 +19,24 @@ namespace SceneUtil { } - virtual void apply(osg::Group& group) - { - if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) - { - mFoundNode = &group; - return; - } - traverse(group); - } + virtual void apply(osg::Group& group); std::string mNameToFind; osg::Group* mFoundNode; }; + // Disable freezeOnCull for all visited particlesystems + class DisableFreezeOnCullVisitor : public osg::NodeVisitor + { + public: + DisableFreezeOnCullVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &geode); + }; + } #endif From ad016da31d1c36b674262631d406843563a88a83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:42:37 +0100 Subject: [PATCH 1230/1812] Enable fog on weather particles --- apps/openmw/mwrender/sky.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0f00b5a4c8..3adc565eaf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1457,8 +1457,10 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); - mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); + osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); + particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); + particleStateSet->setNestRenderBins(false); + particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 9902dfc9ef4be89288c824335629723782a58462 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:22 +0100 Subject: [PATCH 1231/1812] Comment --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index bb6d549e04..84fe4fcc93 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -474,7 +474,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); + createSimpleWaterStateSet(geode2); // Water_Map_Alpha geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -527,7 +527,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 380256977b2d737c33a725141dcb53b7337b21bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:38 +0100 Subject: [PATCH 1232/1812] Fix another renderBin issue with the weather particles Depth sorting w.r.t. the rest of the scene was broken --- apps/openmw/mwrender/sky.cpp | 32 +++++++++++++++----------------- apps/openmw/mwrender/sky.hpp | 1 + 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3adc565eaf..a1e5dbba87 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1066,18 +1066,19 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; - // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); - + mEarlyRenderBinRoot = new osg::Group; + // render before the world is rendered + mEarlyRenderBinRoot->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); // Prevent unwanted clipping by water reflection camera's clipping plane - mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mRootNode->addChild(mEarlyRenderBinRoot); } void SkyManager::create() { assert(!mCreated); - mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot); ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); @@ -1086,7 +1087,7 @@ void SkyManager::create() mAtmosphereNightNode = new osg::PositionAttitudeTransform; mAtmosphereNightNode->setNodeMask(0); - mRootNode->addChild(mAtmosphereNightNode); + mEarlyRenderBinRoot->addChild(mAtmosphereNightNode); osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) @@ -1099,14 +1100,14 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); + mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; - mRootNode->addChild(mCloudNode); + mEarlyRenderBinRoot->addChild(mCloudNode); mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); @@ -1123,9 +1124,9 @@ void SkyManager::create() osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color"); @@ -1282,6 +1283,7 @@ void SkyManager::createRain() stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f)); @@ -1457,10 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); - particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); - particleStateSet->setNestRenderBins(false); - particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index a4eeb861c2..573c0ceb61 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -155,6 +155,7 @@ namespace MWRender Resource::SceneManager* mSceneManager; osg::ref_ptr mRootNode; + osg::ref_ptr mEarlyRenderBinRoot; osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; From 8e8f72408d45720891401dc5d021bec52d1fa795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:12:00 +0100 Subject: [PATCH 1233/1812] Use diffuse/ambient lighting for the simple water --- apps/openmw/mwrender/water.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 84fe4fcc93..e72fc050cd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -79,6 +79,10 @@ namespace waterGeom->setVertexArray(verts); waterGeom->setTexCoordArray(0, texcoords); + osg::ref_ptr normal (new osg::Vec3Array); + normal->push_back(osg::Vec3f(0,0,1)); + waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); return waterGeom; } @@ -526,9 +530,9 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 30c828dff0642f3e3a3f2181c7473a3931856959 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:17:42 +0100 Subject: [PATCH 1234/1812] Include cleanup --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwrender/water.hpp | 7 +++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e1c0ea666a..4dbfb3072f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -32,6 +32,7 @@ #include #include "../mwworld/fallback.hpp" +#include "../mwworld/cellstore.hpp" #include "sky.hpp" #include "effectmanager.hpp" diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e72fc050cd..cb03c489d0 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -33,6 +33,8 @@ #include +#include "../mwworld/cellstore.hpp" + #include "vismask.hpp" #include "ripplesimulation.hpp" #include "renderbin.hpp" diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f77afbfee8..b5eca3f256 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_MWRENDER_WATER_H #define OPENMW_MWRENDER_WATER_H +#include + #include +#include #include -#include "../mwworld/cellstore.hpp" - namespace osg { class Group; @@ -28,6 +29,8 @@ namespace Resource namespace MWWorld { class Fallback; + class CellStore; + class Ptr; } namespace MWRender From c0a81030bba44e92e54dcb255c8aed48dadcb763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:24:50 +0100 Subject: [PATCH 1235/1812] Make use of INI settings for the simple water --- apps/openmw/mwrender/water.cpp | 20 +++++++++++++------- apps/openmw/mwrender/water.hpp | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cb03c489d0..101d9c8220 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -34,6 +34,7 @@ #include #include "../mwworld/cellstore.hpp" +#include "../mwworld/fallback.hpp" #include "vismask.hpp" #include "ripplesimulation.hpp" @@ -457,6 +458,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mFallback(fallback) , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) @@ -480,7 +482,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); // Water_Map_Alpha + createSimpleWaterStateSet(geode2, mFallback->getFallbackFloat("Water_Map_Alpha")); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -522,18 +524,18 @@ void Water::updateWaterMaterial() createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); } else - createSimpleWaterStateSet(mWaterGeode); + createSimpleWaterStateSet(mWaterGeode, mFallback->getFallbackFloat("Water_World_Alpha")); updateVisible(); } -void Water::createSimpleWaterStateSet(osg::Node* node) +void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); @@ -548,14 +550,18 @@ void Water::createSimpleWaterStateSet(osg::Node* node) stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; - for (int i=0; i<32; ++i) + int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); + std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); + for (int i=0; igetTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + float fps = mFallback->getFallbackFloat("Water_SurfaceFPS"); + + osg::ref_ptr controller (new NifOsg::FlipController(0, 1.f/fps, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); node->setUpdateCallback(controller); node->setStateSet(stateset); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index b5eca3f256..551184c11c 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -50,6 +50,7 @@ namespace MWRender osg::ref_ptr mWaterNode; osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; + const MWWorld::Fallback* mFallback; osg::ref_ptr mIncrementalCompileOperation; std::auto_ptr mSimulation; @@ -66,7 +67,7 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - void createSimpleWaterStateSet(osg::Node* node); + void createSimpleWaterStateSet(osg::Node* node, float alpha); /// @param reflection the reflection camera (required) /// @param refraction the refraction camera (optional) From b72d5c5190a9e1ef8756d3c8734a0d011748cb75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:48:35 +0100 Subject: [PATCH 1236/1812] Don't play idlestorm animation when swimming --- apps/openmw/mwmechanics/character.cpp | 7 +++---- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 36c251053c..de4b449867 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -504,8 +504,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } - - updateIdleStormState(); } @@ -867,7 +865,7 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } -void CharacterController::updateIdleStormState() +void CharacterController::updateIdleStormState(bool inwater) { bool inStormDirection = false; if (MWBase::Environment::get().getWorld()->isInStorm()) @@ -877,7 +875,7 @@ void CharacterController::updateIdleStormState() inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length())) > osg::DegreesToRadians(120.f); } - if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) + if (inStormDirection && !inwater && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; mAnimation->getInfo("idlestorm", &complete); @@ -1796,6 +1794,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + updateIdleStormState(inwater); } if (inJump) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index fee7b959cb..90e285b522 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool updateWeaponState(); bool updateCreatureState(); - void updateIdleStormState(); + void updateIdleStormState(bool inwater); void updateHeadTracking(float duration); From de97a8a3dad74b49a72917bb32df80c3be49983b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:53:57 +0100 Subject: [PATCH 1237/1812] Do not allow disabling the player object --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 17118e169b..45aa310654 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -781,6 +781,9 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { + if (reference == getPlayerPtr()) + throw std::runtime_error("can not disable player object"); + reference.getRefData().disable(); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) From a5f8ffb83dbbae8cde9dde83e16f98c03ae6fc30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:15:47 +0100 Subject: [PATCH 1238/1812] aimToTarget: Fix the collision box translation not being taken into account --- apps/openmw/mwphysics/actor.cpp | 5 +++++ apps/openmw/mwphysics/actor.hpp | 6 ++++++ apps/openmw/mwphysics/physicssystem.cpp | 25 +++++++++++++++++++++---- apps/openmw/mwphysics/physicssystem.hpp | 9 +++++++-- apps/openmw/mwworld/worldimp.cpp | 3 +-- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index a681c79452..98ccefe71c 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -95,6 +95,11 @@ void Actor::updatePosition() mCollisionObject->setWorldTransform(tr); } +osg::Vec3f Actor::getPosition() const +{ + return toOsg(mCollisionObject->getWorldTransform().getOrigin()); +} + void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index a4afa48a11..bcbc256d0e 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -70,6 +70,12 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the position of the collision body + * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + */ + osg::Vec3f getPosition() const; + /** * Returns the half extents of the collision body (scaled according to rendering scale) * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 80a63bf1b5..f4bf7a364b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -869,24 +869,33 @@ namespace MWPhysics } } - osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getHalfExtents(); else return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getRenderingHalfExtents(); else return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const + { + const Actor* physactor = getActor(actor); + if (physactor) + return physactor->getPosition(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: @@ -1036,6 +1045,14 @@ namespace MWPhysics return NULL; } + const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const + { + ActorMap::const_iterator found = mActors.find(ptr); + if (found != mActors.end()) + return found->second; + return NULL; + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 6f38653c89..7c5be0b6e3 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -62,6 +62,7 @@ namespace MWPhysics void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); Actor* getActor(const MWWorld::Ptr& ptr); + const Actor* getActor(const MWWorld::Ptr& ptr) const; // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -108,10 +109,14 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); /// Get physical half extents (scaled) of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const; /// @see MWPhysics::Actor::getRenderingHalfExtents - osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const; + + /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. + /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + osg::Vec3f getPosition(const MWWorld::Ptr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 45aa310654..0f8c5aa327 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3259,8 +3259,7 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) { osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); - osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); - targetPos.z() += mPhysics->getHalfExtents(target).z(); + osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } } From 46e07e4b19e5db9a8860dfbf844ccfa71a407a52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:27:15 +0100 Subject: [PATCH 1239/1812] Head tracking: fall back to target collision box center if the target has no head node --- apps/openmw/mwmechanics/character.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index de4b449867..f1c3da5ad1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2121,7 +2121,7 @@ void CharacterController::updateHeadTracking(float duration) osg::Matrixf mat = mats[0]; osg::Vec3f headPos = mat.getTrans(); - osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3()); + osg::Vec3f direction; if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); @@ -2131,11 +2131,12 @@ void CharacterController::updateHeadTracking(float duration) { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - targetPos = mats[0].getTrans(); + direction = mats[0].getTrans() - headPos; } + else + // no head node to look at, fall back to look at center of collision box + direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget); } - - osg::Vec3f direction = targetPos - headPos; direction.normalize(); if (!mPtr.getRefData().getBaseNode()) From 682f30ef9c7e8edad3e825be6920670ffac3bdce Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 19:05:36 +0100 Subject: [PATCH 1240/1812] Fix incorrect uses of PhysicsSystem::getHalfExtents Did not account for translation of collision box (mMeshTranslation in actor.cpp) --- apps/openmw/mwphysics/physicssystem.cpp | 19 ++++++++----------- apps/openmw/mwworld/projectilemanager.cpp | 7 +------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f4bf7a364b..92994d5574 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,6 +240,8 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); + float collisionShapeOffset = physicActor->getPosition().z() - position.z(); + // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -256,12 +258,11 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - osg::Vec3f halfExtents = physicActor->getHalfExtents(); - position.z() += halfExtents.z(); + position.z() += collisionShapeOffset; static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -369,7 +370,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + halfExtents.z() > waterlevel) + && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) newPosition = oldPosition; } else @@ -450,7 +451,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= halfExtents.z(); // remove what was added at the beginning + newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning return newPosition; } }; @@ -820,12 +821,8 @@ namespace MWPhysics if (!physactor1 || !physactor2) return false; - osg::Vec3f halfExt1 = physactor1->getHalfExtents(); - osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); - pos1.z() += halfExt1.z()*2*0.9f; // eye level - osg::Vec3f halfExt2 = physactor2->getHalfExtents(); - osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - pos2.z() += halfExt2.z()*2*0.9f; + osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level + osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3e9f172786..d5aca17a63 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,12 +68,7 @@ namespace MWWorld const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, const osg::Vec3f& fallbackDirection) { - float height = 0; - - height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight - - osg::Vec3f pos(caster.getRefData().getPosition().asVec3()); - pos.z() += height; + osg::Vec3f pos = mPhysics->getPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; From e3b30baff9733396fbad1fa7f3ff0e51782fd9b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:10:52 +0100 Subject: [PATCH 1241/1812] clipFudge fix --- apps/openmw/mwrender/water.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 101d9c8220..80023ecdaa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -152,12 +152,9 @@ class ClipCullNode : public osg::Group osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); - // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; - // now apply the height of the plane + // apply the height of the plane // we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well - float translate = clipFudge + ((*mCullPlane)[3] * -1); - modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate); + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * ((*mCullPlane)[3] * -1)); // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) @@ -165,6 +162,10 @@ class ClipCullNode : public osg::Group modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); } + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = -5; + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); From 209fa52883aa824baac579074e4568e9993c66a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:15:43 +0100 Subject: [PATCH 1242/1812] Hide weather particles underwater (Fixes #2701) --- apps/openmw/mwrender/renderingmanager.cpp | 2 + apps/openmw/mwrender/sky.cpp | 68 ++++++++++++++++++++++- apps/openmw/mwrender/sky.hpp | 10 ++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4dbfb3072f..5b2aac9e50 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -450,11 +450,13 @@ namespace MWRender void RenderingManager::setWaterEnabled(bool enabled) { mWater->setEnabled(enabled); + mSky->setWaterEnabled(enabled); } void RenderingManager::setWaterHeight(float height) { mWater->setHeight(height); + mSky->setWaterHeight(height); } class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a1e5dbba87..4ff7256ca8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -262,8 +262,18 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + const osg::Vec3f& getLastEyePoint() const { + return mEyePoint; + } + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const + { + if (nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + { + mEyePoint = static_cast(nv)->getEyePoint(); + } + if (_referenceFrame==RELATIVE_RF) { matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); @@ -322,6 +332,9 @@ public: cv->getCurrentCullingSet().popCurrentMask(); } }; +private: + // eyePoint for the current frame + mutable osg::Vec3f mEyePoint; }; class ModVertexAlphaVisitor : public osg::NodeVisitor @@ -371,6 +384,45 @@ private: int mMeshType; }; +/// @brief Hides the node subgraph if the eye point is below water. +/// @note Must be added as cull callback. +/// @note Meant to be used on a node that is child of a CameraRelativeTransform. +/// The current eye point must be retrieved by the CameraRelativeTransform since we can't get it anymore once we are in camera-relative space. +class UnderwaterSwitchCallback : public osg::NodeCallback +{ +public: + UnderwaterSwitchCallback(CameraRelativeTransform* cameraRelativeTransform) + : mCameraRelativeTransform(cameraRelativeTransform) + , mEnabled(true) + , mWaterLevel(0.f) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Vec3f eyePoint = mCameraRelativeTransform->getLastEyePoint(); + + if (mEnabled && eyePoint.z() < mWaterLevel) + return; + + traverse(node, nv); + } + + void setEnabled(bool enabled) + { + mEnabled = enabled; + } + void setWaterLevel(float waterLevel) + { + mWaterLevel = waterLevel; + } + +private: + osg::ref_ptr mCameraRelativeTransform; + bool mEnabled; + float mWaterLevel; +}; + /// A base class for the sun and moons. class CelestialBody { @@ -1072,6 +1124,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Prevent unwanted clipping by water reflection camera's clipping plane mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); mRootNode->addChild(mEarlyRenderBinRoot); + + mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); } void SkyManager::create() @@ -1319,6 +1373,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); + mRainNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mRainNode); } @@ -1459,6 +1514,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); @@ -1607,4 +1663,14 @@ void SkyManager::setGlareTimeOfDayFade(float val) mSun->setGlareTimeOfDayFade(val); } +void SkyManager::setWaterHeight(float height) +{ + mUnderwaterSwitch->setWaterLevel(height); +} + +void SkyManager::setWaterEnabled(bool enabled) +{ + mUnderwaterSwitch->setEnabled(enabled); +} + } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 573c0ceb61..0caadaa073 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -35,6 +35,7 @@ namespace MWRender class RainShooter; class RainFader; class AlphaFader; + class UnderwaterSwitchCallback; struct WeatherResult { @@ -100,6 +101,8 @@ namespace MWRender float mMoonAlpha; }; + ///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered + /// relative to the camera (e.g. weather particle effects) class SkyManager { public: @@ -144,6 +147,12 @@ namespace MWRender void setGlareTimeOfDayFade(float val); + /// Enable or disable the water plane (used to remove underwater weather particles) + void setWaterEnabled(bool enabled); + + /// Set height of water plane (used to remove underwater weather particles) + void setWaterHeight(float height); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -160,6 +169,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; + osg::ref_ptr mUnderwaterSwitch; osg::ref_ptr mCloudNode; From 1cf1c944b79d3bbd64bbb909614816b08e663cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:20:17 +0100 Subject: [PATCH 1243/1812] Don't attempt to render weather particles on the refraction and reflection textures --- apps/openmw/mwrender/sky.cpp | 2 ++ apps/openmw/mwrender/vismask.hpp | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4ff7256ca8..12708ba481 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1374,6 +1374,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); + mRainNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mRainNode); } @@ -1515,6 +1516,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode = new osg::PositionAttitudeTransform; mParticleNode->addCullCallback(mUnderwaterSwitch); + mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index b1329e9588..a26bde1d13 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,21 +15,26 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Sun = (1<<6), - Mask_Water = (1<<7), - Mask_SimpleWater = (1<<8), - Mask_Terrain = (1<<9), - Mask_FirstPerson = (1<<10), + Mask_Water = (1<<6), + Mask_Terrain = (1<<7), + Mask_FirstPerson = (1<<8), + + // child of Sky + Mask_Sun = (1<<9), + Mask_WeatherParticles = (1<<10), + + // child of Water + Mask_SimpleWater = (1<<11), // top level masks - Mask_Scene = (1<<11), - Mask_GUI = (1<<12), + Mask_Scene = (1<<12), + Mask_GUI = (1<<13), // Set on a Geode - Mask_ParticleSystem = (1<<13), + Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<14) + Mask_RenderToTexture = (1<<15) // reserved: (1<<16) for SceneUtil::Mask_Lit }; From c23609e22b1d931274b93c3ce031c682cf6176ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 00:19:15 +0100 Subject: [PATCH 1244/1812] Cache the light list in LightListCallback When multiple cameras are rendering, the later cameras can reuse the light lists from the first camera. --- components/sceneutil/lightmanager.cpp | 37 +++++++++++++++------------ components/sceneutil/lightmanager.hpp | 4 +++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 18d7ddd46b..1e1d04cf50 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -280,37 +280,40 @@ namespace SceneUtil // - cull list of lights by the camera frustum // - organize lights in a quad tree - // Don't use Camera::getViewMatrix, that one might be relative to another camera! - const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); - const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); - - if (lights.size()) + // update light list if necessary + // makes sure we don't update it more than once per frame when rendering with multiple cameras + if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber()) { + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + + // Don't use Camera::getViewMatrix, that one might be relative to another camera! + const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); + // we do the intersections in view space osg::BoundingSphere nodeBound = node->getBound(); osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - LightManager::LightList lightList; + mLightList.clear(); for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - if (lightList.size() > maxLights) + osg::StateSet* stateset = NULL; + + if (mLightList.size() > maxLights) { // remove lights culled by this camera + LightManager::LightList lightList = mLightList; for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; ) { osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack(); @@ -334,9 +337,11 @@ namespace SceneUtil while (lightList.size() > maxLights) lightList.pop_back(); } + stateset = mLightManager->getLightListStateSet(lightList); } + else + stateset = mLightManager->getLightListStateSet(mLightList); - osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); cv->pushStateSet(stateset); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index c2a1779ede..0783e595dc 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -113,11 +113,13 @@ namespace SceneUtil int mStartLight; }; + /// @note Not thread safe for CullThreadPerCamera threading mode. class LightListCallback : public osg::NodeCallback { public: LightListCallback() : mLightManager(NULL) + , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) @@ -129,6 +131,8 @@ namespace SceneUtil private: LightManager* mLightManager; + unsigned int mLastFrameNumber; + LightManager::LightList mLightList; }; /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. From 6bf393227922926be06e520e46f9c656b4d08b21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:25:03 +0100 Subject: [PATCH 1245/1812] Fix the check_tabs.sh script choking on QT generated UI files when doing an in-source build --- CI/check_tabs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh index 91f81e2a1e..1e88b57fd4 100755 --- a/CI/check_tabs.sh +++ b/CI/check_tabs.sh @@ -1,6 +1,6 @@ #!/bin/bash -OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} --exclude=ui_\* apps components) if [[ $OUTPUT ]] ; then echo "Error: Tab characters found!" From f7d0d06134c8b82c5142451d9ff256c1effcce74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:31:23 +0100 Subject: [PATCH 1246/1812] Compiler: remove unused mNameStartingWithDigit --- components/compiler/scanner.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 8478959785..fe867febae 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -37,7 +37,6 @@ namespace Compiler float mPutbackFloat; std::string mPutbackName; TokenLoc mPutbackLoc; - bool mNameStartingWithDigit; public: From c996702b56e9525299f90969aecaf84f68badb8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:34:50 +0100 Subject: [PATCH 1247/1812] Fix some uninitialised variables found by static analysis --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- components/sceneutil/lightmanager.hpp | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1c3da5ad1..c9b2489848 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -654,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) + , mAdjustMovementAnimSpeed(false) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5b2aac9e50..7b11c9d859 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -131,6 +131,10 @@ namespace MWRender , mRootNode(rootNode) , mResourceSystem(resourceSystem) , mFogDepth(0.f) + , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) + , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) + , mUnderwaterFog(0.f) + , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; @@ -202,10 +206,6 @@ namespace MWRender updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); - mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor"); - mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight"); - mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog"); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 0783e595dc..b652562aa8 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -122,7 +122,9 @@ namespace SceneUtil , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) + , mLightManager(copy.mLightManager) + , mLastFrameNumber(0) {} META_Object(NifOsg, LightListCallback) From 489addf772568d0d67c4387a21b5dc4788ce72d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 22:24:25 +0100 Subject: [PATCH 1248/1812] Don't attempt to run openmw_test_suite on coverity scan branch, since it is not being built --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 69879bd781..22f6164c2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com From 8e4e4e5e38f53974fef9bc3373cd8b9d72c89c8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Nov 2015 01:18:01 +0100 Subject: [PATCH 1249/1812] Fix infinite loop in addToLevList --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 32d86f55ad..5aebbc3a9e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -37,7 +37,7 @@ namespace void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end(); ++it) { if (it->mLevel == level && itemId == it->mId) return; From 95cf13e3f2995e573c8c275256106dc1d4449d81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 15:23:37 +0100 Subject: [PATCH 1250/1812] Terrain: make the blendmapSize and layerTileSize in FixedFunctionTechnique configurable --- components/terrain/material.cpp | 14 ++++++++------ components/terrain/material.hpp | 6 ++++-- components/terrain/terraingrid.cpp | 4 +++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index df45b6ec2a..d467a9e167 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -11,7 +11,7 @@ namespace Terrain { FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, - const std::vector >& blendmaps) + const std::vector >& blendmaps, int blendmapSize, float layerTileSize) { bool firstLayer = true; int i=0; @@ -36,7 +36,7 @@ namespace Terrain // This is to map corner vertices directly to the center of a blendmap texel. osg::Matrixf texMat; - float scale = (16/(16.f+1.f)); + float scale = (blendmapSize/(static_cast(blendmapSize)+1.f)); texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); @@ -57,8 +57,7 @@ namespace Terrain stateset->setTextureAttributeAndModes(texunit, tex.get()); osg::ref_ptr texMat (new osg::TexMat); - float scale = 16.f; - texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(scale,scale,1.f))); + texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(layerTileSize,layerTileSize,1.f))); stateset->setTextureAttributeAndModes(texunit, texMat, osg::StateAttribute::ON); firstLayer = false; @@ -67,9 +66,12 @@ namespace Terrain } } - Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps) + Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps, + int blendmapSize, float layerTileSize) : mLayers(layers) , mBlendmaps(blendmaps) + , mBlendmapSize(blendmapSize) + , mLayerTileSize(layerTileSize) { osg::ref_ptr material (new osg::Material); material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); @@ -80,7 +82,7 @@ namespace Terrain bool Effect::define_techniques() { - addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapSize, mLayerTileSize)); return true; } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b423aa8b0c..1be227b0d7 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -19,7 +19,7 @@ namespace Terrain public: FixedFunctionTechnique( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapSize, float layerTileSize); protected: virtual void define_passes() {} @@ -30,7 +30,7 @@ namespace Terrain public: Effect( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapSize, float layerTileSize); virtual bool define_techniques(); @@ -50,6 +50,8 @@ namespace Terrain private: std::vector > mLayers; std::vector > mBlendmaps; + int mBlendmapSize; + float mLayerTileSize; }; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 5afb991768..7c23955662 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include #include @@ -150,7 +152,7 @@ void TerrainGrid::loadCell(int x, int y) for (unsigned int i=0; i<2; ++i) geometry->setTexCoordArray(i, mCache.getUVBuffer()); - osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, ESM::Land::LAND_TEXTURE_SIZE, ESM::Land::LAND_TEXTURE_SIZE)); effect->addCullCallback(new SceneUtil::LightListCallback); From ef18f4217f1aca7830f39f241d355b353a4602ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:14:57 +0100 Subject: [PATCH 1251/1812] Terrain: create 4x4 terrain chunks per ESM::Cell to improve performance Improves performance because the number of splatting layers per chunk is reduced, and finer grained frustum culling can be done. --- components/esmterrain/storage.cpp | 80 ++++++++---- components/terrain/buffercache.cpp | 3 + components/terrain/material.cpp | 10 +- components/terrain/material.hpp | 6 +- components/terrain/terraingrid.cpp | 203 ++++++++++++++++++----------- components/terrain/terraingrid.hpp | 7 + 6 files changed, 199 insertions(+), 110 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index ccfe6d9ee5..e954bfec8a 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,6 +1,7 @@ #include "storage.hpp" #include +#include #include #include @@ -34,19 +35,22 @@ namespace ESMTerrain osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int startRow = (origin.x() - cellX) * ESM::Land::LAND_SIZE; + int startColumn = (origin.y() - cellY) * ESM::Land::LAND_SIZE; + + int endRow = startRow + size * (ESM::Land::LAND_SIZE-1) + 1; + int endColumn = startColumn + size * (ESM::Land::LAND_SIZE-1) + 1; if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT)) { min = std::numeric_limits::max(); max = -std::numeric_limits::max(); - for (int row=0; rowmHeights[col*ESM::Land::LAND_SIZE+row]; if (h > max) @@ -143,11 +147,9 @@ namespace ESMTerrain size_t increment = 1 << lodLevel; osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); - int startX = static_cast(origin.x()); - int startY = static_cast(origin.y()); + int startCellX = static_cast(std::floor(origin.x())); + int startCellY = static_cast(std::floor(origin.y())); size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); @@ -162,10 +164,10 @@ namespace ESMTerrain float vertX = 0; float vertY_ = 0; // of current cell corner - for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) + for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY) { float vertX_ = 0; // of current cell corner - for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) + for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX) { const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); @@ -175,18 +177,31 @@ namespace ESMTerrain int colStart = 0; // Skip the first row / column unless we're at a chunk edge, // since this row / column is already contained in a previous cell + // This is only relevant if we're creating a chunk spanning multiple cells if (colStart == 0 && vertY_ != 0) colStart += increment; if (rowStart == 0 && vertX_ != 0) rowStart += increment; + // Only relevant for chunks smaller than (contained in) one cell + rowStart += (origin.x() - startCellX) * ESM::Land::LAND_SIZE; + colStart += (origin.y() - startCellY) * ESM::Land::LAND_SIZE; + int rowEnd = rowStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + int colEnd = colStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + vertY = vertY_; - for (int col=colStart; col= 0 && row < ESM::Land::LAND_SIZE); + assert(col >= 0 && col < ESM::Land::LAND_SIZE); + + assert (vertX < numVerts); + assert (vertY < numVerts); float height = -2048; if (heightData) @@ -200,7 +215,7 @@ namespace ESMTerrain if (normalData) { for (int i=0; i<3; ++i) - normal[i] = normalData->mNormals[arrayIndex+i]; + normal[i] = normalData->mNormals[srcArrayIndex+i]; normal.normalize(); } @@ -222,7 +237,7 @@ namespace ESMTerrain if (colourData) { for (int i=0; i<3; ++i) - color[i] = colourData->mColours[arrayIndex+i] / 255.f; + color[i] = colourData->mColours[srcArrayIndex+i] / 255.f; } else { @@ -305,8 +320,19 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); + + int realTextureSize = ESM::Land::LAND_TEXTURE_SIZE+1; // add 1 to wrap around next cell + + int rowStart = (origin.x() - cellX) * realTextureSize; + int colStart = (origin.y() - cellY) * realTextureSize; + int rowEnd = rowStart + chunkSize * (realTextureSize-1) + 1; + int colEnd = colStart + chunkSize * (realTextureSize-1) + 1; + + assert (rowStart >= 0 && colStart >= 0); + assert (rowEnd <= realTextureSize); + assert (colEnd <= realTextureSize); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -317,8 +343,15 @@ namespace ESMTerrain // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. textureIndices.insert(std::make_pair(0,0)); - for (int y=0; ysecond; int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index a64f8ffd1d..c6cf0fe33c 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,6 +1,7 @@ #include "buffercache.hpp" #include +#include #include @@ -208,6 +209,8 @@ namespace Terrain { unsigned int verts = mNumVerts; + std::cout << "getting index buffer for " << verts << std::endl; + if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { return mIndexBufferMap[flags]; diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index d467a9e167..59d06f2542 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -11,7 +11,7 @@ namespace Terrain { FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize) + const std::vector >& blendmaps, int blendmapScale, float layerTileSize) { bool firstLayer = true; int i=0; @@ -36,7 +36,7 @@ namespace Terrain // This is to map corner vertices directly to the center of a blendmap texel. osg::Matrixf texMat; - float scale = (blendmapSize/(static_cast(blendmapSize)+1.f)); + float scale = (blendmapScale/(static_cast(blendmapScale)+1.f)); texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); @@ -67,10 +67,10 @@ namespace Terrain } Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps, - int blendmapSize, float layerTileSize) + int blendmapScale, float layerTileSize) : mLayers(layers) , mBlendmaps(blendmaps) - , mBlendmapSize(blendmapSize) + , mBlendmapScale(blendmapScale) , mLayerTileSize(layerTileSize) { osg::ref_ptr material (new osg::Material); @@ -82,7 +82,7 @@ namespace Terrain bool Effect::define_techniques() { - addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapSize, mLayerTileSize)); + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapScale, mLayerTileSize)); return true; } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 1be227b0d7..dd00e41ed4 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -19,7 +19,7 @@ namespace Terrain public: FixedFunctionTechnique( const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); protected: virtual void define_passes() {} @@ -30,7 +30,7 @@ namespace Terrain public: Effect( const std::vector >& layers, - const std::vector >& blendmaps, int blendmapSize, float layerTileSize); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); virtual bool define_techniques(); @@ -50,7 +50,7 @@ namespace Terrain private: std::vector > mLayers; std::vector > mBlendmaps; - int mBlendmapSize; + int mBlendmapScale; float mLayerTileSize; }; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 7c23955662..6414fa9517 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,6 +1,8 @@ #include "terraingrid.hpp" #include +#include +#include #include #include @@ -47,8 +49,10 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) + , mNumSplits(4) , mKdTreeBuilder(new osg::KdTreeBuilder) { + mCache = BufferCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1); } TerrainGrid::~TerrainGrid() @@ -62,108 +66,149 @@ TerrainGrid::~TerrainGrid() class GridElement { public: - osg::ref_ptr mNode; + osg::ref_ptr mNode; }; +osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) +{ + if (chunkSize * mNumSplits > 1.f) + { + // keep splitting + osg::ref_ptr group (new osg::Group); + if (parent) + parent->addChild(group); + std::cout << "splitting " << chunkSize << " " << std::endl; + float newChunkSize = chunkSize/2.f; + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f)); + return group; + } + else + { + float minH, maxH; + if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH)) + return NULL; // no terrain defined + + std::cout << "creating " << chunkSize << " " << chunkCenter << std::endl; + + osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + + if (parent) + parent->addChild(transform); + + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); + + osg::ref_ptr vbo (new osg::VertexBufferObject); + positions->setVertexBufferObject(vbo); + normals->setVertexBufferObject(vbo); + colors->setVertexBufferObject(vbo); + + mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors); + + osg::ref_ptr geometry (new osg::Geometry); + geometry->setVertexArray(positions); + geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); + geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + geometry->setUseDisplayList(false); + geometry->setUseVertexBufferObjects(true); + + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); + + // we already know the bounding box, so no need to let OSG compute it. + osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize, + -0.5f*mStorage->getCellWorldSize()*chunkSize, + minH); + osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize, + 0.5f*mStorage->getCellWorldSize()*chunkSize, + maxH); + osg::BoundingBox bounds(min, max); + geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); + + + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); + + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); + + std::vector > layerTextures; + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) + { + layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } + + std::vector > blendmapTextures; + for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + { + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(*it); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + blendmapTextures.push_back(texture); + + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } + + // use texture coordinates for both texture units, the layer texture and blend texture + for (unsigned int i=0; i<2; ++i) + geometry->setTexCoordArray(i, mCache.getUVBuffer()); + + float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize; + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, blendmapScale, blendmapScale)); + + effect->addCullCallback(new SceneUtil::LightListCallback); + + transform->addChild(effect); + effect->addChild(geode); + + return transform; + } +} + void TerrainGrid::loadCell(int x, int y) { if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded osg::Vec2f center(x+0.5f, y+0.5f); - float minH, maxH; - if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) + + osg::ref_ptr terrainNode = buildTerrain(NULL, 1.f, center); + if (!terrainNode) return; // no terrain defined std::auto_ptr element (new GridElement); - - osg::Vec2f worldCenter = center*mStorage->getCellWorldSize(); - element->mNode = new osg::PositionAttitudeTransform; - element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + element->mNode = terrainNode; mTerrainRoot->addChild(element->mNode); - osg::ref_ptr positions (new osg::Vec3Array); - osg::ref_ptr normals (new osg::Vec3Array); - osg::ref_ptr colors (new osg::Vec4Array); - - osg::ref_ptr vbo (new osg::VertexBufferObject); - positions->setVertexBufferObject(vbo); - normals->setVertexBufferObject(vbo); - colors->setVertexBufferObject(vbo); - - mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); - - osg::ref_ptr geometry (new osg::Geometry); - geometry->setVertexArray(positions); - geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); - geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); - geometry->setUseDisplayList(false); - geometry->setUseVertexBufferObjects(true); - - geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); - - // we already know the bounding box, so no need to let OSG compute it. - osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(), - -0.5f*mStorage->getCellWorldSize(), - minH); - osg::Vec3f max (0.5f*mStorage->getCellWorldSize(), - 0.5f*mStorage->getCellWorldSize(), - maxH); - osg::BoundingBox bounds(min, max); - geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); - + /* // build a kdtree to speed up intersection tests with the terrain // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree geode->accept(*mKdTreeBuilder); + */ - std::vector layerList; - std::vector > blendmaps; - mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); - - // For compiling textures, I don't think the osgFX::Effect does it correctly - osg::ref_ptr textureCompileDummy (new osg::Node); - - std::vector > layerTextures; - for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) - { - layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); - } - - std::vector > blendmapTextures; - for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - { - osg::ref_ptr texture (new osg::Texture2D); - texture->setImage(*it); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - texture->setResizeNonPowerOfTwoHint(false); - blendmapTextures.push_back(texture); - - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); - } - - // use texture coordinates for both texture units, the layer texture and blend texture - for (unsigned int i=0; i<2; ++i) - geometry->setTexCoordArray(i, mCache.getUVBuffer()); - - osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, ESM::Land::LAND_TEXTURE_SIZE, ESM::Land::LAND_TEXTURE_SIZE)); - - effect->addCullCallback(new SceneUtil::LightListCallback); - - effect->addChild(geode); - element->mNode->addChild(effect); + /* if (mIncrementalCompileOperation) { mIncrementalCompileOperation->add(geode); mIncrementalCompileOperation->add(textureCompileDummy); } + */ + mGrid[std::make_pair(x,y)] = element.release(); } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 832b952e89..169a9a6228 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,6 +1,8 @@ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H +#include + #include "world.hpp" #include "material.hpp" @@ -26,6 +28,11 @@ namespace Terrain virtual void unloadCell(int x, int y); private: + osg::ref_ptr buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); + + // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks + unsigned int mNumSplits; + typedef std::map, GridElement*> Grid; Grid mGrid; From 7ca8e45d5ddbb2cfbf28716aa297e928cde08889 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:21:39 +0100 Subject: [PATCH 1252/1812] Terrain: remove debug code --- components/esmterrain/storage.cpp | 8 -------- components/terrain/buffercache.cpp | 3 --- components/terrain/terraingrid.cpp | 7 ++----- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index e954bfec8a..c36e3efe0c 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,7 +1,6 @@ #include "storage.hpp" #include -#include #include #include @@ -343,13 +342,6 @@ namespace ESMTerrain // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. textureIndices.insert(std::make_pair(0,0)); - /* - _________ - | | | | - | | | | - - | | | | - | | | | - - - */ - for (int y=colStart; y -#include #include @@ -209,8 +208,6 @@ namespace Terrain { unsigned int verts = mNumVerts; - std::cout << "getting index buffer for " << verts << std::endl; - if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { return mIndexBufferMap[flags]; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 6414fa9517..99525d0f48 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,8 +1,6 @@ #include "terraingrid.hpp" #include -#include -#include #include #include @@ -77,7 +75,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu osg::ref_ptr group (new osg::Group); if (parent) parent->addChild(group); - std::cout << "splitting " << chunkSize << " " << std::endl; + float newChunkSize = chunkSize/2.f; buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f)); buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f)); @@ -91,8 +89,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH)) return NULL; // no terrain defined - std::cout << "creating " << chunkSize << " " << chunkCenter << std::endl; - osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); osg::ref_ptr transform (new osg::PositionAttitudeTransform); transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); @@ -194,6 +190,7 @@ void TerrainGrid::loadCell(int x, int y) element->mNode = terrainNode; mTerrainRoot->addChild(element->mNode); + // kdtree probably not needed with mNumSplits=4 /* // build a kdtree to speed up intersection tests with the terrain // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree From 72252d4f32e200f21c076688322854b477ca9bb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 20:22:07 +0100 Subject: [PATCH 1253/1812] Terrain: restore IncrementalCompileOperation --- components/terrain/terraingrid.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 99525d0f48..732936aa99 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -171,6 +171,12 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu transform->addChild(effect); effect->addChild(geode); + if (mIncrementalCompileOperation) + { + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); + } + return transform; } } @@ -197,16 +203,6 @@ void TerrainGrid::loadCell(int x, int y) geode->accept(*mKdTreeBuilder); */ - - /* - if (mIncrementalCompileOperation) - { - mIncrementalCompileOperation->add(geode); - mIncrementalCompileOperation->add(textureCompileDummy); - } - */ - - mGrid[std::make_pair(x,y)] = element.release(); } From 0210b87ffc0fc33bddaf2449ad1d1c042cc51553 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 22:35:12 +0100 Subject: [PATCH 1254/1812] Revert "Fix LightSource crash" This reverts commit f336c6db87be04903c0a92ab0c749bfe290bb5f0. Root cause should be fixed in next commit. --- components/sceneutil/lightmanager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index b652562aa8..e62dc00e58 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -76,7 +76,7 @@ namespace SceneUtil struct LightSourceTransform { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::Matrix mWorldMatrix; }; @@ -84,7 +84,7 @@ namespace SceneUtil struct LightSourceViewBound { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::BoundingSphere mViewBound; }; From 6e698081294377acab61a29be0056d8ac491e2c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 22:41:32 +0100 Subject: [PATCH 1255/1812] Fix the frameNumber not being incremented in certain frames --- apps/openmw/mwgui/loadingscreen.cpp | 8 +++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++++++++++++++-- apps/openmw/mwrender/renderingmanager.cpp | 10 +++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9afce68735..321d5e6645 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -282,7 +282,13 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); //osg::Timer timer; - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); //std::cout << "frame took " << timer.time_m() << std::endl; //if (mViewer->getIncrementalCompileOperation()) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 90a5f74817..e1e838cdf9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -859,7 +859,13 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } } } @@ -1756,7 +1762,13 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } mVideoWidget->stop(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7b11c9d859..7848cdd3cb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -521,10 +521,18 @@ namespace MWRender osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); callback->waitTillDone(); + // now that we've "used up" the current frame, get a fresh framenumber for the next frame() following after the screenshot is completed + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); From 2407f393cee9a3a7634337777c8ce902a9186923 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 23:13:57 +0100 Subject: [PATCH 1256/1812] Fix double update traversal in screenshot function --- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7848cdd3cb..45c04ceecd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -489,6 +489,15 @@ namespace MWRender mutable bool mDone; }; + + class NoTraverseCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + } + }; + void RenderingManager::screenshot(osg::Image *image, int w, int h) { osg::ref_ptr rttCamera (new osg::Camera); @@ -512,6 +521,7 @@ namespace MWRender image->setDataType(GL_UNSIGNED_BYTE); image->setPixelFormat(texture->getInternalFormat()); + rttCamera->setUpdateCallback(new NoTraverseCallback); rttCamera->addChild(mLightRoot); rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); From 4cc200680c071541f484d36897eab61171d57182 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Nov 2015 23:59:06 +0100 Subject: [PATCH 1257/1812] Comment out shadows tab in settings menu --- files/mygui/openmw_settings_window.layout | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e76c3a7dbc..5f2a6e5a06 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -392,7 +392,11 @@ + + + From a41ebd6695096f71b2c5a54983e222d2aec8eb16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:02:15 +0100 Subject: [PATCH 1258/1812] Comment out object shaders in the settings menu --- files/mygui/openmw_settings_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 5f2a6e5a06..cb74636560 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -262,6 +262,8 @@ + + From 47664e13707c5ed2a4f0b3282dc4cb67dfc7392a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:10:49 +0100 Subject: [PATCH 1259/1812] Hide the defunct FPS checkbox in settings menu, added hint text for f3 binding --- files/mygui/openmw_settings_window.layout | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index cb74636560..1d02ea19ae 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -256,6 +256,8 @@ + + @@ -273,6 +275,12 @@ + + + + + + From 13c7235b6b49b8ec76a1034e2876992adbccdffc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 00:13:13 +0100 Subject: [PATCH 1260/1812] Remove old FPS setting code --- apps/mwiniimporter/importer.cpp | 1 - apps/openmw/engine.cpp | 3 --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 28 +---------------------- apps/openmw/mwgui/hud.hpp | 8 +------ apps/openmw/mwgui/settingswindow.cpp | 12 ---------- apps/openmw/mwgui/settingswindow.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 11 +-------- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ---- files/mygui/openmw_hud.layout | 6 ----- files/mygui/openmw_settings_window.layout | 8 ------- files/mygui/openmw_text.skin.xml | 9 -------- files/settings-default.cfg | 5 ---- 13 files changed, 3 insertions(+), 96 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 479f8cba28..251889e281 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -20,7 +20,6 @@ MwIniImporter::MwIniImporter() { const char *map[][2] = { - { "fps", "General:Show FPS" }, { "no-sound", "General:Disable Audio" }, { 0, 0 } }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 089880fb26..5d2d588ed3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -168,9 +168,6 @@ void OMW::Engine::frame(float frametime) if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { -#if 0 - mEnvironment.getWindowManager()->wmUpdateFps(fps); -#endif mEnvironment.getWindowManager()->update(); } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fb7eca4a35..f364ada7ac 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -155,8 +155,6 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - virtual void wmUpdateFps(float fps) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a93bb47e9d..3922b1997c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -67,7 +67,7 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) + HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) @@ -85,8 +85,6 @@ namespace MWGui , mCellNameBox(NULL) , mDrowningFrame(NULL) , mDrowningFlash(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -161,8 +159,6 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - setFpsVisible(showFps); - LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); @@ -181,28 +177,6 @@ namespace MWGui delete mSpellIcons; } - void HUD::setFpsVisible(const bool visible) - { - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (visible) - { - getWidget(mFpsBox, "FPSBox"); - //mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); - } - } - - void HUD::setFPS(float fps) - { - if (mFpsCounter) - mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); - } - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { int current = std::max(0, static_cast(value.getCurrent())); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 629613c982..c5ae457891 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,10 +19,9 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); + HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setFPS(float fps); /// Set time left for the player to start drowning /// @param time time left to start drowning @@ -38,8 +37,6 @@ namespace MWGui void setEffectVisible(bool visible); void setMinimapVisible(bool visible); - void setFpsVisible(const 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); @@ -77,9 +74,6 @@ namespace MWGui MyGUI::TextBox* mWeaponSpellBox; MyGUI::Widget *mDrowningFrame, *mDrowningFlash; - MyGUI::Widget* mFpsBox; - MyGUI::TextBox* mFpsCounter; - // bottom left elements int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft; // bottom right elements diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 667dc0c285..eb2f235299 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -166,7 +166,6 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mWindowBorderButton, "WindowBorderButton"); - getWidget(mFPSButton, "FPSButton"); getWidget(mFOVSlider, "FOVSlider"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); @@ -201,7 +200,6 @@ namespace MWGui mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -256,8 +254,6 @@ namespace MWGui mShadowsEnabledButton->setEnabled(false); } - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); - MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); @@ -427,14 +423,6 @@ namespace MWGui } } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) - { - int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; - Settings::Manager::setInt("fps", "HUD", newLevel); - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); - apply(); - } - void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { Settings::Manager::setString("texture filtering", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 0369eb40ec..99553808b4 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -30,7 +30,6 @@ namespace MWGui MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mWindowBorderButton; - MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mFOVSlider; MyGUI::ScrollBar* mDifficultySlider; MyGUI::ScrollBar* mAnisotropySlider; @@ -53,7 +52,6 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); - void onFpsToggled(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e1e838cdf9..e2404c58a1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -185,7 +185,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mFPS(0.0f) , mFallbackMap(fallbackMap) , mShowOwned(0) , mVersionDescription(versionDescription) @@ -296,7 +295,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -464,8 +463,6 @@ namespace MWGui { cleanupGarbage(); - mHud->setFPS(mFPS); - mHud->update(); } @@ -1138,7 +1135,6 @@ namespace MWGui void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - mHud->setFpsVisible(static_cast(Settings::Manager::getInt("fps", "HUD"))); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); for (Settings::CategorySettingVector::const_iterator it = changed.begin(); @@ -1322,11 +1318,6 @@ namespace MWGui mConsole->executeFile (path); } - void WindowManager::wmUpdateFps(float fps) - { - mFPS = fps; - } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a1f76683e5..7df5508a16 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -180,8 +180,6 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - virtual void wmUpdateFps(float fps); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -486,8 +484,6 @@ namespace MWGui void updateMap(); - float mFPS; - std::map mFallbackMap; int mShowOwned; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 97b0184696..03c05260f3 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -125,11 +125,5 @@ - - - - - - diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 1d02ea19ae..22d36de2b6 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -255,14 +255,6 @@ - - - - - - - - diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index e459f22fab..b7a893580f 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -18,15 +18,6 @@ color_misc=0,205,205 # ???? - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7c809b9266..d68bc2fef7 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -84,11 +84,6 @@ fade start = 0.8 debug = false [HUD] -# FPS counter -# 0: not visible -# 1: FPS display -fps = 0 - crosshair = true [Objects] From 7ff168b787f33169456db82c3127b2c6f832cdbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:21:03 +0100 Subject: [PATCH 1261/1812] osgMyGUI: add support for layers to insert custom rendering state --- .../myguiplatform/myguirendermanager.cpp | 46 ++++++++++++++++--- .../myguiplatform/myguirendermanager.hpp | 6 +++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 160d659bd6..5bd56dc8f4 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -45,6 +45,9 @@ namespace osgMyGUI class Drawable : public osg::Drawable { osgMyGUI::RenderManager *mParent; + osg::ref_ptr mStateSet; + +public: // Stage 0: update widget animations and controllers. Run during the Update traversal. class FrameUpdate : public osg::Drawable::UpdateCallback @@ -101,6 +104,10 @@ class Drawable : public osg::Drawable { virtual void drawImplementation(osg::RenderInfo &renderInfo) const { osg::State *state = renderInfo.getState(); + + state->pushStateSet(mStateSet); + state->apply(); + state->disableAllVertexArrays(); state->setClientActiveTextureUnit(0); glEnableClientState(GL_VERTEX_ARRAY); @@ -113,6 +120,13 @@ class Drawable : public osg::Drawable { { const Batch& batch = *it; osg::VertexBufferObject *vbo = batch.mVertexBuffer; + + if (batch.mStateSet) + { + state->pushStateSet(batch.mStateSet); + state->apply(); + } + osg::Texture2D* texture = batch.mTexture; if(texture) state->applyTextureAttribute(0, texture); @@ -135,12 +149,20 @@ class Drawable : public osg::Drawable { } glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + + if (batch.mStateSet) + { + state->popStateSet(); + state->apply(); + } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + state->popStateSet(); + state->unbindVertexBufferObject(); state->dirtyAllVertexArrays(); state->disableAllVertexArrays(); @@ -161,10 +183,17 @@ public: osg::ref_ptr frameUpdate = new FrameUpdate; frameUpdate->setRenderManager(mParent); setUpdateCallback(frameUpdate); + + mStateSet = new osg::StateSet; + mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); + mStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) + , mStateSet(copy.mStateSet) , mWriteTo(0) , mReadFrom(0) { @@ -180,6 +209,9 @@ public: // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array osg::ref_ptr mArray; + // optional + osg::ref_ptr mStateSet; + size_t mVertexCount; }; @@ -321,6 +353,7 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R , mUpdate(false) , mIsInitialise(false) , mInvScalingFactor(1.f) + , mInjectState(NULL) { if (scalingFactor != 0.f) mInvScalingFactor = 1.f / scalingFactor; @@ -364,12 +397,6 @@ void RenderManager::initialise() camera->setViewMatrix(osg::Matrix::identity()); camera->setRenderOrder(osg::Camera::POST_RENDER); camera->setClearMask(GL_NONE); - osg::StateSet *state = new osg::StateSet; - state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); - state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - state->setMode(GL_BLEND, osg::StateAttribute::ON); - state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); @@ -418,10 +445,17 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC) mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin() } + if (mInjectState) + batch.mStateSet = mInjectState; mDrawable->addBatch(batch); } +void RenderManager::setInjectState(osg::StateSet* stateSet) +{ + mInjectState = stateSet; +} + void RenderManager::end() { } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index d9fdc1834a..f2251cdb04 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -20,6 +20,7 @@ namespace osg class Group; class Camera; class RenderInfo; + class StateSet; } namespace osgMyGUI @@ -48,6 +49,8 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget float mInvScalingFactor; + osg::StateSet* mInjectState; + void destroyAllResources(); public: @@ -95,6 +98,9 @@ public: /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to NULL again. */ + void setInjectState(osg::StateSet* stateSet); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } From 51f3a8fec66ce990d6cef41ed5b8490355a9791c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:39:31 +0100 Subject: [PATCH 1262/1812] osgMyGUI: move Platform methods to the .cpp file --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + components/CMakeLists.txt | 2 +- components/myguiplatform/myguiplatform.cpp | 62 +++++++++++++++++ components/myguiplatform/myguiplatform.hpp | 79 ++++++++-------------- 4 files changed, 91 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2404c58a1..6f2e7755d6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -33,6 +33,7 @@ #include #include +#include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00eac6ca52..1460dee7b5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -115,7 +115,7 @@ add_component_dir (loadinglistener ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer ) add_component_dir (widgets diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 01d6ca567f..22b88438f6 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -1,2 +1,64 @@ #include "myguiplatform.hpp" +#include "myguirendermanager.hpp" +#include "myguidatamanager.hpp" +#include "myguiloglistener.hpp" + +namespace osgMyGUI +{ + +Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::TextureManager *textureManager, float uiScalingFactor) + : mRenderManager(nullptr) + , mDataManager(nullptr) + , mLogManager(nullptr) + , mLogFacility(nullptr) +{ + mLogManager = new MyGUI::LogManager(); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); + mDataManager = new DataManager(); +} + +Platform::~Platform() +{ + delete mRenderManager; + mRenderManager = nullptr; + delete mDataManager; + mDataManager = nullptr; + delete mLogManager; + mLogManager = nullptr; + delete mLogFacility; + mLogFacility = nullptr; +} + +void Platform::initialise(const std::string &resourcePath, const std::string &_logName) +{ + if (!_logName.empty() && !mLogFacility) + { + mLogFacility = new LogFacility(_logName, false); + mLogManager->addLogSource(mLogFacility->getSource()); + } + + mDataManager->setResourcePath(resourcePath); + + mRenderManager->initialise(); + mDataManager->initialise(); +} + +void Platform::shutdown() +{ + mRenderManager->shutdown(); + mDataManager->shutdown(); +} + +RenderManager *Platform::getRenderManagerPtr() +{ + return mRenderManager; +} + +DataManager *Platform::getDataManagerPtr() +{ + return mDataManager; +} + + +} diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 513267c991..56562e12a6 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -1,71 +1,46 @@ #ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H #define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H -#include "MyGUI_Prerequest.h" -#include "MyGUI_LogManager.h" +#include -#include "myguirendermanager.hpp" -#include "myguidatamanager.hpp" -#include "myguiloglistener.hpp" +namespace osgViewer +{ + class Viewer; +} +namespace osg +{ + class Group; +} +namespace Resource +{ + class TextureManager; +} +namespace MyGUI +{ + class LogManager; +} namespace osgMyGUI { + class RenderManager; + class DataManager; + class LogFacility; + class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor) - : mRenderManager(nullptr) - , mDataManager(nullptr) - , mLogManager(nullptr) - , mLogFacility(nullptr) - { - mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); - mDataManager = new DataManager(); - } + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor); - ~Platform() - { - delete mRenderManager; - mRenderManager = nullptr; - delete mDataManager; - mDataManager = nullptr; - delete mLogManager; - mLogManager = nullptr; - delete mLogFacility; - mLogFacility = nullptr; - } + ~Platform(); - void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") - { - if (!_logName.empty() && !mLogFacility) - { - mLogFacility = new LogFacility(_logName, false); - mLogManager->addLogSource(mLogFacility->getSource()); - } + void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log"); - mDataManager->setResourcePath(resourcePath); + void shutdown(); - mRenderManager->initialise(); - mDataManager->initialise(); - } + RenderManager* getRenderManagerPtr(); - void shutdown() - { - mRenderManager->shutdown(); - mDataManager->shutdown(); - } - - RenderManager* getRenderManagerPtr() - { - return mRenderManager; - } - - DataManager* getDataManagerPtr() - { - return mDataManager; - } + DataManager* getDataManagerPtr(); private: RenderManager* mRenderManager; From 57b9eafa0fd2d4d073a3fee9176f24b4cd98de52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:45:22 +0100 Subject: [PATCH 1263/1812] osgMyGUI: implement AdditiveLayer --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ components/myguiplatform/additivelayer.cpp | 33 ++++++++++++++++++++++ components/myguiplatform/additivelayer.hpp | 33 ++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 components/myguiplatform/additivelayer.cpp create mode 100644 components/myguiplatform/additivelayer.hpp diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6f2e7755d6..fdf26d9499 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -34,6 +34,7 @@ #include #include +#include #include @@ -216,6 +217,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); ItemWidget::registerComponents(); diff --git a/components/myguiplatform/additivelayer.cpp b/components/myguiplatform/additivelayer.cpp new file mode 100644 index 0000000000..aa2ef08b3b --- /dev/null +++ b/components/myguiplatform/additivelayer.cpp @@ -0,0 +1,33 @@ +#include "additivelayer.hpp" + +#include +#include + +#include "myguirendermanager.hpp" + +namespace osgMyGUI +{ + + AdditiveLayer::AdditiveLayer() + { + mStateSet = new osg::StateSet; + mStateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE)); + } + + AdditiveLayer::~AdditiveLayer() + { + // defined in .cpp file since we can't delete incomplete types + } + + void AdditiveLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + RenderManager& renderManager = static_cast(MyGUI::RenderManager::getInstance()); + + renderManager.setInjectState(mStateSet.get()); + + MyGUI::OverlappedLayer::renderToTarget(_target, _update); + + renderManager.setInjectState(NULL); + } + +} diff --git a/components/myguiplatform/additivelayer.hpp b/components/myguiplatform/additivelayer.hpp new file mode 100644 index 0000000000..f3d47bc826 --- /dev/null +++ b/components/myguiplatform/additivelayer.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER + +#include + +#include + +namespace osg +{ + class StateSet; +} + +namespace osgMyGUI +{ + + /// @brief A Layer rendering with additive blend mode. + class AdditiveLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED( AdditiveLayer ) + + AdditiveLayer(); + ~AdditiveLayer(); + + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + private: + osg::ref_ptr mStateSet; + }; + +} + +#endif From a90ef8afd0aacf576467513cc9ec4e64732e2b40 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 17:48:36 +0100 Subject: [PATCH 1264/1812] layer renaming --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- files/mygui/openmw_layers.xml | 4 ++-- files/mygui/openmw_screen_fader.layout | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fdf26d9499..3fe786ab22 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -334,7 +334,7 @@ namespace MWGui mDebugWindow = new DebugWindow(); - mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"Overlay"); + mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); mHud->setVisible(mHudEnabled); diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cf577aec52..7b2955bbd4 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,7 +1,7 @@ - + @@ -12,6 +12,6 @@ - + diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout index 13234792f7..e9009d32a6 100644 --- a/files/mygui/openmw_screen_fader.layout +++ b/files/mygui/openmw_screen_fader.layout @@ -1,7 +1,7 @@ - + From d85d74e615818ba2abf71dd668b0581c077a1575 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 18:04:03 +0100 Subject: [PATCH 1265/1812] Use AdditiveLayer for the hit fader --- apps/openmw/mwgui/screenfader.cpp | 4 ++-- apps/openmw/mwgui/screenfader.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_layers.xml | 1 + files/mygui/openmw_screen_fader_hit.layout | 7 +++++++ 6 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 files/mygui/openmw_screen_fader_hit.layout diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 473776a82a..c44bcc3f1f 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -66,8 +66,8 @@ namespace MWGui mFader->notifyOperationFinished(); } - ScreenFader::ScreenFader(const std::string & texturePath) - : WindowBase("openmw_screen_fader.layout") + ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout) + : WindowBase(layout) , mCurrentAlpha(0.f) , mFactor(1.f) , mRepeat(false) diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 402554555e..d25f5fdc4e 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,7 +36,7 @@ namespace MWGui class ScreenFader : public WindowBase { public: - ScreenFader(const std::string & texturePath); + ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout"); void setTexture(const std::string & texturePath); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3fe786ab22..bf65377f6d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -329,7 +329,7 @@ namespace MWGui // TODO: check if non-BM versions actually use player_hit_01.dds if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) hitFaderTexture = "textures\\player_hit_01.dds"; - mHitFader = new ScreenFader(hitFaderTexture); + mHitFader = new ScreenFader(hitFaderTexture, "openmw_screen_fader_hit.layout"); mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index dc9e8ea848..7494d3ba2d 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_savegame_dialog.layout openmw_recharge_dialog.layout openmw_screen_fader.layout + openmw_screen_fader_hit.layout openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 7b2955bbd4..c8684c858f 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -2,6 +2,7 @@ + diff --git a/files/mygui/openmw_screen_fader_hit.layout b/files/mygui/openmw_screen_fader_hit.layout new file mode 100644 index 0000000000..7e60f0ff5a --- /dev/null +++ b/files/mygui/openmw_screen_fader_hit.layout @@ -0,0 +1,7 @@ + + + + + + + From 6c12c9a467cfeb0b4e640e9f48b95bfaec1bf3b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Nov 2015 19:45:30 +0100 Subject: [PATCH 1266/1812] Layer renaming fix --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bf65377f6d..58e33623d0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -248,7 +248,7 @@ namespace MWGui MyGUI::PointerManager::getInstance().setVisible(false); mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, - MyGUI::Align::Default, "Overlay"); + MyGUI::Align::Default, "InputBlocker"); mVideoBackground->setImageTexture("black"); mVideoBackground->setVisible(false); mVideoBackground->setNeedMouseFocus(true); From 231570f0916386c56fe7134106e56baf25d7cd9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 01:21:59 +0100 Subject: [PATCH 1267/1812] travis.yml fix --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22f6164c2f..0910ac5462 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com From 08a55febc874abb44216303110ea4dcc1db6525c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 17:52:39 +0100 Subject: [PATCH 1268/1812] Adjust Scroll window layout to better match MW --- files/mygui/openmw_scroll.layout | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index 194700f36e..e4ad23bba6 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -2,24 +2,24 @@ - + - + - + - + From 59aee04ddb33b50e4a02a6f4a296126a7bdf1d4f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:21:25 +0100 Subject: [PATCH 1269/1812] Implement ScalingLayer, for layouting of widgets in screen-relative coordinates --- components/CMakeLists.txt | 2 +- components/myguiplatform/scalinglayer.cpp | 138 ++++++++++++++++++++++ components/myguiplatform/scalinglayer.hpp | 31 +++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 components/myguiplatform/scalinglayer.cpp create mode 100644 components/myguiplatform/scalinglayer.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1460dee7b5..f8f4c64ab0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -115,7 +115,7 @@ add_component_dir (loadinglistener ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer scalinglayer ) add_component_dir (widgets diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp new file mode 100644 index 0000000000..7f7cac69b9 --- /dev/null +++ b/components/myguiplatform/scalinglayer.cpp @@ -0,0 +1,138 @@ +#include "scalinglayer.hpp" + +#include + +namespace osgMyGUI +{ + + /// @brief the ProxyRenderTarget allows to adjust the pixel scale and offset for a "source" render target. + class ProxyRenderTarget : public MyGUI::IRenderTarget + { + public: + /// @param target The target to render to. + /// @param viewSize The size of the underlying layer node to render. + /// @param hoffset The horizontal rendering offset, specified as an offset from the left screen edge in range 0-1. + /// @param voffset The vertical rendering offset, specified as an offset from the top screen edge in range 0-1. + ProxyRenderTarget(MyGUI::IRenderTarget* target, MyGUI::IntSize viewSize, float hoffset, float voffset) + : mTarget(target) + , mViewSize(viewSize) + , mHOffset(hoffset) + , mVOffset(voffset) + { + } + + virtual void begin() + { + mTarget->begin(); + } + + virtual void end() + { + mTarget->end(); + } + + virtual void doRender(MyGUI::IVertexBuffer* _buffer, MyGUI::ITexture* _texture, size_t _count) + { + mTarget->doRender(_buffer, _texture, _count); + } + + virtual const MyGUI::RenderTargetInfo& getInfo() + { + mInfo = mTarget->getInfo(); + mInfo.hOffset = mHOffset; + mInfo.vOffset = mVOffset; + mInfo.pixScaleX = 1.f / mViewSize.width; + mInfo.pixScaleY = 1.f / mViewSize.height; + return mInfo; + } + + private: + MyGUI::IRenderTarget* mTarget; + MyGUI::IntSize mViewSize; + float mHOffset, mVOffset; + MyGUI::RenderTargetInfo mInfo; + }; + + MyGUI::ILayerItem *ScalingLayer::getLayerItemByPoint(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + + return OverlappedLayer::getLayerItemByPoint(_left, _top); + } + + void ScalingLayer::screenToLayerCoords(int& _left, int& _top) const + { + float scale = getScaleFactor(); + if (scale <= 0.f) + return; + + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + _left -= globalViewSize.width/2; + _top -= globalViewSize.height/2; + + _left /= scale; + _top /= scale; + + _left += mViewSize.width/2; + _top += mViewSize.height/2; + } + + float ScalingLayer::getScaleFactor() const + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + float w = viewSize.width; + float h = viewSize.height; + + float heightScale = (h / mViewSize.height); + float widthScale = (w / mViewSize.width); + return std::min(widthScale, heightScale); + } + + MyGUI::IntPoint ScalingLayer::getPosition(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + return MyGUI::IntPoint(_left, _top); + } + + void ScalingLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize viewSize = globalViewSize; + viewSize.width /= getScaleFactor(); + viewSize.height /= getScaleFactor(); + + float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); + float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); + + ProxyRenderTarget proxy(_target, viewSize, hoffset, voffset); + + MyGUI::OverlappedLayer::renderToTarget(&proxy, _update); + } + + void ScalingLayer::resizeView(const MyGUI::IntSize &_viewSize) + { + // do nothing + } + + void ScalingLayer::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + MyGUI::OverlappedLayer::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next()) + { + if (info->getName() == "Property") + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Size") + { + mViewSize = MyGUI::IntSize::parse(value); + } + } + } + } + +} diff --git a/components/myguiplatform/scalinglayer.hpp b/components/myguiplatform/scalinglayer.hpp new file mode 100644 index 0000000000..3ee1489f19 --- /dev/null +++ b/components/myguiplatform/scalinglayer.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER + +#include + +namespace osgMyGUI +{ + + ///@brief A Layer that lays out and renders widgets in screen-relative coordinates. The "Size" property determines the size of the virtual screen, + /// which is then upscaled to the real screen size during rendering. The aspect ratio is kept intact, adding blanks to the sides when necessary. + class ScalingLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED(ScalingLayer) + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual MyGUI::ILayerItem* getLayerItemByPoint(int _left, int _top) const; + virtual MyGUI::IntPoint getPosition(int _left, int _top) const; + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + virtual void resizeView(const MyGUI::IntSize& _viewSize); + + private: + void screenToLayerCoords(int& _left, int& _top) const; + float getScaleFactor() const; + }; + +} + +#endif From f9932130dabc201067d32cca69b8b5b4e49b2c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:23:02 +0100 Subject: [PATCH 1270/1812] Work around MyGUI bug with mouse event coordinates (fixed in git) --- apps/openmw/mwgui/bookpage.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index cfb49ebffb..9878051f7a 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -949,12 +949,18 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse press coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == MyGUI::MouseButton::None) { - mFocusItem = mBook->hitTest (left, mViewTop + top); + mFocusItem = mBook->hitTest (pos.left, mViewTop + pos.top); mItemActive = true; dirtyFocusItem (); @@ -968,12 +974,19 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse release coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == id) { - Style * mItem = mBook->hitTest (left, mViewTop + top); + Style * mItem = mBook->hitTest (pos.left, mViewTop + pos.top); bool clicked = mFocusItem == mItem; From a7ad45e73e32131716bbdf871231fe43aa8abe0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:23:47 +0100 Subject: [PATCH 1271/1812] WindowBase::center use the layer size instead of render window size --- apps/openmw/mwgui/windowbase.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 191e8223d8..c9d1b06175 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -49,11 +49,13 @@ void WindowBase::center() { // Centre dialog - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize layerSize = MyGUI::RenderManager::getInstance().getViewSize(); + if (mMainWidget->getLayer()) + layerSize = mMainWidget->getLayer()->getSize(); MyGUI::IntCoord coord = mMainWidget->getCoord(); - coord.left = (gameWindowSize.width - coord.width)/2; - coord.top = (gameWindowSize.height - coord.height)/2; + coord.left = (layerSize.width - coord.width)/2; + coord.top = (layerSize.height - coord.height)/2; mMainWidget->setCoord(coord); } From 516f2765a15c7c80fcc8784f953c1d5e2842bbd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:24:28 +0100 Subject: [PATCH 1272/1812] Use the ScalingLayer for journal, books and scrolls --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ files/mygui/openmw_book.layout | 2 +- files/mygui/openmw_journal.layout | 2 +- files/mygui/openmw_layers.xml | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 58e33623d0..a7c3a19576 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -218,6 +219,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Layer"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); ItemWidget::registerComponents(); diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 2336d5b2ca..7c158af8dc 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 5524f55202..9c40bd5623 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index c8684c858f..c6d3df5210 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -6,6 +6,9 @@ + + + From 79b3f1e6a823ff5fbf9784adb4db9f991d477ec5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:27:01 +0100 Subject: [PATCH 1273/1812] Small cleanup --- components/myguiplatform/scalinglayer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index 7f7cac69b9..19ae108410 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -99,8 +99,9 @@ namespace osgMyGUI { MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize viewSize = globalViewSize; - viewSize.width /= getScaleFactor(); - viewSize.height /= getScaleFactor(); + float scale = getScaleFactor(); + viewSize.width /= scale; + viewSize.height /= scale; float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); From 75f11f781c85acc3d6efa077403e1fb12db710d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 18:32:41 +0100 Subject: [PATCH 1274/1812] Use the ScalingLayer for Scroll window --- files/mygui/openmw_scroll.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index e4ad23bba6..b2e62f28d8 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -2,7 +2,7 @@ - + From 66925be44073dbd45d1c107823eb6c2c1633edea Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 19:59:33 +0100 Subject: [PATCH 1275/1812] Partially revert 682f30ef9c7e8edad3e825be6920670ffac3bdce This change made dead netch fall through the floor, because the animation moves the creature *below* its external collision box. --- apps/openmw/mwphysics/physicssystem.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 92994d5574..739b0013b8 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,8 +240,6 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); - float collisionShapeOffset = physicActor->getPosition().z() - position.z(); - // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -258,11 +256,17 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - position.z() += collisionShapeOffset; + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + + // NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos). + // That means the collision shape used for moving this actor is in a different spot than the collision shape + // other actors are using to collide against this actor. + // While this is strictly speaking wrong, it's needed for MW compatibility. + position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -370,7 +374,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) + && newPosition.z() + halfExtents.z() > waterlevel) newPosition = oldPosition; } else @@ -451,7 +455,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning return newPosition; } }; From f0a1434578506727f86c935f72c0be2d3f986044 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Nov 2015 20:58:00 +0100 Subject: [PATCH 1276/1812] Dead actors underwater will float to the surface --- apps/openmw/mwphysics/physicssystem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 739b0013b8..55144afe75 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -288,6 +288,11 @@ namespace MWPhysics velocity = velocity + physicActor->getInertialForce(); } } + + // dead actors underwater will float to the surface + if (ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) + velocity = osg::Vec3f(0,0,1) * 25; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; // Now that we have the effective movement vector, apply wind forces to it From 055841e721734b043f1f80be6f3653547332239a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 02:22:40 +0100 Subject: [PATCH 1277/1812] Improve cloud lighting --- apps/openmw/mwrender/sky.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 12708ba481..5c38d79d4d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1563,17 +1563,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } - if (mCloudColour != weather.mSunColor) + if (mCloudColour != weather.mFogColor) { - // FIXME: this doesn't look correct - osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, - weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, - weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + osg::Vec4f clr (weather.mFogColor); + clr += osg::Vec4f(0.13f, 0.13f, 0.13f, 0.f); mCloudUpdater->setEmissionColor(clr); mCloudUpdater2->setEmissionColor(clr); - mCloudColour = weather.mSunColor; + mCloudColour = weather.mFogColor; } if (mSkyColour != weather.mSkyColor) From b89945804c829443beac2de8c80730c2a2dbb7a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 02:57:49 +0100 Subject: [PATCH 1278/1812] BookPage: implement hit test with margin for error --- apps/openmw/mwgui/bookpage.cpp | 46 +++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 9878051f7a..b728b748f7 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -153,6 +153,34 @@ struct TypesetBookImpl : TypesetBook visitRuns (top, bottom, NULL, visitor); } + /// hit test with a margin for error. only hits on interactive text fragments are reported. + StyleImpl * hitTestWithMargin (int left, int top) + { + StyleImpl * hit = hitTest(left, top); + if (hit && hit->mInteractiveId > 0) + return hit; + + const int maxMargin = 10; + for (int margin=1; margin < maxMargin; ++margin) + { + for (int i=0; i<4; ++i) + { + if (i==0) + hit = hitTest(left, top-margin); + else if (i==1) + hit = hitTest(left, top+margin); + else if (i==2) + hit = hitTest(left-margin, top); + else + hit = hitTest(left+margin, top); + + if (hit && hit->mInteractiveId > 0) + return hit; + } + } + return NULL; + } + StyleImpl * hitTest (int left, int top) const { for (Sections::const_iterator i = mSections.begin (); i != mSections.end (); ++i) @@ -916,15 +944,15 @@ public: left -= mCroppedParent->getAbsoluteLeft (); top -= mCroppedParent->getAbsoluteTop (); - Style * Hit = mBook->hitTest (left, mViewTop + top); + Style * hit = mBook->hitTestWithMargin (left, mViewTop + top); if (mLastDown == MyGUI::MouseButton::None) { - if (Hit != mFocusItem) + if (hit != mFocusItem) { dirtyFocusItem (); - mFocusItem = Hit; + mFocusItem = hit; mItemActive = false; dirtyFocusItem (); @@ -933,7 +961,7 @@ public: else if (mFocusItem != 0) { - bool newItemActive = Hit == mFocusItem; + bool newItemActive = hit == mFocusItem; if (newItemActive != mItemActive) { @@ -960,7 +988,7 @@ public: if (mLastDown == MyGUI::MouseButton::None) { - mFocusItem = mBook->hitTest (pos.left, mViewTop + pos.top); + mFocusItem = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); mItemActive = true; dirtyFocusItem (); @@ -986,9 +1014,9 @@ public: if (mLastDown == id) { - Style * mItem = mBook->hitTest (pos.left, mViewTop + pos.top); + Style * item = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); - bool clicked = mFocusItem == mItem; + bool clicked = mFocusItem == item; mItemActive = false; @@ -996,8 +1024,8 @@ public: mLastDown = MyGUI::MouseButton::None; - if (clicked && mLinkClicked && mItem && mItem->mInteractiveId != 0) - mLinkClicked (mItem->mInteractiveId); + if (clicked && mLinkClicked && item && item->mInteractiveId != 0) + mLinkClicked (item->mInteractiveId); } } From b61b732207e9ec5e48023987e368156375916b57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 09:07:18 +0100 Subject: [PATCH 1279/1812] fixed an interference with script warning mode and error downgrading (Fixes #2990) --- components/compiler/errorhandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index a987a86da2..7f02255db2 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -32,7 +32,10 @@ namespace Compiler void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) { - if (mWarningsMode==1) + if (mWarningsMode==1 || + // temporarily change from mode 2 to mode 1 if error downgrading is enabled to + // avoid infinite recursion + (mWarningsMode==2 && mDowngradeErrors)) { ++mWarnings; report (message, loc, WarningMessage); From cdf17f415e5357723aae6d49fb32419d55154f70 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 12:03:27 +0100 Subject: [PATCH 1280/1812] updated version number --- CMakeLists.txt | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e966a1635..d33521e8ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 36) -set(OPENMW_VERSION_RELEASE 1) +set(OPENMW_VERSION_MINOR 37) +set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index 362d2eef45..f353cd76ef 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.36.1 +* Version: 0.37.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From 93b0008a18da08760ac93b149c6c282594fa51c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Nov 2015 12:14:36 +0100 Subject: [PATCH 1281/1812] updated changelog --- CHANGELOG.md | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e7dc25c2..3a3cdfd252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,228 @@ +0.37.0 +------ + + Bug #385: Light emitting objects have a too short distance of activation + Bug #455: Animation doesn't resize creature's bounding box + Bug #602: Only collision model is updated when modifying objects trough console + Bug #639: Sky horizon at nighttime + Bug #672: incorrect trajectory of the moons + Bug #814: incorrect NPC width + Bug #827: Inaccurate raycasting for dead actors + Bug #996: Can see underwater clearly when at right height/angle + Bug #1317: Erene Llenim in Seyda Neen does not walk around + Bug #1330: Cliff racers fail to hit the player + Bug #1366: Combat AI can't aim down (in order to hit small creatures) + Bug #1511: View distance while under water is much too short + Bug #1563: Terrain positioned incorrectly and appears to vibrate in far-out cells + Bug #1612: First person models clip through walls + Bug #1647: Crash switching from full screen to windows mode - D3D9 + Bug #1650: No textures with directx on windows + Bug #1730: Scripts names starting with digit(s) fail to compile + Bug #1738: Socucius Ergalla's greetings are doubled during the tutorial + Bug #1813: Underwater flora lighting up entire area. + Bug #1871: Handle controller extrapolation flags + Bug #1921: Footstep frequency and velocity do not immediately update when speed attribute changes + Bug #2001: OpenMW crashes on start with OpenGL 1.4 drivers + Bug #2014: Antialiasing setting does nothing on Linux + Bug #2037: Some enemies attack the air when spotting the player + Bug #2052: NIF rotation matrices including scales are not supported + Bug #2111: Raindrops in front of fire look wrong + Bug #2140: [OpenGL] Water effects, flames and parts of creatures solid black when observed through brazier flame + Bug #2147: Trueflame and Hopesfire flame effects not properly aligned with blade + Bug #2148: Verminous fabricants have little coloured box beneath their feet + Bug #2149: Sparks in Clockwork City should bounce off the floor + Bug #2151: Clockwork City dicer trap doesn't activate when you're too close + Bug #2186: Mini map contains scrambled pixels that cause the mini map to flicker + Bug #2187: NIF file with more than 255 NiBillboardNodes does not load + Bug #2191: Editor: Crash when trying to view cell in render view in OpenCS + Bug #2270: Objects flicker transparently + Bug #2280: Latest 32bit windows build of openmw runns out of vram + Bug #2281: NPCs don't scream when they die + Bug #2286: Jumping animation restarts when equipping mid-air + Bug #2287: Weapon idle animation stops when turning + Bug #2355: Light spell doesn't work in 1st person view + Bug #2362: Lantern glas opaque to flame effect from certain viewing angles + Bug #2364: Light spells are not as bright as in Morrowind + Bug #2383: Remove the alpha testing override list + Bug #2436: Crash on entering cell "Tower of Tel Fyr, Hall of Fyr" + Bug #2457: Player followers should not report crimes + Bug #2458: crash in some fighting situations + Bug #2464: Hiding an emitter node should make that emitter stop firing particles + Bug #2466: Can't load a save created with OpenMW-0.35.0-win64 + Bug #2468: music from title screen continues after loading savegame + Bug #2494: Map not consistent between saves + Bug #2504: Dialog scroll should always start at the top + Bug #2506: Editor: Undo/Redo shortcuts do not work in script editor + Bug #2513: Mannequins in mods appear as dead bodies + Bug #2524: Editor: TopicInfo "custom" condition section is missing + Bug #2540: Editor: search and verification result table can not be sorted by clicking on the column names + Bug #2543: Editor: there is a problem with spell effects + Bug #2544: Editor fails to save NPC information correctly. + Bug #2545: Editor: delete record in Objects (referenceables) table messes up data + Bug #2546: Editor: race base attributes and skill boni are not displayed, thus not editable + Bug #2547: Editor: some NPC data is not displayed, thus not editable + Bug #2551: Editor: missing data in cell definition + Bug #2553: Editor: value filter does not work for float values + Bug #2555: Editor: undo leaves the record status as Modified + Bug #2559: Make Detect Enchantment marks appear on top of the player arrow + Bug #2563: position consoling npc doesn't work without cell reload + Bug #2564: Editor: Closing a subview from code does not clean up properly and will lead to crash on opening the next subview + Bug #2568: Editor: Setting default window size is ignored + Bug #2569: Editor: saving from an esp to omwaddon file results in data loss for TopicInfo + Bug #2575: Editor: Deleted record (with Added (ModifiedOnly) status) remains in the Dialog SubView + Bug #2576: Editor: Editor doesn't scroll to a newly opened subview, when ScrollBar Only mode is active + Bug #2578: Editor: changing Level or Reputation of an NPC crashes the editor + Bug #2579: Editor: filters not updated when adding or cloning records + Bug #2580: Editor: omwaddon makes OpenMW crash + Bug #2581: Editor: focus problems in edit subviews single- and multiline input fields + Bug #2582: Editor: object verifier should check for non-existing scripts being referenced + Bug #2583: Editor: applying filter to TopicInfo on mods that have added dialouge makes the Editor crash + Bug #2586: Editor: some dialogue only editable items do not refresh after undo + Bug #2588: Editor: Cancel button exits program + Bug #2589: Editor: Regions table - mapcolor does not change correctly + Bug #2591: Placeatme - spurious 5th parameter raises error + Bug #2593: COC command prints multiple times when GUI is hidden + Bug #2598: Editor: scene view of instances has to be zoomed out to displaying something - center camera instance please + Bug #2607: water behind an invisible NPC becomes invisible as well + Bug #2611: Editor: Sort problem in Objects table when few nested rows are added + Bug #2621: crash when a creature has no model + Bug #2624: Editor: missing columns in tables + Bug #2627: Character sheet doesn't properly update when backing out of CharGen + Bug #2642: Editor: endif without if - is not reported as error when "verify" was executed + Bug #2644: Editor: rebuild the list of available content files when opening the open/new dialogues + Bug #2656: OpenMW & OpenMW-CS: setting "Flies" flag for ghosts has no effect + Bug #2659: OpenMW & OpenMW-CS: savegame load fail due to script attached to NPCs + Bug #2668: Editor: reputation value in the input field is not stored + Bug #2696: Horkers use land idle animations under water + Bug #2705: Editor: Sort by Record Type (Objects table) is incorrect + Bug #2711: Map notes on an exterior cell that shows up with a map marker on the world map do not show up in the tooltip for that cell's marker on the world map + Bug #2714: Editor: Can't reorder rows with the same topic in different letter case + Bug #2720: Head tracking for creatures not implemented + Bug #2722: Alchemy should only include effects shared by at least 2 ingredients + Bug #2723: "ori" console command is not working + Bug #2726: Ashlanders in front of Ghostgate start wandering around + Bug #2727: ESM writer does not handle encoding when saving the TES3 header + Bug #2728: Editor: Incorrect position of an added row in Info tables + Bug #2731: Editor: Deleting a record triggers a Qt warning + Bug #2733: Editor: Undo doesn't restore the Modified status of a record when a nested data is changed + Bug #2734: Editor: The Search doesn't work + Bug #2738: Additive moon blending + Bug #2746: NIF node names should be case insensitive + Bug #2752: Fog depth/density not handled correctly + Bug #2753: Editor: line edit in dialogue subview tables shows after a single click + Bug #2755: Combat AI changes target too frequently + Bug #2761: Can't attack during block animations + Bug #2764: Player doesn't raise arm in 3rd person for weathertype 9 + Bug #2768: Current screen resolution not selected in options when starting OpenMW + Bug #2773: Editor: Deleted scripts are editable + Bug #2776: ordinators still think I'm wearing their helm even though Khajiit and argonians can't + Bug #2779: Slider bars continue to move if you don't release mouse button + Bug #2781: sleep interruption is a little off (is this an added feature?) + Bug #2782: erroneously able to ready weapon/magic (+sheathe weapon/magic) while paralyzed + Bug #2785: Editor: Incorrect GMSTs for newly created omwgame files + Bug #2786: Kwama Queen head is inverted under OpenMW + Bug #2788: additem and removeitem incorrect gold behavior + Bug #2790: --start doesn't trace down + Bug #2791: Editor: Listed attributes and skill should not be based on number of NPC objects. + Bug #2792: glitched merchantile/infinite free items + Bug #2794: Need to ignore quotes in names of script function + Bug #2797: Editor: Crash when removing the first row in a nested table + Bug #2800: Show an error message when S3TC support is missing + Bug #2811: Targetted Open spell effect persists. + Bug #2819: Editor: bodypart's race filter not displayed correctly + Bug #2820: Editor: table sorting is inverted + Bug #2821: Editor: undo/redo command labels are incorrect + Bug #2826: locking beds that have been locked via magic psuedo-freezes the game + Bug #2830: Script compiler does not accept IDs as instruction/functions arguments if the ID is also a keyword + Bug #2832: Cell names are not localized on the world map + Bug #2833: [cosmetic] Players swimming at water's surface are slightly too low. + Bug #2840: Save/load menu is not entirely localized + Bug #2853: [exploit/bug] disintegrate weapon incorrectly applying to lockpicks, probes. creates unbreakable lockpicks + Bug #2855: Mouse wheel in journal is not disabled by "Options" panel. + Bug #2856: Heart of Lorkhan doesn't visually respond to attacks + Bug #2863: Inventory highlights wrong category after load + Bug #2864: Illuminated Order 1.0c Bug – The teleport amulet is not placed in the PC inventory. + Bug #2866: Editor: use checkbox instead of combobox for boolean values + Bug #2875: special cases of fSleepRandMod not behaving properly. + Bug #2878: Editor: Verify reports "creature has non-positive level" but there is no level setting + Bug #2879: Editor: entered value of field "Buys *" is not saved for a creature + Bug #2880: OpenMW & OpenMW-CS: having a scale value of 0.000 makes the game laggy + Bug #2882: Freeze when entering cell "Guild of Fighters (Ald'ruhn)" after dropping some items inside + Bug #2884: NPC chats about wrong player race + Bug #2886: Adding custom races breaks existing numbering of PcRace + Bug #2888: Editor: value entered in "AI Wander Idle" is not kept + Bug #2889: Editor: creatures made with the CS (not cloned) are always dead + Bug #2890: Editor: can't make NPC say a specific "Hello" voice-dialouge + Bug #2893: Editor: making a creature use textual dialogue doesn't work. + Bug #2901: Editor: gold for trading can not be set for creatures + Bug #2907: looking from uderwater part of the PC that is below the surface looks like it would be above the water + Bug #2914: Magicka not recalculated on character generation + Bug #2915: When paralyzed, you can still enter and exit sneak + Bug #2917: chameleon does not work for creatures + Bug #2927: Editor: in the automatic script checker local variable caches are not invalidated/updated on modifications of other scripts + Bug #2930: Editor: AIWander Idle can not be set for a creature + Bug #2932: Editor: you can add rows to "Creature Attack" but you can not enter values + Bug #2938: Editor: Can't add a start script. + Bug #2944: Spell chance for power to show as 0 on hud when used + Bug #2953: Editor: rightclick in an empty place in the menu bar shows an unnamed checkbox + Bug #2956: Editor: freezes while editing Filter + Bug #2962: OpenMW: Assertion `it != invStore.end()' failed + Bug #2964: Recursive script execution can corrupt script runtime data + Bug #2973: Editor: placing a chest in the game world and activating it heavily blurrs the character portrait + Bug #2978: Editor: Cannot edit alchemy ingredient properties + Bug #2980: Editor: Attribute and Skill can be selected for spells that do not require these parameters, leading to non-functional spells + Bug #2990: Compiling a script with warning mode 2 and enabled error downgrading leads to infinite recursion + Bug #2992: [Mod: Great House Dagoth] Killing Dagoth Gares freezes the game + Feature #706: Editor: Script Editor enhancements + Feature #872: Editor: Colour values in tables + Feature #880: Editor: ID auto-complete + Feature #928: Editor: Partial sorting in info tables + Feature #942: Editor: Dialogue for editing/viewing content file meta information + Feature #1057: NiStencilProperty + Feature #1278: Editor: Mouse picking in worldspace widget + Feature #1280: Editor: Cell border arrows + Feature #1401: Editor: Cloning enhancements + Feature #1463: Editor: Fine grained configuration of extended revert/delete commands + Feature #1591: Editor: Make fields in creation bar drop targets where applicable + Feature #1998: Editor: Magic effect record verifier + Feature #1999: Editor Sound Gen record verifier + Feature #2000: Editor: Pathgrid record verifier + Feature #2528: Game Time Tracker + Feature #2534: Editor: global search does not auomatically focus the search input field + Feature #2535: OpenMW: allow comments in openmw.cfg + Feature #2541: Editor: provide a go to the very bottom button for TopicInfo and JournalInfo + Feature #2549: Editor: add a horizontal slider to scroll between opened tables + Feature #2558: Editor: provide a shortcut for closing the subview that has the focus + Feature #2565: Editor: add context menu for dialogue sub view fields with an item matching "Edit 'x'" from the table subview context menu + Feature #2585: Editor: Ignore mouse wheel input for numeric values unless the respective widget has the focus + Feature #2620: Editor: make the verify-view refreshable + Feature #2622: Editor: Make double click behaviour in result tables configurable (see ID tables) + Feature #2717: Editor: Add severity column to report tables + Feature #2729: Editor: Various dialogue button bar improvements + Feature #2739: Profiling overlay + Feature #2740: Resource manager optimizations + Feature #2741: Make NIF files into proper resources + Feature #2742: Use the skinning data in NIF files as-is + Feature #2743: Small feature culling + Feature #2744: Configurable near clip distance + Feature #2745: GUI scaling option + Feature #2747: Support anonymous textures + Feature #2749: Loading screen optimizations + Feature #2751: Character preview optimization + Feature #2804: Editor: Merge Tool + Feature #2818: Editor: allow copying a record ID to the clipboard + Feature #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it + Feature #2946: Editor: add script line number in results of search + Feature #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings + Feature #2963: Editor: Mouse button bindings in 3D scene + Feature #2983: Sun Glare fader + Feature #2999: Scaling of journal and books + Task #2665: Support building with Qt5 + Task #2725: Editor: Remove Display_YesNo + Task #2730: Replace hardcoded column numbers in SimpleDialogueSubView/DialogueSubView + Task #2750: Bullet shape instancing optimization + Task #2793: Replace grid size setting with half grid size setting + 0.36.1 ------ From 2fb4a9df6d992ca9ee14f3632c51a1fff0ca8a92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 15:32:16 +0100 Subject: [PATCH 1282/1812] Update CHANGELOG.md (features that should be bugs instead) --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3cdfd252..c5905a897c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,6 +148,7 @@ Bug #2879: Editor: entered value of field "Buys *" is not saved for a creature Bug #2880: OpenMW & OpenMW-CS: having a scale value of 0.000 makes the game laggy Bug #2882: Freeze when entering cell "Guild of Fighters (Ald'ruhn)" after dropping some items inside + Bug #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it Bug #2884: NPC chats about wrong player race Bug #2886: Adding custom races breaks existing numbering of PcRace Bug #2888: Editor: value entered in "AI Wander Idle" is not kept @@ -166,6 +167,7 @@ Bug #2944: Spell chance for power to show as 0 on hud when used Bug #2953: Editor: rightclick in an empty place in the menu bar shows an unnamed checkbox Bug #2956: Editor: freezes while editing Filter + Bug #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings Bug #2962: OpenMW: Assertion `it != invStore.end()' failed Bug #2964: Recursive script execution can corrupt script runtime data Bug #2973: Editor: placing a chest in the game world and activating it heavily blurrs the character portrait @@ -211,9 +213,7 @@ Feature #2751: Character preview optimization Feature #2804: Editor: Merge Tool Feature #2818: Editor: allow copying a record ID to the clipboard - Feature #2883: game not playable if mod providing a spell is removed but the list of known spells still contains it Feature #2946: Editor: add script line number in results of search - Feature #2959: space character in field enchantment (of an amulet) prevents rendering of surroundings Feature #2963: Editor: Mouse button bindings in 3D scene Feature #2983: Sun Glare fader Feature #2999: Scaling of journal and books From 35f5be680bb877bd4c8ad9ae48c1126fb25a6d69 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 16:52:39 +0100 Subject: [PATCH 1283/1812] Support for NiVisController on trishape nodes --- components/nifosg/nifloader.cpp | 60 +++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2b73f779f6..a8865e7d2d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -609,15 +609,20 @@ namespace NifOsg } else if (ctrl->recType == Nif::RC_NiVisController) { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - - osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); - setupController(visctrl, callback, animflags); - transformNode->addUpdateCallback(callback); + handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } + void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -942,28 +947,31 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geometry; - if(!triShape->controller.empty()) - { - Nif::ControllerPtr ctrl = triShape->controller; - do { - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); - setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); - break; - } - } while(!(ctrl=ctrl->next).empty()); + osg::ref_ptr geometry; + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } } if (!geometry.get()) geometry = new osg::Geometry; - osg::ref_ptr geode (new osg::Geode); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); geode->addDrawable(geometry); @@ -1043,6 +1051,16 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } + } + osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 64abdbabe3f2b169ebcc9932dc910512592dcae7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:00:33 +0100 Subject: [PATCH 1284/1812] Small refactor of controllers handling, print warning messages for unhandled controllers --- components/nifosg/nifloader.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a8865e7d2d..49bc7b0fba 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -536,7 +536,7 @@ namespace NifOsg handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, composite, boundTextures, animflags); + handleMeshControllers(nifNode, node, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) @@ -570,7 +570,7 @@ namespace NifOsg return node; } - void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -587,6 +587,14 @@ namespace NifOsg setupController(uvctrl, ctrl, animflags); composite->addController(ctrl); } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), node, animflags); + } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + {} // handled in handleTriShape + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } @@ -815,6 +823,8 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) partctrl = static_cast(ctrl.getPtr()); + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } if (!partctrl) { @@ -962,10 +972,7 @@ namespace NifOsg static_cast(ctrl.getPtr())->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); geometry->setUpdateCallback(morphctrl); - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + break; } } @@ -1051,16 +1058,6 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); - for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); - } - } - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 1b52749ae1930e5322e19066a2513d8b9dccfece Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:30:11 +0100 Subject: [PATCH 1285/1812] Adjust third person camera height based on character height --- apps/openmw/mwrender/camera.cpp | 13 ++++++++++--- apps/openmw/mwrender/camera.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index fb6573d65f..ea8c60bf32 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -42,7 +42,8 @@ namespace MWRender { Camera::Camera (osg::Camera* camera) - : mCamera(camera), + : mHeightScale(1.f), + mCamera(camera), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -93,7 +94,7 @@ namespace MWRender osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) - position.z() += mHeight; + position.z() += mHeight * mHeightScale; return position; } @@ -372,11 +373,17 @@ namespace MWRender mTrackingNode = mAnimation->getNode("Camera"); if (!mTrackingNode) mTrackingNode = mAnimation->getNode("Head"); + mHeightScale = 1.f; } else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); + osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); + mTrackingNode = transform; + if (transform) + mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + else + mHeightScale = 1.f; } rotateCamera(getPitch(), getYaw(), false); } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index a655e1c1f8..899fc94471 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -29,6 +29,7 @@ namespace MWRender MWWorld::Ptr mTrackingPtr; osg::ref_ptr mTrackingNode; + float mHeightScale; osg::ref_ptr mCamera; @@ -97,6 +98,8 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } + void updateScale(); + void processViewChange(); void update(float duration, bool paused=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 45c04ceecd..27ea7ebed4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -439,6 +439,9 @@ namespace MWRender void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) { ptr.getRefData().getBaseNode()->setScale(scale); + + if (ptr == mCamera->getTrackingPtr()) // update height of camera + mCamera->processViewChange(); } void RenderingManager::removeObject(const MWWorld::Ptr &ptr) From 1200ff91866ae430d9e5d3e4d1ccff3d133e1ba6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:31:41 +0100 Subject: [PATCH 1286/1812] RigGeometry: fix incorrect bounding box in the first frame The default computeBound() was overriding the manually set bounding box. --- components/sceneutil/riggeometry.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 8eb08f546d..ac29ee3e87 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -2,9 +2,9 @@ #include #include - #include +#include #include #include "skeleton.hpp" @@ -58,6 +58,14 @@ public: } }; +// We can't compute the bounds without a NodeVisitor, since we need the current geomToSkelMatrix. +// So we return nothing. Bounds are updated every frame in the UpdateCallback. +class DummyComputeBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback +{ +public: + virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return osg::BoundingBox(); } +}; + RigGeometry::RigGeometry() : mSkeleton(NULL) , mLastFrameNumber(0) @@ -66,6 +74,7 @@ RigGeometry::RigGeometry() setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); + setComputeBoundingBoxCallback(new DummyComputeBoundCallback); } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) @@ -278,6 +287,12 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) } _boundingBox = box; + _boundingBoxComputed = true; +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. + _boundingSphere = osg::BoundingSphere(_boundingBox); + _boundingSphereComputed = true; +#endif for (unsigned int i=0; idirtyBound(); } From bd8332d2b01ab600b6405c7d6a0b73cf7746e8a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:57:17 +0100 Subject: [PATCH 1287/1812] Remove default copyop argument for nodecallback copy constructors Works around a compiler warning with OSG 3.4: warning: base class 'class osg::Callback' should be explicitly initialized in the copy constructor [-Wextra] With no default argument for osg::CopyOp&, the compiler no longer sees the function as a real copy constructor and stops warning about the missing virtual initializations. We don't care about this warning because there is nothing interesting to initialize in the osg::NodeCallback base anyway. A proper fix for the warning would require to inserting OSG_VERSION conditional compiling all over the place, that is as long as we are still supporting OSG 3.2. --- components/nifosg/controller.hpp | 2 +- components/nifosg/particle.hpp | 2 +- components/sceneutil/lightmanager.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 58870317e9..d0c6d1de33 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -146,7 +146,7 @@ namespace NifOsg { public: UVController(); - UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const UVController&,const osg::CopyOp&); UVController(const Nif::NiUVData *data, std::set textureUnits); META_Object(NifOsg,UVController) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index c7d5d585d4..0434898658 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -60,7 +60,7 @@ namespace NifOsg InverseWorldMatrix() { } - InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) + InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op) : osg::Object(), osg::NodeCallback() { } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index e62dc00e58..bcdcdf7dc7 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -121,7 +121,7 @@ namespace SceneUtil : mLightManager(NULL) , mLastFrameNumber(0) {} - LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) , mLightManager(copy.mLightManager) , mLastFrameNumber(0) From 801dc8eee381e30c64a52d8c27513d3c284b940a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:17:21 +0100 Subject: [PATCH 1288/1812] ObstacleCheck: fix weird distance calculation --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 53f12a982e..b5c0dedd40 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -126,8 +126,8 @@ namespace MWMechanics if(mDistSameSpot == -1) mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); - bool samePosition = (std::abs(pos.pos[0] - mPrevX) < mDistSameSpot) && - (std::abs(pos.pos[1] - mPrevY) < mDistSameSpot); + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + // update position mPrevX = pos.pos[0]; mPrevY = pos.pos[1]; From caa523a9592c80abdacc102bc6a5c9d94b15af25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:21:25 +0100 Subject: [PATCH 1289/1812] ObstacleCheck: fix the framerate not being taken into account --- apps/openmw/mwmechanics/obstacle.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index b5c0dedd40..078c31ac09 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,7 +11,7 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 1.8f; + static const float DIST_SAME_SPOT = 0.72f; static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; @@ -114,19 +114,22 @@ namespace MWMechanics * t = how long before considered stuck * u = how long to move sideways * - * DIST_SAME_SPOT is calibrated for movement speed of around 150. - * A rat has walking speed of around 30, so we need to adjust for - * that. */ bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration) { const MWWorld::Class& cls = actor.getClass(); ESM::Position pos = actor.getRefData().getPosition(); - if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); + // actors can move at most 60 fps (the physics framerate). + // the max() can be removed if we implement physics interpolation. + float movementDuration = std::max(1/60.f, duration); - bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + if(mDistSameSpot == -1) + mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); + + float distSameSpot = mDistSameSpot * movementDuration; + + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; // update position mPrevX = pos.pos[0]; From d233bc483d195afbbacbad7b6b2c940bace024b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:26:18 +0100 Subject: [PATCH 1290/1812] ObstacleCheck: fix evasion issue The check if (samePosition... would not work as intended because actors do not move in every frame when the framerate is higher than the physics framerate. In that case the actor would change its evasion direction almost every frame. --- apps/openmw/mwmechanics/obstacle.cpp | 13 +++++-------- apps/openmw/mwmechanics/obstacle.hpp | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 078c31ac09..8c9ab33800 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -163,13 +163,13 @@ namespace MWMechanics { mStuckDuration = 0; mWalkState = State_Evade; + chooseEvasionDirection(); } } } /* FALL THROUGH */ case State_Evade: { - chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -191,16 +191,13 @@ namespace MWMechanics actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } - void ObstacleCheck::chooseEvasionDirection(bool samePosition) + void ObstacleCheck::chooseEvasionDirection() { // change direction if attempt didn't work - if (samePosition && (0 < mEvadeDuration)) + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) { - ++mEvadeDirectionIndex; - if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) - { - mEvadeDirectionIndex = 0; - } + mEvadeDirectionIndex = 0; } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ecff00a5c2..6b442f5a50 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -65,7 +65,7 @@ namespace MWMechanics float mDistSameSpot; // take account of actor's speed int mEvadeDirectionIndex; - void chooseEvasionDirection(bool samePosition); + void chooseEvasionDirection(); }; } From 3c338b9da994b0c0d2d222e3ef08ab1cf44daa6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:31:40 +0100 Subject: [PATCH 1291/1812] ObstacleCheck: tweak the stuck detection parameters The netch_betty wander animation starts up so slowly that the creature thought it was stuck, even though it's not. --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 8c9ab33800..7def96bef3 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,8 +11,8 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 0.72f; - static const float DURATION_SAME_SPOT = 1.0f; + static const float DIST_SAME_SPOT = 0.5f; + static const float DURATION_SAME_SPOT = 1.5f; static const float DURATION_TO_EVADE = 0.4f; const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = From 637cd3a628e365899752a7a95e865e21fd854fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 01:01:41 +0100 Subject: [PATCH 1292/1812] Adjust the FirstPersonNeckController to follow the camera with a reduced factor (Fixes #1784) --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 18 ++++++++++++++++-- apps/openmw/mwrender/npcanimation.hpp | 7 +++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c9b2489848..129206f519 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1479,6 +1479,8 @@ bool CharacterController::updateWeaponState() } } + mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped); + return forcestateupdate; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1e46cc71a5..5aaa4071b8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -439,6 +439,7 @@ public: virtual void setHeadYaw(float yawRadians); virtual float getHeadPitch() const; virtual float getHeadYaw() const; + virtual void setAccurateAiming(bool enabled) {} private: Animation(const Animation&); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b3838a33b..8156712661 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -281,7 +281,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mSoundsDisabled(disableSounds) + mSoundsDisabled(disableSounds), + mAccurateAiming(false), + mAimingFactor(0.f) { mNpc = mPtr.get()->mBase; @@ -726,7 +728,14 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) if (mFirstPersonNeckController) { - mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); + if (mAccurateAiming) + mAimingFactor = 1.f; + else + mAimingFactor = std::max(0.f, mAimingFactor - timepassed * 0.5f); + + float rotateFactor = 0.75f + 0.25f * mAimingFactor; + + mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0] * rotateFactor, osg::Vec3f(-1,0,0))); mFirstPersonNeckController->setOffset(mFirstPersonOffset); } @@ -1072,4 +1081,9 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } +void NpcAnimation::setAccurateAiming(bool enabled) +{ + mAccurateAiming = enabled; +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b4272226d9..2289703c8f 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -67,6 +67,9 @@ private: bool mSoundsDisabled; + bool mAccurateAiming; + float mAimingFactor; + void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, @@ -104,6 +107,10 @@ public: virtual void enableHeadAnimation(bool enable); + /// 1: the first person meshes follow the camera's rotation completely + /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands + virtual void setAccurateAiming(bool enabled); + virtual void setWeaponGroup(const std::string& group); virtual osg::Vec3f runAnimation(float timepassed); From 37158df339d1cc5b760e54f9e260ce565ab0915e Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Nov 2015 14:59:26 +0100 Subject: [PATCH 1293/1812] Update scalinglayer.cpp MSVC Explicitly requires for std::min and/or max --- components/myguiplatform/scalinglayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index 19ae108410..ee9de349ed 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -1,6 +1,7 @@ #include "scalinglayer.hpp" #include +#include namespace osgMyGUI { From 91583fc027024e1cb80eed63d8a0a24f6eaa8ff0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:00:33 +0100 Subject: [PATCH 1294/1812] Fix MWRender::Mask_ParticleSystem --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ components/resource/scenemanager.cpp | 17 +++++++++++++---- components/resource/scenemanager.hpp | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 27ea7ebed4..e0a0c75c65 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -137,6 +137,8 @@ namespace MWRender , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { + resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); + osg::ref_ptr lightRoot = new SceneUtil::LightManager; mLightRoot = lightRoot; lightRoot->setStartLight(1); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 08fa7bc9b3..f2840574b6 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -25,8 +25,10 @@ namespace class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor { public: - InitWorldSpaceParticlesVisitor() + /// @param mask The node mask to set on ParticleSystem nodes. + InitWorldSpaceParticlesVisitor(unsigned int mask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMask(mask) { } @@ -47,7 +49,7 @@ namespace if (geode->getNumParents() && geode->getParent(0)->getNumParents()) transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); } - geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem + geode->setNodeMask(mMask); } } } @@ -74,8 +76,9 @@ namespace box.expandBy(sphere); partsys->setInitialBound(box); } + private: + unsigned int mMask; }; - } namespace Resource @@ -84,6 +87,7 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) : mVFS(vfs) , mTextureManager(textureManager) + , mParticleSystemMask(~0u) { } @@ -183,7 +187,7 @@ namespace Resource void SceneManager::notifyAttached(osg::Node *node) const { - InitWorldSpaceParticlesVisitor visitor; + InitWorldSpaceParticlesVisitor visitor (mParticleSystemMask); node->accept(visitor); } @@ -197,4 +201,9 @@ namespace Resource return mTextureManager; } + void SceneManager::setParticleSystemMask(unsigned int mask) + { + mParticleSystemMask = mask; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 168247a156..5ecb875acd 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -73,12 +73,17 @@ namespace Resource Resource::TextureManager* getTextureManager(); + /// @param mask The node mask to apply to loaded particle system nodes. + void setParticleSystemMask(unsigned int mask); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; osg::ref_ptr mIncrementalCompileOperation; + unsigned int mParticleSystemMask; + // observer_ptr? typedef std::map > Index; Index mIndex; From 35459f20d54602d6c465863cb7975e183c4607fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:19:51 +0100 Subject: [PATCH 1295/1812] Refactor lighting mask --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwrender/vismask.hpp | 17 +++++++-------- apps/openmw/mwrender/water.cpp | 4 ++-- components/sceneutil/lightmanager.cpp | 25 ++++++++++++++++------- components/sceneutil/lightmanager.hpp | 13 +++++++++--- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 06065c566d..c3ddbf2973 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1066,6 +1066,7 @@ namespace MWRender osg::ref_ptr lightSource = new SceneUtil::LightSource; osg::Light* light = new osg::Light; lightSource->setLight(light); + lightSource->setNodeMask(Mask_Lighting); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e0a0c75c65..c55d11795d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -140,6 +140,7 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setLightingMask(Mask_Lighting); mLightRoot = lightRoot; lightRoot->setStartLight(1); @@ -165,7 +166,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - source->setNodeMask(SceneUtil::Mask_Lit); + source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index a26bde1d13..dd6e85e2ca 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,16 +15,16 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Water = (1<<6), - Mask_Terrain = (1<<7), - Mask_FirstPerson = (1<<8), + Mask_Water = (1<<6), // choose Water or SimpleWater depending on detail required + Mask_SimpleWater = (1<<7), + Mask_Terrain = (1<<8), + Mask_FirstPerson = (1<<9), // child of Sky - Mask_Sun = (1<<9), - Mask_WeatherParticles = (1<<10), + Mask_Sun = (1<<10), + Mask_WeatherParticles = (1<<11), // child of Water - Mask_SimpleWater = (1<<11), // top level masks Mask_Scene = (1<<12), @@ -34,9 +34,10 @@ namespace MWRender Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<15) + Mask_RenderToTexture = (1<<15), - // reserved: (1<<16) for SceneUtil::Mask_Lit + // Set on a camera's cull mask to enable the LightManager + Mask_Lighting = (1<<16) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 80023ecdaa..e93060f7c2 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -302,7 +302,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -378,7 +378,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1e1d04cf50..dc6da73a66 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -131,6 +131,7 @@ namespace SceneUtil LightManager::LightManager() : mStartLight(0) + , mLightingMask(~0u) { setUpdateCallback(new LightManagerUpdateCallback); } @@ -138,10 +139,21 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mStartLight(copy.mStartLight) + , mLightingMask(copy.mLightingMask) { } + void LightManager::setLightingMask(unsigned int mask) + { + mLightingMask = mask; + } + + unsigned int LightManager::getLightingMask() const + { + return mLightingMask; + } + void LightManager::update() { mLights.clear(); @@ -237,7 +249,6 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { - setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); mId = sLightId++; } @@ -260,12 +271,6 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); - if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) - { - traverse(node, nv); - return; - } - if (!mLightManager) { mLightManager = findLightManager(nv->getNodePath()); @@ -276,6 +281,12 @@ namespace SceneUtil } } + if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask())) + { + traverse(node, nv); + return; + } + // Possible optimizations: // - cull list of lights by the camera frustum // - organize lights in a quad tree diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index bcdcdf7dc7..27ee1cdaa8 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,9 +9,6 @@ namespace SceneUtil { - // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. - const int Mask_Lit = (1<<16); - /// LightSource managed by a LightManager. class LightSource : public osg::Node { @@ -68,6 +65,14 @@ namespace SceneUtil LightManager(const LightManager& copy, const osg::CopyOp& copyop); + /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired. + /// By default, it's ~0u i.e. always on. + /// If you have some views that do not require lighting, then set the Camera's cull mask to not include + /// the lightingMask for a much faster cull and rendering. + void setLightingMask (unsigned int mask); + + unsigned int getLightingMask() const; + // Called automatically by the UpdateCallback void update(); @@ -111,6 +116,8 @@ namespace SceneUtil LightStateSetMap mStateSetCache; int mStartLight; + + unsigned int mLightingMask; }; /// @note Not thread safe for CullThreadPerCamera threading mode. From f1ac408f352fed6c5520b6bae1b6c120ff4873bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:21:56 +0100 Subject: [PATCH 1296/1812] Place Drawables directly in the scene graph when built with OSG 3.4 OSG 3.4 adds the ability to place Drawables directly in the scene graph, without a Geode decorating them. Leveraging this should give a small performance boost, because the redundant Geodes increase culling overhead. There is still an oustanding issue with the RemoveDrawableVisitor no longer working correctly, because Drawables can have multiple parents. --- apps/openmw/mwrender/animation.cpp | 22 ++++++++++++ apps/openmw/mwrender/objects.cpp | 9 +++++ apps/openmw/mwrender/sky.cpp | 47 ++++++++++++------------ components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++------- components/resource/scenemanager.cpp | 50 +++++++++++++++++--------- components/sceneutil/visitor.cpp | 12 ++++--- components/sceneutil/visitor.hpp | 1 + 7 files changed, 138 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c3ddbf2973..c2cbb46278 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -196,10 +197,18 @@ namespace traverse(node); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + mToRemove.push_back(&drw); + } +#endif + void remove() { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); @@ -219,6 +228,18 @@ namespace } virtual void apply(osg::Geode &node) + { + applyImpl(node); + } + +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + applyImpl(drw); + } +#endif + + void applyImpl(osg::Node& node) { const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) @@ -232,6 +253,7 @@ namespace { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bdefdcafa3..9f4fe2de2d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -54,11 +55,19 @@ namespace for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) geode.removeDrawable(*it); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + mToRemove.push_back(partsys); + } +#endif void remove() { for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5c38d79d4d..7d38308b1d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -351,33 +351,36 @@ public: for (unsigned int i=0; iasGeometry(); - if (!geom) - continue; - - osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); - for (unsigned int i=0; isize(); ++i) + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) { - float alpha = 1.f; - if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (mMeshType == 1) - { - if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 0.25098; // second row - else alpha = 1.f; - } - else if (mMeshType == 2) - { - osg::Vec4Array* origColors = static_cast(geom->getColorArray()); - alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; - } - - (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; } - geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); } + + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); } private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 49bc7b0fba..b926d7eea8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // resource #include @@ -885,9 +886,6 @@ namespace NifOsg // localToWorldMatrix for transforming to particle space handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); - std::vector drawableProps; collectDrawableProperties(nifNode, drawableProps); applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); @@ -907,13 +905,21 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + osg::Node* toAttach = geode.get(); +#else + osg::Node* toAttach = partsys.get(); +#endif + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) - parentNode->addChild(geode); + parentNode->addChild(toAttach); else { osg::MatrixTransform* trans = new osg::MatrixTransform; trans->setUpdateCallback(new InverseWorldMatrix); - trans->addChild(geode); + trans->addChild(toAttach); parentNode->addChild(trans); } } @@ -957,8 +963,6 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry; for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -981,21 +985,36 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); +#endif if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost geometry->setDataVariance(osg::Object::STATIC); - osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + osg::ref_ptr geom2 = static_cast(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(geometry); + frameswitch->addChild(geom2); +#endif + parentNode->addChild(frameswitch); } else +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) parentNode->addChild(geode); +#else + parentNode->addChild(geometry); +#endif } osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -1056,8 +1075,6 @@ namespace NifOsg void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); @@ -1090,17 +1107,27 @@ namespace NifOsg } rig->setInfluenceMap(map); - geode->addDrawable(rig); - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost rig->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(rig); + osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); - osg::ref_ptr frameswitch = new FrameSwitch; frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + SceneUtil::RigGeometry* rig2 = static_cast(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES| + osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(rig); + frameswitch->addChild(rig2); +#endif parentNode->addChild(frameswitch); } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f2840574b6..20bee13d1d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -32,31 +33,48 @@ namespace { } - void apply(osg::Node& node) + bool isWorldSpaceParticleSystem(osgParticle::ParticleSystem* partsys) { - if (osg::Geode* geode = node.asGeode()) + // HACK: ParticleSystem has no getReferenceFrame() + return (partsys->getUserDataContainer() + && partsys->getUserDataContainer()->getNumDescriptions() > 0 + && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace"); + } + + void apply(osg::Geode& geode) + { + for (unsigned int i=0;igetNumDrawables();++i) + if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode.getDrawable(i))) { - if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode->getDrawable(i))) + if (isWorldSpaceParticleSystem(partsys)) { - // HACK: ParticleSystem has no getReferenceFrame() - if (partsys->getUserDataContainer() - && partsys->getUserDataContainer()->getNumDescriptions() > 0 - && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace") - { - // HACK: Ignore the InverseWorldMatrix transform the geode is attached to - if (geode->getNumParents() && geode->getParent(0)->getNumParents()) - transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); - } - geode->setNodeMask(mMask); + // HACK: Ignore the InverseWorldMatrix transform the geode is attached to + if (geode.getNumParents() && geode.getParent(0)->getNumParents()) + transformInitialParticles(partsys, geode.getParent(0)->getParent(0)); } + geode.setNodeMask(mMask); } } - - traverse(node); } +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. + void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + { + if (isWorldSpaceParticleSystem(partsys)) + { + // HACK: Ignore the InverseWorldMatrix transform the particle system is attached to + if (partsys->getNumParents() && partsys->getParent(0)->getNumParents()) + transformInitialParticles(partsys, partsys->getParent(0)->getParent(0)); + } + partsys->setNodeMask(mMask); + } + } +#endif + void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { osg::MatrixList mats = node->getWorldMatrices(); diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 3738be08d1..0a5ad2d006 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -22,11 +22,13 @@ namespace SceneUtil void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) { for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } + apply(*geode.getDrawable(i)); + } + + void DisableFreezeOnCullVisitor::apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + partsys->setFreezeOnCull(false); } } diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 6560849407..dcfefe9cd6 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -35,6 +35,7 @@ namespace SceneUtil } virtual void apply(osg::Geode &geode); + virtual void apply(osg::Drawable& drw); }; } From 0409e5a043d1d2db1c07aded5f73e5a8b2a9b25b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:28:58 +0100 Subject: [PATCH 1297/1812] Use OSG_VERSION_GREATER_EQUAL / LESS_THAN rather than MIN_VERSION_REQUIRED (cosmetic change) --- apps/openmw/mwrender/sky.cpp | 2 +- components/nifosg/nifloader.cpp | 10 +++++----- components/resource/scenemanager.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- components/sceneutil/controller.cpp | 4 ++-- components/sceneutil/riggeometry.cpp | 2 +- components/sdlutil/sdlgraphicswindow.cpp | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d38308b1d..66253f70d5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1271,7 +1271,7 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b926d7eea8..ccf840dfe6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -905,7 +905,7 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); osg::Node* toAttach = geode.get(); @@ -985,7 +985,7 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); #endif @@ -997,7 +997,7 @@ namespace NifOsg geometry->setDataVariance(osg::Object::STATIC); osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); @@ -1010,7 +1010,7 @@ namespace NifOsg parentNode->addChild(frameswitch); } else -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) parentNode->addChild(geode); #else parentNode->addChild(geometry); @@ -1113,7 +1113,7 @@ namespace NifOsg osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 20bee13d1d..eb4a4992de 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -58,7 +58,7 @@ namespace } } -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. void apply(osg::Drawable& drw) { diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index c2f76a527f..8b80efcdca 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -119,7 +119,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index a2c1cdcd39..7762b48d07 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -65,7 +65,7 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); @@ -96,7 +96,7 @@ namespace SceneUtil { osg::Drawable* drw = geode.getDrawable(i); -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = drw->getUpdateCallback(); #else osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ac29ee3e87..bd3d613a31 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -288,7 +288,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingBox = box; _boundingBoxComputed = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. _boundingSphere = osg::BoundingSphere(_boundingBox); _boundingSphereComputed = true; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 84aafa1004..da4b666ec4 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -109,7 +109,7 @@ void GraphicsWindowSDL2::init() mValid = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); @@ -130,7 +130,7 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); From 7776c49fc15a921d2e81bf24c46be88de80f8157 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:42:59 +0100 Subject: [PATCH 1298/1812] GraphicsWindowSDL2: adjust the log levels --- components/sdlutil/sdlgraphicswindow.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index da4b666ec4..49afe32a88 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -2,7 +2,6 @@ #include -#include #include namespace SDLUtil @@ -79,15 +78,13 @@ void GraphicsWindowSDL2::init() if(!_traits.valid()) return; - // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); - WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; mOwnsWindow = (mWindow == 0); if(mOwnsWindow) { - OSG_NOTICE<<"Error: No SDL window provided."< Date: Tue, 10 Nov 2015 19:18:02 +0100 Subject: [PATCH 1299/1812] Fixing bug for merchant --- apps/openmw/mwworld/containerstore.cpp | 56 +++++++++++++++++++------- apps/openmw/mwworld/containerstore.hpp | 7 ++-- components/esm/inventorystate.cpp | 9 ++++- components/esm/inventorystate.hpp | 2 +- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bcaaeff94a..78a50b4e78 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -442,9 +442,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks if (!levItem.empty() && count < 0) { - if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) - mLevelledItemMap[id] = 0; - mLevelledItemMap[id] += std::abs(count); + //If there is no item in map, insert it + std::map >::iterator itemInMap = + mLevelledItemMap.insert(std::make_pair(id, std::make_pair(0, levItem))).first; + //Update spawned count + itemInMap->second.first += std::abs(count); } count = std::abs(count); @@ -461,30 +463,56 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { - // Remove the items already spawned by levelled items that will restock - for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) - { - if (count(it->first) >= it->second) - remove(it->first, it->second, ptr); - } - mLevelledItemMap.clear(); + //allowedForReplace - Holds information about how many items from the list were sold; + // Hence, tells us how many items we need to restock. + //allowedForReplace[list] <- How many items we should generate(how many of these were sold) + std::map allowedForReplace; + //Check which lists need restocking: + for (std::map >::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + { + int spawnedCount = it->second.first; //How many items should be in shop originally + int itemCount = count(it->first); //How many items are there in shop now + //If anything was sold + if(itemCount < spawnedCount) + { + //Create entry if it does not exist yet + std::map::iterator listInMap = allowedForReplace.insert( + std::make_pair(it->second.second, 0)).first; + //And signal that we need to restock item from this list + listInMap->second += std::abs(spawnedCount - itemCount); + //Also, remove the record if item no longer figures in the shop + if(!itemCount) + mLevelledItemMap.erase(it->first); + //If there's still item in the shop, change its spawnedCount to current count. + else + it->second.first -= itemCount; + } + } + + //Restock: + //For every item that NPC could have for (std::vector::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it) { + //If he shouldn't have it restocked, don't restock it. if (it->mCount >= 0) continue; - std::string item = Misc::StringUtils::lowerCase(it->mItem.toString()); + std::string itemOrList = Misc::StringUtils::lowerCase(it->mItem.toString()); + //If it's levelled list, restock if there's need to do so. if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, it->mCount, true); + std::map::iterator listInMap = allowedForReplace.find(itemOrList); + if(listInMap != allowedForReplace.end()) + addInitialItem(itemOrList, owner, listInMap->second, true); } else { - int currentCount = count(item); + //Restocking static item - just restock to the max count + int currentCount = count(itemOrList); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); + addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e9750a6228..aaf83755a3 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -68,9 +69,9 @@ namespace MWWorld MWWorld::CellRefList repairs; MWWorld::CellRefList weapons; - std::map mLevelledItemMap; - ///< Stores result of levelled item spawns. - /// This is used to remove the spawned item(s) if the levelled item is restocked. + std::map > mLevelledItemMap; + ///< Stores result of levelled item spawns. + /// This is used to restock levelled items(s) if the old item was sold. mutable float mCachedWeight; mutable bool mWeightUpToDate; diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index e7257ae537..1864b6e8df 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -36,6 +36,10 @@ void ESM::InventoryState::load (ESMReader &esm) { std::string id = esm.getHString(); int count; + std::string parentList; + //TODO: How should I handle old saves? + if(esm.isNextSub("LLST")) + std::string parentList = esm.getHString(); esm.getHNT (count, "COUN"); mLevelledItemMap[id] = count; } @@ -79,10 +83,11 @@ void ESM::InventoryState::save (ESMWriter &esm) const iter->save (esm, true); } - for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map >::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { esm.writeHNString ("LEVM", it->first); - esm.writeHNT ("COUN", it->second); + esm.writeHNT ("COUN", it->second.first); + esm.writeHNString("LLST", it->second.second) } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index d5c317beb9..a12be321ff 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -20,7 +20,7 @@ namespace ESM // std::map mEquipmentSlots; - std::map mLevelledItemMap; + std::map > mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From 8e3bc981a218b669bdc567ca27d856595977475e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 21:45:53 +0100 Subject: [PATCH 1300/1812] Fix self-referencing camera --- apps/openmw/mwrender/globalmap.cpp | 10 ++++------ apps/openmw/mwrender/localmap.cpp | 12 +++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 3445e4189b..1e0a9112fc 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -62,9 +62,8 @@ namespace class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(MWRender::GlobalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } @@ -73,7 +72,7 @@ namespace { if (mRendered) { - mCamera->setNodeMask(0); + node->setNodeMask(0); return; } @@ -82,13 +81,12 @@ namespace if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } } private: bool mRendered; - osg::ref_ptr mCamera; MWRender::GlobalMap* mParent; }; @@ -263,7 +261,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e479119ee1..14ec770e84 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,22 +30,21 @@ namespace class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(MWRender::LocalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } - virtual void operator()(osg::Node*, osg::NodeVisitor*) + virtual void operator()(osg::Node* node, osg::NodeVisitor*) { if (mRendered) - mCamera->setNodeMask(0); + node->setNodeMask(0); if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, @@ -55,7 +54,6 @@ namespace private: bool mRendered; - osg::ref_ptr mCamera; MWRender::LocalMap* mParent; }; @@ -205,7 +203,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(this)); return camera; } From b840c68f0c5ad860a074be71e851d6298d8cc717 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 21:46:40 +0100 Subject: [PATCH 1301/1812] Do not create a depth buffer for the global map 2d rendering --- apps/openmw/mwrender/globalmap.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 1e0a9112fc..f91f7674f8 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -266,6 +266,9 @@ namespace MWRender camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); + // no need for a depth buffer + camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT); + if (cpuCopy) { // Attach an image to copy the render back to the CPU when finished @@ -286,10 +289,12 @@ namespace MWRender { osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); osg::ref_ptr depth = new osg::Depth; - depth->setFunction(osg::Depth::ALWAYS); - geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + depth->setWriteMask(0); + osg::StateSet* stateset = geom->getOrCreateStateSet(); + stateset->setAttribute(depth); + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(geom); camera->addChild(geode); From 2e9805fa0ee57fa5d724c04f8c2230cc0ba5a927 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 00:50:57 +0100 Subject: [PATCH 1302/1812] Leak fix --- apps/openmw/mwrender/characterpreview.cpp | 9 ++++----- apps/openmw/mwrender/characterpreview.hpp | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb950ea795..f7296b1bd0 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -157,11 +157,10 @@ namespace MWRender void CharacterPreview::rebuild() { - delete mAnimation; - mAnimation = NULL; + mAnimation.reset(NULL); - mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, - (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); + mAnimation.reset(new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal))); onSetup(); @@ -194,7 +193,7 @@ namespace MWRender void InventoryPreview::update() { - if (!mAnimation) + if (!mAnimation.get()) return; mAnimation->showWeapons(true); diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 0f85cc3bf9..32c1850c65 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -2,6 +2,7 @@ #define MWRENDER_CHARACTERPREVIEW_H #include +#include #include @@ -61,7 +62,7 @@ namespace MWRender MWWorld::Ptr mCharacter; - MWRender::NpcAnimation* mAnimation; + std::auto_ptr mAnimation; osg::ref_ptr mNode; std::string mCurrentAnimGroup; From fc93dc619578eff74c647ee35a3875b4c79332ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:32:31 +0100 Subject: [PATCH 1303/1812] Remove a stray method declaration --- components/nifosg/particle.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 0434898658..bfb127218d 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -139,9 +139,6 @@ namespace NifOsg META_Object(NifOsg, ParticleColorAffector) - // TODO: very similar to vec3 version, refactor to a template - osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys); - virtual void operate(osgParticle::Particle* particle, double dt); private: From c62c1693e9dd3741b44d84faabf119ef20c08d3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:47:11 +0100 Subject: [PATCH 1304/1812] Disable copy constructor and operator= in PartHolder --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5aaa4071b8..b1c34576bd 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -61,6 +61,9 @@ public: private: osg::ref_ptr mNode; + + void operator= (const PartHolder&); + PartHolder(const PartHolder&); }; typedef boost::shared_ptr PartHolderPtr; From afa590bddb5a991cd35aeabd17f43e3ae2fb0e1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:04:17 +0100 Subject: [PATCH 1305/1812] Leak fix --- apps/openmw/mwrender/rotatecontroller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/rotatecontroller.hpp b/apps/openmw/mwrender/rotatecontroller.hpp index 8c3758cb00..456a6dd200 100644 --- a/apps/openmw/mwrender/rotatecontroller.hpp +++ b/apps/openmw/mwrender/rotatecontroller.hpp @@ -27,7 +27,7 @@ protected: bool mEnabled; osg::Quat mRotate; - osg::ref_ptr mRelativeTo; + osg::Node* mRelativeTo; }; From 1edcb219a70f757221810e8c5861dc58972bd691 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:27:17 +0100 Subject: [PATCH 1306/1812] Leak fix --- components/nifosg/nifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ccf840dfe6..3e7f47b6fa 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1407,7 +1407,7 @@ namespace NifOsg osg::StateSet* stateset = node->getOrCreateStateSet(); int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; + osg::ref_ptr mat (new osg::Material); mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); // NIF material defaults don't match OpenGL defaults @@ -1462,12 +1462,11 @@ namespace NifOsg case Nif::RC_NiAlphaProperty: { const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; if (alphaprop->flags&1) { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)), + osg::StateAttribute::ON); bool noSort = (alphaprop->flags>>13)&1; if (!noSort) @@ -1482,11 +1481,10 @@ namespace NifOsg stateset->setRenderBinToInherit(); } - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; if((alphaprop->flags>>9)&1) { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), + alphaprop->data.threshold/255.f), osg::StateAttribute::ON); } else { From 0a52ee17c31851a3c9ad4ea576d0782a1f8feb2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:04:06 +0100 Subject: [PATCH 1307/1812] Fix Drawable removal issues --- apps/openmw/mwrender/animation.cpp | 92 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2cbb46278..b5f0a2036d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,58 +175,71 @@ namespace return 0.0f; } - - // Removes all drawables from a graph. - class RemoveDrawableVisitor : public osg::NodeVisitor + /// @brief Base class for visitors that remove nodes from a scene graph. + /// Subclasses need to fill the mToRemove vector. + /// To use, node->accept(removeVisitor); removeVisitor.remove(); + class RemoveVisitor : public osg::NodeVisitor { public: - RemoveDrawableVisitor() + RemoveVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { } - virtual void apply(osg::Geode &node) + void remove() { - // Not safe to remove in apply(), since the visitor is still iterating the child list - osg::Group* parent = node.getParent(0); - // prune nodes that would be empty after the removal - if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC) - mToRemove.push_back(parent); - else - mToRemove.push_back(&node); - traverse(node); + for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + it->second->removeChild(it->first); + } + + protected: + // + typedef std::vector > RemoveVec; + std::vector > mToRemove; + }; + + // Removes all drawables from a graph. + class RemoveDrawableVisitor : public RemoveVisitor + { + public: + virtual void apply(osg::Geode &geode) + { + applyImpl(geode); } #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { - mToRemove.push_back(&drw); + applyImpl(drw); } #endif - void remove() + void applyImpl(osg::Node& node) { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); - } - } + osg::NodePath::iterator parent = getNodePath().end()-2; + // We know that the parent is a Group because only Groups can have children. + osg::Group* parentGroup = static_cast(*parent); - private: - std::vector mToRemove; + // Try to prune nodes that would be empty after the removal + if (parent != getNodePath().begin()) + { + // This could be extended to remove the parent's parent, and so on if they are empty as well. + // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance. + osg::Group* parentParent = static_cast(*(parent - 1)); + if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) + { + mToRemove.push_back(std::make_pair(parentGroup, parentParent)); + return; + } + } + + mToRemove.push_back(std::make_pair(&node, parentGroup)); + } }; - class RemoveTriBipVisitor : public osg::NodeVisitor + class RemoveTriBipVisitor : public RemoveVisitor { public: - RemoveTriBipVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - virtual void apply(osg::Geode &node) { applyImpl(node); @@ -244,24 +257,11 @@ namespace const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) { + osg::Group* parent = static_cast(*(getNodePath().end()-2)); // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.push_back(&node); + mToRemove.push_back(std::make_pair(&node, parent)); } } - - void remove() - { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); - } - } - - private: - std::vector mToRemove; }; } From 9c503cbd8c0b9f4235e3f7ca0be18c43931684d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:07:31 +0100 Subject: [PATCH 1308/1812] Add build* to the gitignore Allows one to have multiple build folders, e.g. a separate build for a different OSG versions, or for different OpenMW versions, or when you often switch between branches. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88f591aae9..e1abcaa639 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ CMakeCache.txt cmake_install.cmake Makefile makefile -build +build* prebuilt ## doxygen From 02148a43f5da34d3d4be31adf9c148e9de8951d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:22:31 +0100 Subject: [PATCH 1309/1812] Node mask fix --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f0a2036d..55a47d4b69 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1317,6 +1317,7 @@ namespace MWRender { mGlowLight = new SceneUtil::LightSource; mGlowLight->setLight(new osg::Light); + mGlowLight->setNodeMask(Mask_Lighting); osg::Light* light = mGlowLight->getLight(); light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0)); From 79c44d0bfe33deb2ccacda73ac631cdb31931133 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:23:47 +0100 Subject: [PATCH 1310/1812] Style fix --- apps/openmw/mwrender/camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index ea8c60bf32..1d43cde43f 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -381,7 +381,7 @@ namespace MWRender osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); mTrackingNode = transform; if (transform) - mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + mHeightScale = transform->getScale().z(); else mHeightScale = 1.f; } From a68fd791c849d0820d3286921cc6ffa46b54258f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:24:27 +0100 Subject: [PATCH 1311/1812] Remove a stray method declaration --- apps/openmw/mwrender/camera.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 899fc94471..fab63cd3f2 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -98,8 +98,6 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } - void updateScale(); - void processViewChange(); void update(float duration, bool paused=false); From fef0a40bee1809658079f52d2d2a64c742a6a948 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Nov 2015 19:55:14 +0100 Subject: [PATCH 1312/1812] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3cdfd252..cb88ca5d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -338,6 +338,7 @@ Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1743: Moons are transparent Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. + Bug #1784: First person weapons always in the same position Bug #1785: Can't equip two-handed weapon and shield Bug #1809: Player falls too easily Bug #1825: Sword of Perithia can´t run in OpenMW From a07c6b4364b6696abca0f4559275cc4f321b4930 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Nov 2015 19:57:38 +0100 Subject: [PATCH 1313/1812] Modified the changelog for the wrong version. Oops. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e51023422d..378348ff84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug #1650: No textures with directx on windows Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1738: Socucius Ergalla's greetings are doubled during the tutorial + Bug #1784: First person weapons always in the same position Bug #1813: Underwater flora lighting up entire area. Bug #1871: Handle controller extrapolation flags Bug #1921: Footstep frequency and velocity do not immediately update when speed attribute changes @@ -338,7 +339,6 @@ Bug #1730: Scripts names starting with digit(s) fail to compile Bug #1743: Moons are transparent Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. - Bug #1784: First person weapons always in the same position Bug #1785: Can't equip two-handed weapon and shield Bug #1809: Player falls too easily Bug #1825: Sword of Perithia can´t run in OpenMW From 8aacbc398f629ecec0abe79317b6a6f5724fb8d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 00:52:36 +0100 Subject: [PATCH 1314/1812] Rotations: don't wrap the angle values for non-actors It's not really necessary, and just complicates logic elsewhere. Neither does vanilla MW do it. As well, the question is if wrapping to [-PI, PI] or [0, 2*PI] would be the desired range. --- apps/openmw/mwworld/worldimp.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f8c5aa327..ef594ddebf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1247,14 +1247,10 @@ namespace MWWorld if(objRot[0] < -half_pi) objRot[0] = -half_pi; else if(objRot[0] > half_pi) objRot[0] = half_pi; - } - else - { - wrap(objRot[0]); - } - wrap(objRot[1]); - wrap(objRot[2]); + wrap(objRot[1]); + wrap(objRot[2]); + } ptr.getRefData().setPosition(pos); @@ -1269,10 +1265,6 @@ namespace MWWorld rot.rot[1]=osg::DegreesToRadians(y); rot.rot[2]=osg::DegreesToRadians(z); - wrap(rot.rot[0]); - wrap(rot.rot[1]); - wrap(rot.rot[2]); - ptr.getRefData().setLocalRotation(rot); if (ptr.getRefData().getBaseNode() != 0) From 6405049add6c506ea5ca22eec3d0928f1b174e4a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 00:58:29 +0100 Subject: [PATCH 1315/1812] Rotations: move doors via Rotation rather than LocalRotation Now LocalRotation is unneeded, will remove in next commit. --- apps/openmw/mwclass/door.cpp | 7 ++++--- apps/openmw/mwmechanics/obstacle.cpp | 17 ++++++++--------- apps/openmw/mwmechanics/obstacle.hpp | 6 ++---- apps/openmw/mwworld/worldimp.cpp | 19 ++++++++++++------- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 18c381e133..b469dc9e2f 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -159,16 +159,17 @@ namespace MWClass boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); int doorstate = getDoorState(ptr); bool opening = true; + float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2]; if (doorstate == 1) opening = false; - if (doorstate == 0 && ptr.getRefData().getLocalRotation().rot[2] != 0) + if (doorstate == 0 && doorRot != 0) opening = false; if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f); - float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = doorRot/ 3.14159265f * 2.0f; action->setSoundOffset(offset); action->setSound(openSound); } @@ -176,7 +177,7 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = 1.0f - doorRot/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two action->setSoundOffset(offset * 0.5f); diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 7def96bef3..dae5f84963 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -28,15 +28,15 @@ namespace MWMechanics // // Limitation: there can be false detections, and does not test whether the // actor is facing the door. - bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) + bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr) { - if(getNearbyDoor(actor, minSqr, closed)!=MWWorld::Ptr()) + if(getNearbyDoor(actor, minSqr)!=MWWorld::Ptr()) return true; else return false; } - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr) { MWWorld::CellStore *cell = actor.getCell(); @@ -60,12 +60,11 @@ namespace MWMechanics for (; it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr) - if((closed && ref.mData.getLocalRotation().rot[2] == 0) || - (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) - { - return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching - } + if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr + && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) + { + return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching + } } return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 6b442f5a50..98cc4e7a08 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -17,14 +17,12 @@ namespace MWMechanics /// tests actor's proximity to a closed door by default bool proximityToDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED, - bool closed = true); + float minSqr = MIN_DIST_TO_DOOR_SQUARED); /// Returns door pointer within range. No guarentee is given as too which one /** \return Pointer to the door, or NULL if none exists **/ MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED, - bool closed = true); + float minSqr = MIN_DIST_TO_DOOR_SQUARED); class ObstacleCheck { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ef594ddebf..af3470cac7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1402,12 +1402,17 @@ namespace MWWorld } else { - float oldRot = osg::RadiansToDegrees(it->first.getRefData().getLocalRotation().rot[2]); - float diff = duration * 90.f; - float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second == 1 ? 1 : -1)), 90.f); - localRotateObject(it->first, 0, 0, targetRot); + const ESM::Position& objPos = it->first.getRefData().getPosition(); + float oldRot = osg::RadiansToDegrees(objPos.rot[2]); - bool reached = (targetRot == 90.f && it->second) || targetRot == 0.f; + float minRot = osg::RadiansToDegrees(it->first.getCellRef().getPosition().rot[2]); + float maxRot = minRot + 90.f; + + float diff = duration * 90.f; + float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); + rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); + + bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); @@ -1424,7 +1429,7 @@ namespace MWWorld } // we need to undo the rotation - localRotateObject(it->first, 0, 0, oldRot); + rotateObject(it->first, objPos.rot[0], objPos.rot[1], oldRot); reached = false; } } @@ -2103,7 +2108,7 @@ namespace MWWorld switch (state) { case 0: - if (door.getRefData().getLocalRotation().rot[2] == 0) + if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2]) state = 1; // if closed, then open else state = 2; // if open, then close From 666fbba1e044e2a18c9195112636b193734dce6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:08:31 +0100 Subject: [PATCH 1316/1812] Rotations: World::rotateObject takes radians instead of degrees Cuts down on the amount of redundant degree<->radians conversions in the codebase. --- apps/openmw/mwmechanics/character.cpp | 1 - .../mwscript/transformationextensions.cpp | 18 +++++++++--------- apps/openmw/mwworld/scene.cpp | 12 ++++++------ apps/openmw/mwworld/worldimp.cpp | 13 +++++-------- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 129206f519..b5b4721c04 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1816,7 +1816,6 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - rot *= osg::RadiansToDegrees(1.0f); if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) { world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 679a8d2dea..1f47741c38 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -85,12 +85,12 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float angle = runtime[0].mFloat; + Interpreter::Type_Float angle = osg::DegreesToRadians(runtime[0].mFloat); runtime.pop(); - float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); - float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); - float az = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]); + float ax = ptr.getRefData().getPosition().rot[0]; + float ay = ptr.getRefData().getPosition().rot[1]; + float az = ptr.getRefData().getPosition().rot[2]; MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); @@ -337,7 +337,7 @@ namespace MWScript // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,osg::DegreesToRadians(zRot)); ptr.getClass().adjustPosition(ptr, false); } @@ -603,14 +603,14 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + Interpreter::Type_Float rotation = osg::DegreesToRadians(runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); const float *objRot = ptr.getRefData().getPosition().rot; - float ax = osg::RadiansToDegrees(objRot[0]); - float ay = osg::RadiansToDegrees(objRot[1]); - float az = osg::RadiansToDegrees(objRot[2]); + float ax = objRot[0]; + float ay = objRot[1]; + float az = objRot[2]; if (axis == "x") { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 33e2ba17c9..83a7a9f2c1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -419,9 +419,9 @@ namespace MWWorld if (adjustPlayerPos) { world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); - float x = osg::RadiansToDegrees(pos.rot[0]); - float y = osg::RadiansToDegrees(pos.rot[1]); - float z = osg::RadiansToDegrees(pos.rot[2]); + float x = pos.rot[0]; + float y = pos.rot[1]; + float z = pos.rot[2]; world->rotateObject(player, x, y, z); player.getClass().adjustPosition(player, true); @@ -476,9 +476,9 @@ namespace MWWorld MWBase::World *world = MWBase::Environment::get().getWorld(); world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]); - float x = osg::RadiansToDegrees(position.rot[0]); - float y = osg::RadiansToDegrees(position.rot[1]); - float z = osg::RadiansToDegrees(position.rot[2]); + float x = position.rot[0]; + float y = position.rot[1]; + float z = position.rot[2]; world->rotateObject(world->getPlayerPtr(), x, y, z); world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr(), true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index af3470cac7..20a84d6b1a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1317,10 +1317,7 @@ namespace MWWorld void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { - rotateObjectImp(ptr, osg::Vec3f(osg::DegreesToRadians(x), - osg::DegreesToRadians(y), - osg::DegreesToRadians(z)), - adjust); + rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) @@ -1403,12 +1400,12 @@ namespace MWWorld else { const ESM::Position& objPos = it->first.getRefData().getPosition(); - float oldRot = osg::RadiansToDegrees(objPos.rot[2]); + float oldRot = objPos.rot[2]; - float minRot = osg::RadiansToDegrees(it->first.getCellRef().getPosition().rot[2]); - float maxRot = minRot + 90.f; + float minRot = it->first.getCellRef().getPosition().rot[2]; + float maxRot = minRot + osg::DegreesToRadians(90.f); - float diff = duration * 90.f; + float diff = duration * osg::DegreesToRadians(90.f); float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index de9266cb2f..4b3cc5eb76 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,7 +349,7 @@ namespace MWWorld virtual void scaleObject (const Ptr& ptr, float scale); - /// World rotates object, uses degrees + /// World rotates object, uses radians /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); From b4ce73f179f7c2d9465935e7f8efcf3ed614e420 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:16:37 +0100 Subject: [PATCH 1317/1812] Rotations: remove LocalRotation This never existed in vanilla MW in the first place. The reason we got confused was because of a strange behaviour where the order of applying rotations changes as soon as a script touches the object's rotation. --- apps/openmw/mwbase/world.hpp | 2 - apps/openmw/mwscript/miscextensions.cpp | 7 ++- .../mwscript/transformationextensions.cpp | 44 +++++-------------- apps/openmw/mwworld/refdata.cpp | 21 --------- apps/openmw/mwworld/refdata.hpp | 8 ---- apps/openmw/mwworld/scene.cpp | 10 +---- apps/openmw/mwworld/worldimp.cpp | 20 --------- apps/openmw/mwworld/worldimp.hpp | 3 -- components/esm/objectstate.cpp | 7 +-- components/esm/objectstate.hpp | 1 - 10 files changed, 20 insertions(+), 103 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1622e15376..7332a26be1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -270,8 +270,6 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 5aebbc3a9e..63f3ea1901 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -188,7 +188,12 @@ namespace MWScript if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport()) { MWBase::Environment::get().getWorld()->activateDoor(ptr, 0); - MWBase::Environment::get().getWorld()->localRotateObject(ptr, 0, 0, 0); + + float xr = ptr.getCellRef().getPosition().rot[0]; + float yr = ptr.getCellRef().getPosition().rot[1]; + float zr = ptr.getCellRef().getPosition().rot[2]; + + MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); } } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 1f47741c38..f41bb88420 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -92,26 +92,12 @@ namespace MWScript float ay = ptr.getRefData().getPosition().rot[1]; float az = ptr.getRefData().getPosition().rot[2]; - MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); - if (axis == "x") - { - localRot.rot[0] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az); - } else if (axis == "y") - { - localRot.rot[1] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az); - } else if (axis == "z") - { - localRot.rot[2] = 0; - ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle); - } else throw std::runtime_error ("invalid rotation axis: " + axis); } @@ -568,25 +554,19 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + Interpreter::Type_Float rotation = osg::DegreesToRadians(runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float ax = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[0]); - float ay = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[1]); - float az = osg::RadiansToDegrees(ptr.getRefData().getLocalRotation().rot[2]); + float ax = ptr.getRefData().getPosition().rot[0]; + float ay = ptr.getRefData().getPosition().rot[1]; + float az = ptr.getRefData().getPosition().rot[2]; if (axis == "x") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax+rotation,ay,az); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); else if (axis == "y") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay+rotation,az); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); else if (axis == "z") - { - MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,az+rotation); - } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); else throw std::runtime_error ("invalid rotation axis: " + axis); } @@ -641,13 +621,11 @@ namespace MWScript if (!ptr.isInCell()) return; - MWWorld::LocalRotation rot; - rot.rot[0] = 0; - rot.rot[1] = 0; - rot.rot[2] = 0; - ptr.getRefData().setLocalRotation(rot); + float xr = ptr.getCellRef().getPosition().rot[0]; + float yr = ptr.getCellRef().getPosition().rot[1]; + float zr = ptr.getCellRef().getPosition().rot[2]; - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); + MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); dynamic_cast(runtime.getContext()).updatePtr( MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 88a6fa3533..87cbc586f6 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -17,7 +17,6 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; - mLocalRotation = refData.mLocalRotation; mChanged = refData.mChanged; mDeleted = refData.mDeleted; @@ -37,7 +36,6 @@ namespace MWWorld { for (int i=0; i<3; ++i) { - mLocalRotation.rot[i] = 0; mPosition.pos[i] = 0; mPosition.rot[i] = 0; } @@ -49,9 +47,6 @@ namespace MWWorld mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged { - mLocalRotation.rot[0]=0; - mLocalRotation.rot[1]=0; - mLocalRotation.rot[2]=0; } RefData::RefData (const ESM::ObjectState& objectState) @@ -62,8 +57,6 @@ namespace MWWorld mCustomData (0), mChanged(true) // Loading from a savegame -> assume changed { - for (int i=0; i<3; ++i) - mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } RefData::RefData (const RefData& refData) @@ -87,9 +80,6 @@ namespace MWWorld objectState.mEnabled = mEnabled; objectState.mCount = mCount; objectState.mPosition = mPosition; - - for (int i=0; i<3; ++i) - objectState.mLocalRotation[i] = mLocalRotation.rot[i]; } RefData& RefData::operator= (const RefData& refData) @@ -197,17 +187,6 @@ namespace MWWorld return mPosition; } - void RefData::setLocalRotation(const LocalRotation& rot) - { - mChanged = true; - mLocalRotation = rot; - } - - const LocalRotation& RefData::getLocalRotation() - { - return mLocalRotation; - } - void RefData::setCustomData (CustomData *data) { mChanged = true; // We do not currently track CustomData, so assume anything with a CustomData is changed diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 4075f62ce3..13a71ec335 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -21,9 +21,6 @@ namespace ESM namespace MWWorld { - struct LocalRotation{ - float rot[3]; - }; class CustomData; @@ -40,8 +37,6 @@ namespace MWWorld ESM::Position mPosition; - LocalRotation mLocalRotation; - CustomData *mCustomData; void copy (const RefData& refData); @@ -110,9 +105,6 @@ namespace MWWorld void setPosition (const ESM::Position& pos); const ESM::Position& getPosition(); - void setLocalRotation (const LocalRotation& rotation); - const LocalRotation& getLocalRotation(); - void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \a data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 83a7a9f2c1..919eeb18fb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -52,15 +52,7 @@ namespace worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); - float x = ptr.getRefData().getLocalRotation().rot[0]; - float y = ptr.getRefData().getLocalRotation().rot[1]; - float z = ptr.getRefData().getLocalRotation().rot[2]; - - osg::Quat rot(z, osg::Vec3(0,0,-1)); - if (!ptr.getClass().isActor()) - rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0)); - - rendering.rotateObject(ptr, rot * worldRotQuat); + rendering.rotateObject(ptr, worldRotQuat); physics.updateRotation(ptr); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 20a84d6b1a..03f2c1ab8a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1258,21 +1258,6 @@ namespace MWWorld mWorldScene->updateObjectLocalRotation(ptr); } - void World::localRotateObject (const Ptr& ptr, float x, float y, float z) - { - LocalRotation rot = ptr.getRefData().getLocalRotation(); - rot.rot[0]=osg::DegreesToRadians(x); - rot.rot[1]=osg::DegreesToRadians(y); - rot.rot[2]=osg::DegreesToRadians(z); - - ptr.getRefData().setLocalRotation(rot); - - if (ptr.getRefData().getBaseNode() != 0) - { - mWorldScene->updateObjectLocalRotation(ptr); - } - } - void World::adjustPosition(const Ptr &ptr, bool force) { ESM::Position pos (ptr.getRefData().getPosition()); @@ -1829,11 +1814,6 @@ namespace MWWorld object.getClass().copyToCell(object, *cell, pos); // Reset some position values that could be uninitialized if this item came from a container - LocalRotation localRotation; - localRotation.rot[0] = 0; - localRotation.rot[1] = 0; - localRotation.rot[2] = 0; - dropped.getRefData().setLocalRotation(localRotation); dropped.getCellRef().setPosition(pos); dropped.getCellRef().unsetRefNum(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4b3cc5eb76..9ff3e7d1ff 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -353,9 +353,6 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - /// Local rotates object, uses degrees - virtual void localRotateObject (const Ptr& ptr, float x, float y, float z); - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 62aa0452a8..4fd4245c7c 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -23,7 +23,8 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mPosition, "POS_", 24); - esm.getHNOT (mLocalRotation, "LROT", 12); + if (esm.isNextSub("LROT")) + esm.skipHSub(); // local rotation, no longer used // obsolete int unused; @@ -51,10 +52,7 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("COUN", mCount); if (!inInventory) - { esm.writeHNT ("POS_", mPosition, 24); - esm.writeHNT ("LROT", mLocalRotation, 12); - } if (!mHasCustomState) esm.writeHNT ("HCUS", false); @@ -70,7 +68,6 @@ void ESM::ObjectState::blank() { mPosition.pos[i] = 0; mPosition.rot[i] = 0; - mLocalRotation[i] = 0; } mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 674bcb8fc1..215cb74baa 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -24,7 +24,6 @@ namespace ESM unsigned char mEnabled; int mCount; ESM::Position mPosition; - float mLocalRotation[3]; // Is there any class-specific state following the ObjectState bool mHasCustomState; From 3647af8d731fc15c4197ed5528b6c2fa180bd13d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 01:44:00 +0100 Subject: [PATCH 1318/1812] Rotations: use different rotation order when object is rotated via script (Fixes #2062) --- apps/openmw/mwworld/scene.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/scene.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 919eeb18fb..1ba17a9675 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -42,15 +42,22 @@ namespace rendering.addWaterRippleEmitter(ptr); } - void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, - MWRender::RenderingManager& rendering) + void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, + MWRender::RenderingManager& rendering, bool inverseRotationOrder) { if (ptr.getRefData().getBaseNode() != NULL) { osg::Quat worldRotQuat(ptr.getRefData().getPosition().rot[2], osg::Vec3(0,0,-1)); if (!ptr.getClass().isActor()) - worldRotQuat = worldRotQuat * osg::Quat(ptr.getRefData().getPosition().rot[1], osg::Vec3(0,-1,0)) * - osg::Quat(ptr.getRefData().getPosition().rot[0], osg::Vec3(-1,0,0)); + { + float xr = ptr.getRefData().getPosition().rot[0]; + float yr = ptr.getRefData().getPosition().rot[1]; + if (!inverseRotationOrder) + worldRotQuat = worldRotQuat * osg::Quat(yr, osg::Vec3(0,-1,0)) * + osg::Quat(xr, osg::Vec3(-1,0,0)); + else + worldRotQuat = osg::Quat(xr, osg::Vec3(-1,0,0)) * osg::Quat(yr, osg::Vec3(0,-1,0)) * worldRotQuat; + } rendering.rotateObject(ptr, worldRotQuat); physics.updateRotation(ptr); @@ -106,7 +113,7 @@ namespace try { addObject(ptr, mPhysics, mRendering); - updateObjectLocalRotation(ptr, mPhysics, mRendering); + updateObjectRotation(ptr, mPhysics, mRendering, false); updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } @@ -127,9 +134,9 @@ namespace namespace MWWorld { - void Scene::updateObjectLocalRotation (const Ptr& ptr) + void Scene::updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder) { - ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); + ::updateObjectRotation(ptr, *mPhysics, mRendering, inverseRotationOrder); } void Scene::updateObjectScale(const Ptr &ptr) @@ -548,7 +555,7 @@ namespace MWWorld try { addObject(ptr, *mPhysics, mRendering); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + updateObjectRotation(ptr, false); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } catch (std::exception& e) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ca6ed83b91..439c8d72c3 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -107,7 +107,7 @@ namespace MWWorld void removeObjectFromScene (const Ptr& ptr); ///< Remove an object from the scene, but not from the world model. - void updateObjectLocalRotation (const Ptr& ptr); + void updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder); void updateObjectScale(const Ptr& ptr); bool isCellActive(const CellStore &cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 03f2c1ab8a..b800db4a2a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1255,7 +1255,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) - mWorldScene->updateObjectLocalRotation(ptr); + mWorldScene->updateObjectRotation(ptr, true); } void World::adjustPosition(const Ptr &ptr, bool force) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9ff3e7d1ff..9f49281208 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -350,6 +350,8 @@ namespace MWWorld virtual void scaleObject (const Ptr& ptr, float scale); /// World rotates object, uses radians + /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This + /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); From 90b6fa5ef1f16b5a5744216115268ae3b5a2a955 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 21:19:50 +0100 Subject: [PATCH 1319/1812] PlaceItem, PlaceItemCell angle should be treated as degrees (Fixes #3007) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f41bb88420..b2b21a5323 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -402,7 +402,7 @@ namespace MWScript runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float zRot = runtime[0].mFloat; + Interpreter::Type_Float zRotDegrees = runtime[0].mFloat; runtime.pop(); MWWorld::CellStore* store = 0; @@ -429,7 +429,7 @@ namespace MWScript pos.pos[1] = y; pos.pos[2] = z; pos.rot[0] = pos.rot[1] = 0; - pos.rot[2] = zRot; + pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); @@ -454,7 +454,7 @@ namespace MWScript runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float zRot = runtime[0].mFloat; + Interpreter::Type_Float zRotDegrees = runtime[0].mFloat; runtime.pop(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -473,7 +473,7 @@ namespace MWScript pos.pos[1] = y; pos.pos[2] = z; pos.rot[0] = pos.rot[1] = 0; - pos.rot[2] = zRot; + pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); From 9e3eb8291fe5bf0e380f057809794d589ee5be5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 02:09:00 +0100 Subject: [PATCH 1320/1812] Rotations: fix the rotation order for doors --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b800db4a2a..f82392662c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1393,6 +1393,8 @@ namespace MWWorld float diff = duration * osg::DegreesToRadians(90.f); float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot); rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot); + // the rotation order we want to use + mWorldScene->updateObjectRotation(it->first, false); bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; From 19cd987208a18ae098327699d3828404b0f52e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 14:32:39 +0100 Subject: [PATCH 1321/1812] Fix Ptr updates in PositionCell This was not the proper way to get the updated Ptr, it will only work for the player which isn't owned by any cell. For other objects, moving between cells makes the object owned by that cell and thus the getBase() pointer will change. --- apps/openmw/mwscript/transformationextensions.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index b2b21a5323..35e61ab56f 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -312,8 +312,8 @@ namespace MWScript } if(store) { - MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), store); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); + dynamic_cast(runtime.getContext()).updatePtr(ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); @@ -363,8 +363,7 @@ namespace MWScript if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), cell); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); } else { From 01f4b8a182a1722df661b933cd39001b7e10b837 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Nov 2015 15:05:17 +0100 Subject: [PATCH 1322/1812] added scene tooltips system (tag based) --- apps/opencs/model/settings/usersettings.cpp | 14 ++++++ apps/opencs/view/render/tagbase.cpp | 5 ++ apps/opencs/view/render/tagbase.hpp | 5 ++ apps/opencs/view/render/worldspacewidget.cpp | 51 +++++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 10 +++- 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index e8568cac10..8bf24ae343 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -426,6 +426,20 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() dragShiftFactor->setRange (0.001, 100.0); } + declareSection ("tooltips", "Tooltips"); + { + Setting *scene = createSetting (Type_CheckBox, "scene", "Show Tooltips in 3D scenes"); + scene->setDefaultValue ("true"); + + Setting *sceneHideBasic = createSetting (Type_CheckBox, "scene-hide-basic", "Hide basic 3D scenes tooltips"); + sceneHideBasic->setDefaultValue ("false"); + + Setting *sceneDelay = createSetting (Type_SpinBox, "scene-delay", + "Tooltip delay in milliseconds"); + sceneDelay->setDefaultValue (500); + sceneDelay->setRange (1, 10000); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/view/render/tagbase.cpp b/apps/opencs/view/render/tagbase.cpp index af9a376243..79412c1321 100644 --- a/apps/opencs/view/render/tagbase.cpp +++ b/apps/opencs/view/render/tagbase.cpp @@ -7,3 +7,8 @@ CSVRender::Elements CSVRender::TagBase::getElement() const { return mElement; } + +QString CSVRender::TagBase::getToolTip (bool hideBasics) const +{ + return ""; +} diff --git a/apps/opencs/view/render/tagbase.hpp b/apps/opencs/view/render/tagbase.hpp index 874b856c63..9f169c3b1a 100644 --- a/apps/opencs/view/render/tagbase.hpp +++ b/apps/opencs/view/render/tagbase.hpp @@ -3,6 +3,8 @@ #include +#include + #include "elements.hpp" namespace CSVRender @@ -16,6 +18,9 @@ namespace CSVRender TagBase (Elements element); Elements getElement() const; + + virtual QString getToolTip (bool hideBasics) const; + }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e76582b945..0deb498405 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,8 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false) + mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), + mToolTipPos (-1, -1) { setAcceptDrops(true); @@ -85,6 +87,12 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); + + mShowToolTips = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene") == "true"; + mToolTipDelay = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-delay").toInt(); + + mToolTipDelayTimer.setSingleShot (true); + connect (&mToolTipDelayTimer, SIGNAL (timeout()), this, SLOT (showToolTip())); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -294,6 +302,10 @@ void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const mDragWheelFactor = value.at (0).toDouble(); else if (name=="scene-input/drag-shift-factor") mDragShiftFactor = value.at (0).toDouble(); + else if (name=="tooltips/scene-delay") + mToolTipDelay = value.at (0).toInt(); + else if (name=="tooltips/scene") + mShowToolTips = value.at (0)=="true"; else dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); } @@ -368,11 +380,11 @@ bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const return false; } -osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (QMouseEvent *event) +osg::ref_ptr CSVRender::WorldspaceWidget::mousePick (const QPoint& localPos) { // (0,0) is considered the lower left corner of an OpenGL window - int x = event->x(); - int y = height() - event->y(); + int x = localPos.x(); + int y = height() - localPos.y(); osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); @@ -494,6 +506,21 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) mDragging = false; } +void CSVRender::WorldspaceWidget::showToolTip() +{ + if (mShowToolTips) + { + QPoint pos = QCursor::pos(); + + if (osg::ref_ptr tag = mousePick (mapFromGlobal (pos))) + { + bool hideBasics = + CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-hide-basic")=="true"; + QToolTip::showText (pos, tag->getToolTip (hideBasics), this); + } + } +} + void CSVRender::WorldspaceWidget::elementSelectionChanged() { setVisibilityMask (getVisibilityMask()); @@ -509,13 +536,23 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if (!mDragging) { - if (mDragMode=="p-navi" || mDragMode=="s-navi") + if (mDragMode.empty()) + { + if (event->globalPos()!=mToolTipPos) + { + mToolTipPos = event->globalPos(); + + if (mShowToolTips) + mToolTipDelayTimer.start (mToolTipDelay); + } + } + else if (mDragMode=="p-navi" || mDragMode=="s-navi") { } else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select") { - osg::ref_ptr tag = mousePick (event); + osg::ref_ptr tag = mousePick (event->pos()); EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -595,7 +632,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) else if (button=="p-edit" || button=="s-edit" || button=="p-select" || button=="s-select") { - osg::ref_ptr tag = mousePick (event); + osg::ref_ptr tag = mousePick (event->pos()); handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier); } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index c2d61e75be..0b5ae25233 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -5,6 +5,8 @@ #include +#include + #include "../../model/doc/document.hpp" #include "../../model/world/tablemimedata.hpp" @@ -47,6 +49,10 @@ namespace CSVRender double mDragFactor; double mDragWheelFactor; double mDragShiftFactor; + QTimer mToolTipDelayTimer; + QPoint mToolTipPos; + bool mShowToolTips; + int mToolTipDelay; public: @@ -147,7 +153,7 @@ namespace CSVRender /// \return Is \a key a button mapping setting? (ignored otherwise) bool storeMappingSetting (const QString& key, const QString& value); - osg::ref_ptr mousePick (QMouseEvent *event); + osg::ref_ptr mousePick (const QPoint& localPos); std::string mapButton (QMouseEvent *event); @@ -179,6 +185,8 @@ namespace CSVRender void editModeChanged (const std::string& id); + void showToolTip(); + protected slots: void elementSelectionChanged(); From 8b01f1f6fbcfcc4aaffe4667fa6aa98b49a9eba0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Nov 2015 15:09:43 +0100 Subject: [PATCH 1323/1812] added instance tooltips --- apps/opencs/view/render/object.cpp | 5 +++++ apps/opencs/view/render/object.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ac96cb2835..c295a023a8 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -42,6 +42,11 @@ CSVRender::ObjectTag::ObjectTag (Object* object) : TagBase (Element_Reference), mObject (object) {} +QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const +{ + return QString::fromUtf8 (mObject->getReferenceableId().c_str()); +} + void CSVRender::Object::clear() { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 0858a2edb2..e7638e7a99 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -46,6 +46,8 @@ namespace CSVRender ObjectTag (Object* object); Object* mObject; + + virtual QString getToolTip (bool hideBasics) const; }; From 8d2990cc03d55a8768904a56403af63f13785714 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 08:45:34 +0100 Subject: [PATCH 1324/1812] add support for ffmpeg29 thanks to Andreas Cadhalpun; https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=803848 --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 33 ++++++++------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index f143088e81..fb392bb4de 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -90,16 +90,6 @@ void PacketQueue::put(AVPacket *pkt) pkt1->pkt = *pkt; pkt1->next = NULL; - if(pkt->data != flush_pkt.data && pkt1->pkt.destruct == NULL) - { - if(av_dup_packet(&pkt1->pkt) < 0) - { - av_free(pkt1); - throw std::runtime_error("Failed to duplicate packet"); - } - av_free_packet(pkt); - } - this->mutex.lock (); if(!last_pkt) @@ -313,7 +303,7 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) int w = (*this->video_st)->codec->width; int h = (*this->video_st)->codec->height; this->sws_context = sws_getContext(w, h, (*this->video_st)->codec->pix_fmt, - w, h, PIX_FMT_RGBA, SWS_BICUBIC, + w, h, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); if(this->sws_context == NULL) throw std::runtime_error("Cannot initialize the conversion context!\n"); @@ -354,24 +344,28 @@ double VideoState::synchronize_video(AVFrame *src_frame, double pts) return pts; } - +static void our_free_buffer(void *opaque, uint8_t *data); /* These are called whenever we allocate a frame * buffer. We use this to store the global_pts in * a frame at the time it is allocated. */ static int64_t global_video_pkt_pts = AV_NOPTS_VALUE; -static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) +static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic, int flags) { - int ret = avcodec_default_get_buffer(c, pic); + AVBufferRef *ref; + int ret = avcodec_default_get_buffer2(c, pic, flags); int64_t *pts = (int64_t*)av_malloc(sizeof(int64_t)); *pts = global_video_pkt_pts; pic->opaque = pts; + ref = av_buffer_create((uint8_t *)pic->opaque, sizeof(int64_t), our_free_buffer, pic->buf[0], flags); + pic->buf[0] = ref; return ret; } -static void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) +static void our_free_buffer(void *opaque, uint8_t *data) { - if(pic) av_freep(&pic->opaque); - avcodec_default_release_buffer(c, pic); + AVBufferRef *ref = (AVBufferRef *)opaque; + av_buffer_unref(&ref); + av_free(data); } @@ -384,7 +378,7 @@ void VideoState::video_thread_loop(VideoState *self) pFrame = av_frame_alloc(); self->rgbaFrame = av_frame_alloc(); - avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); + avpicture_alloc((AVPicture*)self->rgbaFrame, AV_PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); while(self->videoq.get(packet, self) >= 0) { @@ -589,8 +583,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) case AVMEDIA_TYPE_VIDEO: this->video_st = pFormatCtx->streams + stream_index; - codecCtx->get_buffer = our_get_buffer; - codecCtx->release_buffer = our_release_buffer; + codecCtx->get_buffer2 = our_get_buffer; this->video_thread = boost::thread(video_thread_loop, this); break; From bdfd1c217b926a4f89dac064fe449d7939ef5a29 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 09:37:27 +0100 Subject: [PATCH 1325/1812] try using precise ffmpeg library instead of libav --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 2efb6e2bbf..37f98c1418 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev +sudo apt-get install -qq libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 1e8eddc5b47deb32752871bbbaffa06cf6cc547e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 09:45:01 +0100 Subject: [PATCH 1326/1812] another try --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 37f98c1418..9edcf55cce 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev +sudo apt-get install -qq ffmpeg-real ffmpeg-opti libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 9d5e7b34c6e1f934bbf0851c6005a0c749f0645e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 11 Nov 2015 23:18:51 +0100 Subject: [PATCH 1327/1812] use ffmpeg from our repo --- CI/before_install.linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 9edcf55cce..6e288aa149 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -14,7 +14,7 @@ echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev -sudo apt-get install -qq ffmpeg-real ffmpeg-opti libavcodec-ffmpeg-opti-dev libavformat-ffmpeg-opti-dev libavutil-ffmpeg-opti-dev libswscale-ffmpeg-opti-dev libswresample-ffmpeg-opti-dev +sudo apt-get install -qq ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi From 39f89f967b16d4368130a95a2b33aa2a04cbe4b7 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 12 Nov 2015 12:44:40 +0100 Subject: [PATCH 1328/1812] from kcat: We can't simply get rid of this, otherwise it may break for certain kinds of packets. --- extern/osg-ffmpeg-videoplayer/videostate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extern/osg-ffmpeg-videoplayer/videostate.cpp b/extern/osg-ffmpeg-videoplayer/videostate.cpp index fb392bb4de..3c9279ea25 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.cpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.cpp @@ -85,6 +85,9 @@ void VideoState::setAudioFactory(MovieAudioFactory *factory) void PacketQueue::put(AVPacket *pkt) { AVPacketList *pkt1; + if(pkt != &flush_pkt && !pkt->buf && av_dup_packet(pkt) < 0) + throw std::runtime_error("Failed to duplicate packet"); + pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); if(!pkt1) throw std::bad_alloc(); pkt1->pkt = *pkt; From 3ea3d07d4416ebc3f1f4400bc54e89a5f05d2349 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 12 Nov 2015 16:38:54 +0100 Subject: [PATCH 1329/1812] really purge libav --- CMakeLists.txt | 15 +-- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 10 -- apps/openmw/mwsound/ffmpeg_decoder.hpp | 6 - apps/openmw/mwsound/libavwrapper.cpp | 108 ----------------- extern/osg-ffmpeg-videoplayer/CMakeLists.txt | 1 - .../osg-ffmpeg-videoplayer/audiodecoder.cpp | 12 -- .../osg-ffmpeg-videoplayer/libavwrapper.cpp | 110 ------------------ 8 files changed, 3 insertions(+), 261 deletions(-) delete mode 100644 apps/openmw/mwsound/libavwrapper.cpp delete mode 100644 extern/osg-ffmpeg-videoplayer/libavwrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d33521e8ba..58b88f6219 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,22 +107,11 @@ unset(FFMPEG_LIBRARIES CACHE) find_package(FFmpeg REQUIRED) -set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY}) +set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY} ${SWRESAMPLE_LIBRARIES}) -if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) +if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND OR NOT SWRESAMPLE_FOUND) message(FATAL_ERROR "FFmpeg component required, but not found!") endif() -set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) -if( SWRESAMPLE_FOUND ) - add_definitions(-DHAVE_LIBSWRESAMPLE) - set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) -else() - if( AVRESAMPLE_FOUND ) - set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) - else() - message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") - endif() -endif() # Required for building the FFmpeg headers add_definitions(-D__STDC_CONSTANT_MACROS) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index fa05576f5d..887eedebbf 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness movieaudiofactory ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 6a586e81d5..66b7e09e3a 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -6,16 +6,6 @@ #include #include -extern "C" { -#ifndef HAVE_LIBSWRESAMPLE -// FIXME: remove this section once libswresample is packaged for Debian -int swr_init(AVAudioResampleContext *avr); -void swr_free(AVAudioResampleContext **avr); -int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples); -AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l); -#endif -} - #include namespace MWSound diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index da8e58964b..b27e60c9f5 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -22,13 +22,7 @@ extern "C" // From version 54.56 binkaudio encoding format changed from S16 to FLTP. See: // https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d // http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 -#ifdef HAVE_LIBSWRESAMPLE #include -#else -#include -#include -#define SwrContext AVAudioResampleContext -#endif } #include diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp deleted file mode 100644 index 40be671760..0000000000 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef HAVE_LIBSWRESAMPLE -extern "C" -{ -#include - -#include -#include -// From libavutil version 52.2.0 and onward the declaration of -// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to -// libavutil/channel_layout.h -#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) - #include -#endif -#include -#include - -/* FIXME: delete this file once libswresample is packaged for Debian */ - -int swr_init(AVAudioResampleContext *avr) { return 1; } - -void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); } - -int swr_convert( - AVAudioResampleContext *avr, - uint8_t** output, - int out_samples, - const uint8_t** input, - int in_samples) -{ - // FIXME: potential performance hit - int out_plane_size = 0; - int in_plane_size = 0; - return avresample_convert(avr, output, out_plane_size, out_samples, - (uint8_t **)input, in_plane_size, in_samples); -} - -AVAudioResampleContext * swr_alloc_set_opts( - AVAudioResampleContext *avr, - int64_t out_ch_layout, - AVSampleFormat out_fmt, - int out_rate, - int64_t in_ch_layout, - AVSampleFormat in_fmt, - int in_rate, - int o, - void* l) -{ - avr = avresample_alloc_context(); - if(!avr) - return 0; - - int res; - res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n"); - return 0; - } - - - if(avresample_open(avr) < 0) - { - av_log(avr, AV_LOG_ERROR, "Error opening context\n"); - return 0; - } - else - return avr; -} - -} -#endif diff --git a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt index 614a0804cf..6009f69de5 100644 --- a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt @@ -6,7 +6,6 @@ set(OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES videoplayer.cpp videostate.cpp videodefs.hpp - libavwrapper.cpp audiodecoder.cpp audiofactory.hpp ) diff --git a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp index 77e6b4b6c0..f095d1617a 100644 --- a/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/osg-ffmpeg-videoplayer/audiodecoder.cpp @@ -6,24 +6,12 @@ extern "C" #include - #ifdef HAVE_LIBSWRESAMPLE #include - #else - // FIXME: remove this section once libswresample is packaged for Debian - #include - #include - #define SwrContext AVAudioResampleContext - int swr_init(AVAudioResampleContext *avr); - void swr_free(AVAudioResampleContext **avr); - int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int in_samples); - AVAudioResampleContext * swr_alloc_set_opts( AVAudioResampleContext *avr, int64_t out_ch_layout, AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, AVSampleFormat in_fmt, int in_rate, int o, void* l); - #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) #define av_frame_alloc avcodec_alloc_frame #endif - } #include "videostate.hpp" diff --git a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp b/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp deleted file mode 100644 index 26a7b63706..0000000000 --- a/extern/osg-ffmpeg-videoplayer/libavwrapper.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// This file is a wrapper around the libavresample library (the API-incompatible swresample replacement in the libav fork of ffmpeg), to make it look like swresample to the user. - -#ifndef HAVE_LIBSWRESAMPLE -extern "C" -{ -#include - -#include -#include -// From libavutil version 52.2.0 and onward the declaration of -// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to -// libavutil/channel_layout.h -#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) - #include -#endif -#include -#include - -/* FIXME: delete this file once libswresample is packaged for Debian */ - -int swr_init(AVAudioResampleContext *avr) { return 1; } - -void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); } - -int swr_convert( - AVAudioResampleContext *avr, - uint8_t** output, - int out_samples, - const uint8_t** input, - int in_samples) -{ - // FIXME: potential performance hit - int out_plane_size = 0; - int in_plane_size = 0; - return avresample_convert(avr, output, out_plane_size, out_samples, - (uint8_t **)input, in_plane_size, in_samples); -} - -AVAudioResampleContext * swr_alloc_set_opts( - AVAudioResampleContext *avr, - int64_t out_ch_layout, - AVSampleFormat out_fmt, - int out_rate, - int64_t in_ch_layout, - AVSampleFormat in_fmt, - int in_rate, - int o, - void* l) -{ - avr = avresample_alloc_context(); - if(!avr) - return 0; - - int res; - res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res); - return 0; - } - res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - if(res < 0) - { - av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n"); - return 0; - } - - - if(avresample_open(avr) < 0) - { - av_log(avr, AV_LOG_ERROR, "Error opening context\n"); - return 0; - } - else - return avr; -} - -} -#endif From af7b5e636e173a12c9b5799cc59d8f4b17fdb678 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 30 Sep 2015 10:30:50 +0200 Subject: [PATCH 1330/1812] improves InterpreterContext::updatePtr This checks the update is really on the right pointer. It fixes the boat disappearing in "fishing academy", and it allows scripts linked to objects not to loose their default reference when using the object-> notation on another object. --- apps/openmw/mwscript/interpretercontext.cpp | 4 ++-- apps/openmw/mwscript/interpretercontext.hpp | 2 +- .../mwscript/transformationextensions.cpp | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b0d4d3f2df..c70eb6cf8f 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -601,9 +601,9 @@ namespace MWScript return mTargetId; } - void InterpreterContext::updatePtr(const MWWorld::Ptr& updated) + void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated) { - if (!mReference.isEmpty()) + if (!mReference.isEmpty() && base == mReference) mReference = updated; } } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index d3841befdf..3c43444cc7 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -167,7 +167,7 @@ namespace MWScript MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) - void updatePtr(const MWWorld::Ptr& updated); + void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated); ///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell. virtual std::string getTargetId() const; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 35e61ab56f..f650352262 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -186,7 +186,7 @@ namespace MWScript runtime.push(ptr.getRefData().getPosition().pos[2]); } else - throw std::runtime_error ("invalid axis: " + axis); + throw std::runtime_error ("invalid axis: " + axis); } }; @@ -232,7 +232,7 @@ namespace MWScript else throw std::runtime_error ("invalid axis: " + axis); - dynamic_cast(runtime.getContext()).updatePtr(updated); + dynamic_cast(runtime.getContext()).updatePtr(ptr,updated); } }; @@ -300,7 +300,7 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); int cx,cy; MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -312,9 +312,9 @@ namespace MWScript } if(store) { + MWWorld::Ptr base = ptr; ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -360,6 +360,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. + MWWorld::Ptr base = ptr; if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -369,7 +370,7 @@ namespace MWScript { ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -626,7 +627,7 @@ namespace MWScript MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); - dynamic_cast(runtime.getContext()).updatePtr( + dynamic_cast(runtime.getContext()).updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2])); @@ -744,8 +745,8 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodePositionExplicit,new OpPosition); interpreter.installSegment5(Compiler::Transformation::opcodePositionCell,new OpPositionCell); interpreter.installSegment5(Compiler::Transformation::opcodePositionCellExplicit,new OpPositionCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtPc,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMe,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMeExplicit,new OpPlaceAt); From 9897400d9702117183319b52959d354e459ef598 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:03:24 +0100 Subject: [PATCH 1331/1812] Restore the previous key focus widget after playing video --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a7c3a19576..114b8223d0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1743,6 +1743,7 @@ namespace MWGui MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); + MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); setKeyFocusWidget(mVideoWidget); mVideoBackground->setVisible(true); @@ -1770,6 +1771,8 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->resumeSounds(); + setKeyFocusWidget(oldKeyFocus); + setCursorVisible(cursorWasVisible); // Restore normal rendering From 626281977eb2d0bc5c3549ce0409b0b5e4ed1cca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:40:31 +0100 Subject: [PATCH 1332/1812] Read NiLODNode (Bug #3008) --- components/nif/niffile.cpp | 2 ++ components/nif/node.hpp | 36 ++++++++++++++++++++++++++++++++++++ components/nif/record.hpp | 2 ++ 3 files changed, 40 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1db9c8ccf7..1387a97b0e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -48,6 +48,8 @@ static std::map makeFactory() { std::map newFactory; newFactory.insert(makeEntry("NiNode", &construct , RC_NiNode )); + newFactory.insert(makeEntry("NiSwitchNode", &construct , RC_NiSwitchNode )); + newFactory.insert(makeEntry("NiLODNode", &construct , RC_NiLODNode )); newFactory.insert(makeEntry("AvoidNode", &construct , RC_AvoidNode )); newFactory.insert(makeEntry("NiBSParticleNode", &construct , RC_NiBSParticleNode )); newFactory.insert(makeEntry("NiBSAnimationNode", &construct , RC_NiBSAnimationNode )); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 943ddcc661..326e9802fd 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -250,5 +250,41 @@ struct NiRotatingParticles : Node } }; +// A node used as the base to switch between child nodes, such as for LOD levels. +struct NiSwitchNode : public NiNode +{ + void read(NIFStream *nif) + { + NiNode::read(nif); + nif->getInt(); // unknown + } +}; + +struct NiLODNode : public NiSwitchNode +{ + osg::Vec3f lodCenter; + + struct LODRange + { + float minRange; + float maxRange; + }; + std::vector lodLevels; + + void read(NIFStream *nif) + { + NiSwitchNode::read(nif); + lodCenter = nif->getVector3(); + unsigned int numLodLevels = nif->getUInt(); + for (unsigned int i=0; igetFloat(); + r.maxRange = nif->getFloat(); + lodLevels.push_back(r); + } + } +}; + } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 1022802cc4..bcbdba1154 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -36,6 +36,8 @@ enum RecordType { RC_MISSING = 0, RC_NiNode, + RC_NiSwitchNode, + RC_NiLODNode, RC_NiBillboardNode, RC_AvoidNode, RC_NiTriShape, From 0965a9059d76bac29af26a091e7c7ac0012ec39c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:52:36 +0100 Subject: [PATCH 1333/1812] Handle NiLODNode using osg::LOD (Fixes #3008) --- components/nifosg/nifloader.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3e7f47b6fa..73b72811a5 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // resource #include @@ -424,6 +425,20 @@ namespace NifOsg // Need to make sure that won't break transparency sorting. Check what the original engine is doing? } + osg::ref_ptr handleLodNode(const Nif::NiLODNode* niLodNode) + { + osg::ref_ptr lod (new osg::LOD); + lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER); + lod->setCenter(niLodNode->lodCenter); + for (unsigned int i=0; ilodLevels.size(); ++i) + { + const Nif::NiLODNode::LODRange& range = niLodNode->lodLevels[i]; + lod->setRange(i, range.minRange, range.maxRange); + } + lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); + return lod; + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -555,6 +570,15 @@ namespace NifOsg // Optimization pass optimize(nifNode, node, skipMeshes); + + if (nifNode->recType == Nif::RC_NiLODNode) + { + const Nif::NiLODNode* niLodNode = static_cast(nifNode); + osg::ref_ptr lod = handleLodNode(niLodNode); + node->addChild(lod); // unsure if LOD should be above or below this node's transform + node = lod; + } + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { From 8cd41f0ed4809e960e36733eee481b180be25a2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:05:44 +0100 Subject: [PATCH 1334/1812] Increase the ray distance for dropObjectOnGround (Fixes #3010) --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f82392662c..7e78bef8c6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1870,7 +1870,7 @@ namespace MWWorld orig.z() += 20; osg::Vec3f dir (0, 0, -1); - float len = 100.0; + float len = 1000000.0; MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) From ba211ad9ad43e69f1bb19b00bb0de5ae446750af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:27:34 +0100 Subject: [PATCH 1335/1812] Read NiPointLight (Fixes #3011) --- components/nif/effect.cpp | 27 ++++++++++++-------------- components/nif/effect.hpp | 39 ++++++++++++++++++++++++-------------- components/nif/niffile.cpp | 1 + 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 41dcb09de9..78feeea948 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -5,29 +5,19 @@ namespace Nif { -void NiLight::SLight::read(NIFStream *nif) +void NiLight::read(NIFStream *nif) { + NiDynamicEffect::read(nif); + dimmer = nif->getFloat(); ambient = nif->getVector3(); diffuse = nif->getVector3(); specular = nif->getVector3(); } -void NiLight::read(NIFStream *nif) -{ - Effect::read(nif); - - nif->getInt(); // 1 - nif->getInt(); // 1? - light.read(nif); -} - void NiTextureEffect::read(NIFStream *nif) { - Effect::read(nif); - - int tmp = nif->getInt(); - if(tmp) nif->getInt(); // always 1? + NiDynamicEffect::read(nif); /* 3 x Vector4 = [1,0,0,0] @@ -52,10 +42,17 @@ void NiTextureEffect::read(NIFStream *nif) void NiTextureEffect::post(NIFFile *nif) { - Effect::post(nif); + NiDynamicEffect::post(nif); texture.post(nif); } +void NiPointLight::read(NIFStream *nif) +{ + NiLight::read(nif); + constantAttenuation = nif->getFloat(); + linearAttenuation = nif->getFloat(); + quadraticAttenuation = nif->getFloat(); +} } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index fae1cd7f58..75de0a9abb 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -29,27 +29,38 @@ namespace Nif { -typedef Node Effect; - -// Used for NiAmbientLight and NiDirectionalLight. Might also work for -// NiPointLight and NiSpotLight? -struct NiLight : Effect +struct NiDynamicEffect : public Node { - struct SLight + void read(NIFStream *nif) { - float dimmer; - osg::Vec3f ambient; - osg::Vec3f diffuse; - osg::Vec3f specular; + Node::read(nif); + unsigned int numAffectedNodes = nif->getUInt(); + for (unsigned int i=0; igetUInt(); // ref to another Node + } +}; - void read(NIFStream *nif); - }; - SLight light; +// Used as base for NiAmbientLight, NiDirectionalLight, NiPointLight and NiSpotLight. +struct NiLight : NiDynamicEffect +{ + float dimmer; + osg::Vec3f ambient; + osg::Vec3f diffuse; + osg::Vec3f specular; void read(NIFStream *nif); }; -struct NiTextureEffect : Effect +struct NiPointLight : public NiLight +{ + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + + void read(NIFStream *nif); +}; + +struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1387a97b0e..ab0af8f99c 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -82,6 +82,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiFlipController", &construct , RC_NiFlipController )); newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From a29d1ace2b2beeeda58cc523793f73e401ec1afd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:45:12 +0100 Subject: [PATCH 1336/1812] Read NiSpotLight --- components/nif/effect.cpp | 8 ++++++++ components/nif/effect.hpp | 7 +++++++ components/nif/niffile.cpp | 1 + 3 files changed, 16 insertions(+) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 78feeea948..79cd104312 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -55,4 +55,12 @@ void NiPointLight::read(NIFStream *nif) quadraticAttenuation = nif->getFloat(); } +void NiSpotLight::read(NIFStream *nif) +{ + NiPointLight::read(nif); + + cutoff = nif->getFloat(); + exponent = nif->getFloat(); +} + } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 75de0a9abb..02647e4448 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -60,6 +60,13 @@ struct NiPointLight : public NiLight void read(NIFStream *nif); }; +struct NiSpotLight : public NiPointLight +{ + float cutoff; + float exponent; + void read(NIFStream *nif); +}; + struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index ab0af8f99c..ccfcdfc73c 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -83,6 +83,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiSpotLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From 7c16630874230d886aa1d94f620c8b332676d93a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 00:21:30 +0100 Subject: [PATCH 1337/1812] NifOsg::Emitter: ignore psToWorld scale Seems wrong to me, but MW appears to do it that way. Without this fix, the light_de_candle_08_64 from http://www.nexusmods.com/morrowind/mods/41654/ has flame particles in the wrong spot. --- components/nifosg/particle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 68f3de8aa1..44d062d8ba 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -264,7 +264,9 @@ void Emitter::emitParticles(double dt) osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { - const osg::Matrix psToWorld = worldMats[0]; + osg::Matrix psToWorld = worldMats[0]; + // ignore scales in particlesystem world matrix. this seems wrong, but have to do so for MW compatibility. + psToWorld.orthoNormalize(psToWorld); worldToPs = osg::Matrix::inverse(psToWorld); } From 63ee37d91462282267eddbe97336e8e255dc2919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Nov 2015 11:39:57 +0100 Subject: [PATCH 1338/1812] added 3D scene tooltips --- apps/opencs/view/render/cellarrow.cpp | 27 +++++++++++++++++++++++++++ apps/opencs/view/render/cellarrow.hpp | 2 ++ 2 files changed, 29 insertions(+) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index fce5ffda5c..1356aa0fbd 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -18,6 +18,33 @@ CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const return mArrow; } +QString CSVRender::CellArrowTag::getToolTip (bool hideBasics) const +{ + QString text ("Direction: "); + + switch (mArrow->getDirection()) + { + case CellArrow::Direction_North: text += "North"; break; + case CellArrow::Direction_West: text += "West"; break; + case CellArrow::Direction_South: text += "South"; break; + case CellArrow::Direction_East: text += "East"; break; + } + + if (!hideBasics) + { + text += + "

    " + "Modify which cells are shown" + "

    • Primary-Edit: Add cell in given direction
    • " + "
    • Secondary-Edit: Add cell and remove old cell
    • " + "
    • Shift Primary-Edit: Add cells in given direction
    • " + "
    • Shift Secondary-Edit: Add cells and remove old cells
    • " + "
    "; + } + + return text; +} + void CSVRender::CellArrow::adjustTransform() { diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp index cbbcc9d5ee..4523561946 100644 --- a/apps/opencs/view/render/cellarrow.hpp +++ b/apps/opencs/view/render/cellarrow.hpp @@ -26,6 +26,8 @@ namespace CSVRender CellArrowTag (CellArrow *arrow); CellArrow *getCellArrow() const; + + virtual QString getToolTip (bool hideBasics) const; }; From 692a15a3dfdfafe58595314a5358b5416995bb19 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Nov 2015 14:20:55 +0100 Subject: [PATCH 1339/1812] updated changelog again --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 378348ff84..36700904e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -223,6 +223,7 @@ Task #2730: Replace hardcoded column numbers in SimpleDialogueSubView/DialogueSubView Task #2750: Bullet shape instancing optimization Task #2793: Replace grid size setting with half grid size setting + Task #3003: Support FFMPEG 2.9 (Debian request) 0.36.1 ------ From fc8e40889df58bc18a54082799699c6151d41343 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 18:07:18 +0100 Subject: [PATCH 1340/1812] Move common subrecord definitions (NAME, DELE) to defs.hpp --- components/esm/cellref.cpp | 2 +- components/esm/debugprofile.cpp | 4 ++-- components/esm/defs.hpp | 7 +++++++ components/esm/filter.cpp | 4 ++-- components/esm/loadacti.cpp | 4 ++-- components/esm/loadalch.cpp | 4 ++-- components/esm/loadappa.cpp | 4 ++-- components/esm/loadarmo.cpp | 4 ++-- components/esm/loadbody.cpp | 4 ++-- components/esm/loadbook.cpp | 4 ++-- components/esm/loadbsgn.cpp | 4 ++-- components/esm/loadcell.cpp | 4 ++-- components/esm/loadclas.cpp | 4 ++-- components/esm/loadclot.cpp | 4 ++-- components/esm/loadcont.cpp | 4 ++-- components/esm/loadcrea.cpp | 4 ++-- components/esm/loaddial.cpp | 2 +- components/esm/loaddoor.cpp | 4 ++-- components/esm/loadench.cpp | 4 ++-- components/esm/loadfact.cpp | 4 ++-- components/esm/loadinfo.cpp | 4 ++-- components/esm/loadingr.cpp | 4 ++-- components/esm/loadland.cpp | 2 +- components/esm/loadlevlist.cpp | 4 ++-- components/esm/loadligh.cpp | 4 ++-- components/esm/loadlock.cpp | 4 ++-- components/esm/loadltex.cpp | 4 ++-- components/esm/loadmisc.cpp | 4 ++-- components/esm/loadnpc.cpp | 4 ++-- components/esm/loadpgrd.cpp | 4 ++-- components/esm/loadprob.cpp | 4 ++-- components/esm/loadrace.cpp | 4 ++-- components/esm/loadregn.cpp | 4 ++-- components/esm/loadrepa.cpp | 4 ++-- components/esm/loadscpt.cpp | 2 +- components/esm/loadsndg.cpp | 4 ++-- components/esm/loadsoun.cpp | 4 ++-- components/esm/loadspel.cpp | 4 ++-- components/esm/loadsscr.cpp | 4 ++-- components/esm/loadstat.cpp | 4 ++-- components/esm/loadweap.cpp | 4 ++-- 41 files changed, 83 insertions(+), 76 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index d4ef29e04e..76a82fe232 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -108,7 +108,7 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) case ESM::FourCC<'N','A','M','0'>::value: esm.skipHSub(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 56be91e71f..66e338d0c4 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -15,7 +15,7 @@ void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); break; case ESM::FourCC<'D','E','S','C'>::value: @@ -27,7 +27,7 @@ void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 9f1a935aea..8066b622ae 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -133,5 +133,12 @@ enum RecNameInts REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; +/// Common subrecords +enum SubRecNameInts +{ + SREC_DELE = ESM::FourCC<'D','E','L','E'>::value, + SREC_NAME = ESM::FourCC<'N','A','M','E'>::value +}; + } #endif diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index 5b33c6683e..c3658f1520 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -16,7 +16,7 @@ void ESM::Filter::load (ESMReader& esm, bool &isDeleted) uint32_t name = esm.retSubName().val; switch (name) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); break; case ESM::FourCC<'F','I','L','T'>::value: @@ -25,7 +25,7 @@ void ESM::Filter::load (ESMReader& esm, bool &isDeleted) case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 14db45c342..b9934d3d39 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -31,7 +31,7 @@ namespace ESM case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index ceff4ba7d7..2049045024 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -44,7 +44,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 7a77ba4213..490881fae7 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 600c417be3..f2526554af 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -51,7 +51,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -77,7 +77,7 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 20d6b35cff..09113e8d1b 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -33,7 +33,7 @@ namespace ESM esm.getHT(mData, 4); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index b08b12f501..617040be42 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -45,7 +45,7 @@ namespace ESM case ESM::FourCC<'T','E','X','T'>::value: mText = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 0413a86104..9a4d98bb7b 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -20,7 +20,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -36,7 +36,7 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 703a4f4cba..8455daeac3 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -71,14 +71,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mName = esm.getHString(); break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 2ad14b9f26..61960b87db 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -49,7 +49,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -65,7 +65,7 @@ namespace ESM case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 8a88e6d7a8..2ef69e5e91 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -47,7 +47,7 @@ namespace ESM case ESM::FourCC<'I','N','D','X'>::value: mParts.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 3726837509..739b0d7db6 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -38,7 +38,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -66,7 +66,7 @@ namespace ESM case ESM::FourCC<'N','P','C','O'>::value: mInventory.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index e593ff5405..0b53e5737d 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -30,7 +30,7 @@ namespace ESM { esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -79,7 +79,7 @@ namespace ESM { case AI_CNDT: mAiPackage.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 30fa3cfef7..bc87c4f57d 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -44,7 +44,7 @@ namespace ESM } break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); mType = Unknown; isDeleted = true; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 706e938e89..6d8c0978c8 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -37,7 +37,7 @@ namespace ESM case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 5580ef222a..ae83c63f70 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -20,7 +20,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -31,7 +31,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index f550a55380..75c482d201 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -42,7 +42,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -68,7 +68,7 @@ namespace ESM mReactions[faction] = reaction; break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index d1f20a3d45..246baf0265 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -67,7 +67,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mResponse = esm.getHString(); break; case ESM::FourCC<'S','C','V','R'>::value: @@ -93,7 +93,7 @@ namespace ESM mQuestStatus = QS_Restart; esm.skipRecord(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index a481d5b79a..e00e73ab0b 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 9db58fc5b3..e7be033219 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -105,7 +105,7 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mFlags); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6245ec856a..8c0d503244 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -17,7 +17,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -49,7 +49,7 @@ namespace ESM hasList = true; break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index a0fedc3ad8..20c700b238 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -42,7 +42,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index be93eaa0e7..fc6af86990 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index e9cd4578d1..a42ae7c5bf 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -30,7 +30,7 @@ namespace ESM case ESM::FourCC<'D','A','T','A'>::value: mTexture = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index f03cb9a852..199b4e3b2c 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 72333add37..e524e6a7cc 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -28,7 +28,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -98,7 +98,7 @@ namespace ESM case AI_CNDT: mAiPackage.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 95e6a906fd..69ee60eeb8 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -48,7 +48,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mCell = esm.getHString(); break; case ESM::FourCC<'D','A','T','A'>::value: @@ -111,7 +111,7 @@ namespace ESM } break; } - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index 31caeff414..baf466490b 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index d5172a133e..a371751446 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -31,7 +31,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -48,7 +48,7 @@ namespace ESM case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 9f3089763c..e5382f50b6 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -18,7 +18,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -65,7 +65,7 @@ namespace ESM esm.getHT(sr, 33); mSoundList.push_back(sr); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 00d2ebf085..e4af3d9378 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -39,7 +39,7 @@ namespace ESM case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2a0542138a..b46d5b658a 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -88,7 +88,7 @@ namespace ESM case ESM::FourCC<'S','C','T','X'>::value: mScriptText = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 189cc97df9..d84fe624d0 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -33,7 +33,7 @@ namespace ESM case ESM::FourCC<'S','N','A','M'>::value: mSound = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index d3a82e1984..82f169e54f 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -30,7 +30,7 @@ namespace ESM esm.getHT(mData, 3); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 16ffb63ff7..728b7bc2a7 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -21,7 +21,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -37,7 +37,7 @@ namespace ESM esm.getHT(s, 24); mEffects.mList.push_back(s); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index a211a99bf5..ab4c09750d 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -27,7 +27,7 @@ namespace ESM mData = esm.getHString(); hasData = true; break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index eee7a50f50..62d495ee34 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -18,14 +18,14 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index b0bc1dad67..880a26bcb3 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -19,7 +19,7 @@ namespace ESM esm.getSubName(); switch (esm.retSubName().val) { - case ESM::FourCC<'N','A','M','E'>::value: + case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; @@ -42,7 +42,7 @@ namespace ESM case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; - case ESM::FourCC<'D','E','L','E'>::value: + case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; From 054c3eb24e0160b8a903dfe0de5c9081b8ddb937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:39:44 +0100 Subject: [PATCH 1341/1812] Do not deep copy PrimitiveSets when build with OSG 3.5 --- components/sceneutil/clone.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index e4b4f63bb1..a372b1ebd8 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -1,6 +1,7 @@ #include "clone.hpp" #include +#include #include #include @@ -53,6 +54,7 @@ namespace SceneUtil osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); +#if OSG_VERSION_LESS_THAN(3,5,0) /* Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: @@ -71,12 +73,12 @@ namespace SceneUtil In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - Possible fix submitted to osg-submissions ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). + Fixed in OSG 3.5 ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). */ copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); - +#endif osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) From 1402a16702112b628225e0274019c9998dcd28d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:59:39 +0100 Subject: [PATCH 1342/1812] SceneWidget: change the threading model to DrawThreadPerContext Performs much better because we can break frame early, running cull in parallel with last frame's draw. --- apps/opencs/view/render/scenewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 76b3db348d..426e10ecbd 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -126,7 +126,7 @@ CompositeViewer::CompositeViewer() // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread" when the viewer is run multi-threaded, this is regression from Qt4 osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; #else - osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext; + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::DrawThreadPerContext; #endif setThreadingModel(threadingModel); From 9116c701d518f791252fe2c991d24938bf03e3ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:50:57 +0100 Subject: [PATCH 1343/1812] esmtool fix --- apps/esmtool/record.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 0e7769f378..d7cbea73b0 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -867,7 +867,7 @@ void Record::print() std::cout << " Unknown1: " << data->mUnk1 << std::endl; std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); + mData.unloadData(); std::cout << " Deleted: " << mIsDeleted << std::endl; } From d0d8c2ededfcb45d8c5aebaac23bf076f719b4e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 20:27:06 +0100 Subject: [PATCH 1344/1812] Delete empty test --- apps/openmw_test_suite/CMakeLists.txt | 3 +-- .../components/misc/test_stringops.cpp | 14 -------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 apps/openmw_test_suite/components/misc/test_stringops.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 2ffb7ffa0e..a27c8f1a46 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -4,8 +4,7 @@ if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES - components/misc/test_*.cpp - mwdialogue/test_*.cpp + mwdialogue/test_keywordsearch.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/components/misc/test_stringops.cpp b/apps/openmw_test_suite/components/misc/test_stringops.cpp deleted file mode 100644 index 55fe0e0c27..0000000000 --- a/apps/openmw_test_suite/components/misc/test_stringops.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "components/misc/stringops.hpp" - -struct StringOpsTest : public ::testing::Test -{ - protected: - virtual void SetUp() - { - } - - virtual void TearDown() - { - } -}; From 38c155c579342f8748e3c93f531be1f1da91784a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 23:12:07 +0100 Subject: [PATCH 1345/1812] Tests: add dialogue_merging_test (requires some data files) --- apps/openmw_test_suite/CMakeLists.txt | 4 + apps/openmw_test_suite/mwworld/test_store.cpp | 172 ++++++++++++++++++ .../loadinglistener/loadinglistener.hpp | 14 +- 3 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 apps/openmw_test_suite/mwworld/test_store.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index a27c8f1a46..2300f97a36 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -4,6 +4,10 @@ if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES + ../openmw/mwworld/store.cpp + ../openmw/mwworld/esmstore.cpp + mwworld/test_store.cpp + mwdialogue/test_keywordsearch.cpp ) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp new file mode 100644 index 0000000000..64e064865f --- /dev/null +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -0,0 +1,172 @@ +#include + +#include + +#include +#include +#include + +#include "apps/openmw/mwworld/esmstore.hpp" + +/// Base class for tests of ESMStore that rely on external content files to produce the test data +struct ContentFileTest : public ::testing::Test +{ + protected: + + virtual void SetUp() + { + readContentFiles(); + + // load the content files + std::vector readerList; + readerList.resize(mContentFiles.size()); + + int index=0; + for (std::vector::const_iterator it = mContentFiles.begin(); it != mContentFiles.end(); ++it) + { + ESM::ESMReader lEsm; + lEsm.setEncoder(NULL); + lEsm.setIndex(index); + lEsm.setGlobalReaderList(&readerList); + lEsm.open(it->string()); + readerList[index] = lEsm; + std::auto_ptr listener; + listener.reset(new Loading::Listener); + mEsmStore.load(readerList[index], listener.get()); + + ++index; + } + + mEsmStore.setUp(); + } + + virtual void TearDown() + { + } + + // read absolute path to content files from openmw.cfg + void readContentFiles() + { + boost::program_options::variables_map variables; + + boost::program_options::options_description desc("Allowed options"); + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) + ("content", boost::program_options::value >()->default_value(std::vector(), "") + ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") + ("data-local", boost::program_options::value()->default_value("")); + + boost::program_options::notify(variables); + + mConfigurationManager.readConfiguration(variables, desc, true); + + Files::PathContainer dataDirs, dataLocal; + if (!variables["data"].empty()) { + dataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + dataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mConfigurationManager.processPaths (dataDirs); + mConfigurationManager.processPaths (dataLocal, true); + + if (!dataLocal.empty()) + dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); + + Files::Collections collections (dataDirs, true); + + std::vector contentFiles = variables["content"].as >(); + for (std::vector::iterator it = contentFiles.begin(); it != contentFiles.end(); ++it) + mContentFiles.push_back(collections.getPath(*it)); + } + +protected: + Files::ConfigurationManager mConfigurationManager; + MWWorld::ESMStore mEsmStore; + std::vector mContentFiles; +}; + +/// Print results of the dialogue merging process, i.e. the resulting linked list. +TEST_F(ContentFileTest, dialogue_merging_test) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + const std::string file = "test_dialogue_merging.txt"; + + boost::filesystem::ofstream stream; + stream.open(file); + + const MWWorld::Store& dialStore = mEsmStore.get(); + for (MWWorld::Store::iterator it = dialStore.begin(); it != dialStore.end(); ++it) + { + const ESM::Dialogue& dial = *it; + stream << "Dialogue: " << dial.mId << std::endl; + + for (ESM::Dialogue::InfoContainer::const_iterator infoIt = dial.mInfo.begin(); infoIt != dial.mInfo.end(); ++infoIt) + { + const ESM::DialInfo& info = *infoIt; + stream << info.mId << std::endl; + } + stream << std::endl; + } + + std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; +} + +/* +TEST_F(ContentFileTest, diagnostics) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + +} +*/ + +// TODO: +/// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on +/// - even rounding errors can completely change the resulting spell lists. +/* +TEST_F(ContentFileTest, autocalc_test) +{ + if (mContentFiles.empty()) + { + std::cout << "No content files found, skipping test" << std::endl; + return; + } + + +} +*/ + +/* +/// Base class for tests of ESMStore that do not rely on external content files +struct StoreTest : public ::testing::Test +{ +protected: + MWWorld::ESMStore mEsmStore; +}; + +/// Tests deletion of records. +TEST_F(StoreTest, delete_test) +{ + + +} + +/// Tests overwriting of records. +TEST_F(StoreTest, overwrite_test) +{ + +} +*/ diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 47962015c2..558111b342 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -6,18 +6,18 @@ namespace Loading class Listener { public: - virtual void setLabel (const std::string& label) = 0; + virtual void setLabel (const std::string& label) {} // Use ScopedLoad instead of using these directly - virtual void loadingOn() = 0; - virtual void loadingOff() = 0; + virtual void loadingOn() {} + virtual void loadingOff() {} /// Indicate that some progress has been made, without specifying how much - virtual void indicateProgress () = 0; + virtual void indicateProgress () {} - virtual void setProgressRange (size_t range) = 0; - virtual void setProgress (size_t value) = 0; - virtual void increaseProgress (size_t increase = 1) = 0; + virtual void setProgressRange (size_t range) {} + virtual void setProgress (size_t value) {} + virtual void increaseProgress (size_t increase = 1) {} }; // Used for stopping a loading sequence when the object goes out of scope From 771193bae8d00e0cee089544973deeffafdaccc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 23:38:38 +0100 Subject: [PATCH 1346/1812] Tests: add content_diagnostics_test (requires some data files) --- apps/openmw_test_suite/mwworld/test_store.cpp | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 64e064865f..bb8bcc37c9 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -120,8 +120,61 @@ TEST_F(ContentFileTest, dialogue_merging_test) std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; } -/* -TEST_F(ContentFileTest, diagnostics) +// Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell) +#define RUN_TEST_FOR_TYPES(func, arg1, arg2) \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); \ + func(arg1, arg2); + +template +void printRecords(MWWorld::ESMStore& esmStore, std::ostream& outStream) +{ + const MWWorld::Store& store = esmStore.get(); + outStream << store.getSize() << " " << T::getRecordType() << " records" << std::endl; + + for (typename MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + { + const T& record = *it; + outStream << record.mId << std::endl; + } + + outStream << std::endl; +} + +/// Print some basic diagnostics about the loaded content files, e.g. number of records and names of those records +/// Also used to test the iteration order of records +TEST_F(ContentFileTest, content_diagnostics_test) { if (mContentFiles.empty()) { @@ -129,9 +182,15 @@ TEST_F(ContentFileTest, diagnostics) return; } + const std::string file = "test_content_diagnostics.txt"; + boost::filesystem::ofstream stream; + stream.open(file); + + RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream); + + std::cout << "diagnostics_test successful, results printed to " << file << std::endl; } -*/ // TODO: /// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on From 1e817a976fb836600c74cd4dbfe94742639f1179 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:12:59 +0100 Subject: [PATCH 1347/1812] Tests: add record deletion test --- apps/openmw_test_suite/mwworld/test_store.cpp | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index bb8bcc37c9..dfa1c0b256 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -4,10 +4,14 @@ #include #include +#include +#include #include #include "apps/openmw/mwworld/esmstore.hpp" +static Loading::Listener dummyListener; + /// Base class for tests of ESMStore that rely on external content files to produce the test data struct ContentFileTest : public ::testing::Test { @@ -30,9 +34,7 @@ struct ContentFileTest : public ::testing::Test lEsm.setGlobalReaderList(&readerList); lEsm.open(it->string()); readerList[index] = lEsm; - std::auto_ptr listener; - listener.reset(new Loading::Listener); - mEsmStore.load(readerList[index], listener.get()); + mEsmStore.load(readerList[index], &dummyListener); ++index; } @@ -208,7 +210,6 @@ TEST_F(ContentFileTest, autocalc_test) } */ -/* /// Base class for tests of ESMStore that do not rely on external content files struct StoreTest : public ::testing::Test { @@ -216,11 +217,66 @@ protected: MWWorld::ESMStore mEsmStore; }; + +/// Create an ESM file in-memory containing the specified record. +/// @param deleted Write record with deleted flag? +template +Files::IStreamPtr getEsmFile(T record, bool deleted) +{ + ESM::ESMWriter writer; + std::stringstream* stream = new std::stringstream; + writer.setFormat(0); + writer.save(*stream); + writer.startRecord(T::sRecordId); + writer.writeHNString("NAME", record.mId); + if (deleted) + writer.writeHNT("DELE", (int)1); + record.save(writer); + writer.endRecord(T::sRecordId); + + return Files::IStreamPtr(stream); +} + /// Tests deletion of records. TEST_F(StoreTest, delete_test) { + const std::string recordId = "foobar"; + typedef ESM::Apparatus RecordType; + RecordType record; + record.blank(); + record.mId = recordId; + + ESM::ESMReader reader; + std::vector readerList; + readerList.push_back(reader); + reader.setGlobalReaderList(&readerList); + + // master file inserts a record + Files::IStreamPtr file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 1); + + // now a plugin deletes it + file = getEsmFile(record, true); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 0); + + // now another plugin inserts it again + // expected behaviour is the record to reappear rather than staying deleted + file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + ASSERT_TRUE (mEsmStore.get().getSize() == 1); } /// Tests overwriting of records. @@ -228,4 +284,3 @@ TEST_F(StoreTest, overwrite_test) { } -*/ From f91aae2350a1c6ce188b4f53b5714eb7a288306d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:17:13 +0100 Subject: [PATCH 1348/1812] Tests: add record overwrite test --- apps/openmw_test_suite/mwworld/test_store.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index dfa1c0b256..9933862073 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -196,7 +196,7 @@ TEST_F(ContentFileTest, content_diagnostics_test) // TODO: /// Print results of autocalculated NPC spell lists. Also serves as test for attribute/skill autocalculation which the spell autocalculation heavily relies on -/// - even rounding errors can completely change the resulting spell lists. +/// - even incorrect rounding modes can completely change the resulting spell lists. /* TEST_F(ContentFileTest, autocalc_test) { @@ -282,5 +282,38 @@ TEST_F(StoreTest, delete_test) /// Tests overwriting of records. TEST_F(StoreTest, overwrite_test) { + const std::string recordId = "foobar"; + const std::string recordIdUpper = "Foobar"; + typedef ESM::Apparatus RecordType; + + RecordType record; + record.blank(); + record.mId = recordId; + + ESM::ESMReader reader; + std::vector readerList; + readerList.push_back(reader); + reader.setGlobalReaderList(&readerList); + + // master file inserts a record + Files::IStreamPtr file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + // now a plugin overwrites it with changed data + record.mId = recordIdUpper; // change id to uppercase, to test case smashing while we're at it + record.mModel = "the_new_model"; + file = getEsmFile(record, false); + reader.open(file, "filename"); + mEsmStore.load(reader, &dummyListener); + mEsmStore.setUp(); + + // verify that changes were actually applied + const RecordType* overwrittenRec = mEsmStore.get().search(recordId); + + ASSERT_TRUE (overwrittenRec != NULL); + + ASSERT_TRUE (overwrittenRec && overwrittenRec->mModel == "the_new_model"); } From aae1aa3708bf7a48e768f6b323372f5a61aa93ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 00:23:35 +0100 Subject: [PATCH 1349/1812] Adjust tests to work with esm_rewrite branch. --- apps/openmw_test_suite/mwworld/test_store.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 9933862073..ac21470ded 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -5,14 +5,13 @@ #include #include #include -#include #include #include "apps/openmw/mwworld/esmstore.hpp" static Loading::Listener dummyListener; -/// Base class for tests of ESMStore that rely on external content files to produce the test data +/// Base class for tests of ESMStore that rely on external content files to produce the test results struct ContentFileTest : public ::testing::Test { protected: @@ -228,10 +227,7 @@ Files::IStreamPtr getEsmFile(T record, bool deleted) writer.setFormat(0); writer.save(*stream); writer.startRecord(T::sRecordId); - writer.writeHNString("NAME", record.mId); - if (deleted) - writer.writeHNT("DELE", (int)1); - record.save(writer); + record.save(writer, deleted); writer.endRecord(T::sRecordId); return Files::IStreamPtr(stream); From 05498ad5920e29aead9e0b431c884f84d98043b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 02:43:24 +0100 Subject: [PATCH 1350/1812] Refactor: InputManager no longer depends on Engine --- apps/openmw/engine.cpp | 38 +------------------------ apps/openmw/engine.hpp | 6 ---- apps/openmw/mwinput/inputmanagerimp.cpp | 14 +++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 10 ++----- apps/openmw/mwworld/player.cpp | 29 +++++++++++++++++++ apps/openmw/mwworld/player.hpp | 3 ++ 6 files changed, 44 insertions(+), 56 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5d2d588ed3..031eac8001 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -483,8 +483,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) else gameControllerdb = ""; //if it doesn't exist, pass in an empty string - // FIXME: shouldn't depend on Engine - MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); + MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); std::string myguiResources = (mResDir / "mygui").string(); @@ -717,41 +716,6 @@ void OMW::Engine::go() std::cout << "Quitting peacefully." << std::endl; } -void OMW::Engine::activate() -{ - if (mEnvironment.getWindowManager()->isGuiMode()) - return; - - MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); - if (playerStats.isParalyzed() || playerStats.getKnockedDown()) - return; - - MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); - - if (ptr.isEmpty()) - return; - - if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated - return; - - if (ptr.getClass().isActor()) - { - MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - - if (stats.getAiSequence().isInCombat() && !stats.isDead()) - return; - } - - mEnvironment.getWorld()->activate(ptr, mEnvironment.getWorld()->getPlayerPtr()); -} - -void OMW::Engine::screenshot() -{ - mScreenCaptureHandler->setFramesToCapture(1); - mScreenCaptureHandler->captureNextFrame(*mViewer); -} - void OMW::Engine::setCompileAll (bool all) { mCompileAll = all; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 73de57dc4b..a03752b86f 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -169,12 +169,6 @@ namespace OMW /// Initialise and enter main loop. void go(); - /// Activate the focussed object. - void activate(); - - /// Write screenshot to file. - void screenshot(); - /// Compile all scripts (excludign dialogue scripts) at startup? void setCompileAll (bool all); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ad5fe35bd9..688685e74b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include #include @@ -15,12 +17,11 @@ #include #include -#include "../engine.hpp" - #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -37,15 +38,15 @@ namespace MWInput InputManager::InputManager( SDL_Window* window, osg::ref_ptr viewer, - OMW::Engine& engine, + osg::ref_ptr screenCaptureHandler, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) : mWindow(window) , mWindowVisible(true) , mViewer(viewer) + , mScreenCaptureHandler(screenCaptureHandler) , mJoystickLastUsed(false) , mPlayer(NULL) - , mEngine(engine) , mInputManager(NULL) , mVideoWrapper(NULL) , mUserFile(userFile) @@ -952,7 +953,8 @@ namespace MWInput void InputManager::screenshot() { - mEngine.screenshot(); + mScreenCaptureHandler->setFramesToCapture(1); + mScreenCaptureHandler->captureNextFrame(*mViewer); MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved"); } @@ -1058,7 +1060,7 @@ namespace MWInput void InputManager::activate() { if (mControlSwitch["playercontrols"]) - mEngine.activate(); + mPlayer->activate(); } void InputManager::toggleAutoMove() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 62d0f413ba..fc539f5222 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -25,11 +25,6 @@ namespace MWBase class WindowManager; } -namespace OMW -{ - class Engine; -} - namespace ICS { class InputControlSystem; @@ -54,6 +49,7 @@ namespace SDLUtil namespace osgViewer { class Viewer; + class ScreenCaptureHandler; } struct SDL_Window; @@ -77,7 +73,7 @@ namespace MWInput InputManager( SDL_Window* window, osg::ref_ptr viewer, - OMW::Engine& engine, + osg::ref_ptr screenCaptureHandler, const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab); @@ -157,10 +153,10 @@ namespace MWInput SDL_Window* mWindow; bool mWindowVisible; osg::ref_ptr mViewer; + osg::ref_ptr mScreenCaptureHandler; bool mJoystickLastUsed; MWWorld::Player* mPlayer; - OMW::Engine& mEngine; ICS::InputControlSystem* mInputBinder; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 6bfdd29860..19b66c3c93 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -205,6 +205,35 @@ namespace MWWorld return ptr.getClass().getNpcStats(ptr).getDrawState(); } + void Player::activate() + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + return; + + MWWorld::Ptr player = getPlayer(); + const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); + if (playerStats.isParalyzed() || playerStats.getKnockedDown()) + return; + + MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (toActivate.isEmpty()) + return; + + if (toActivate.getClass().getName(toActivate) == "") // objects without name presented to user can never be activated + return; + + if (toActivate.getClass().isActor()) + { + MWMechanics::CreatureStats &stats = toActivate.getClass().getCreatureStats(toActivate); + + if (stats.getAiSequence().isInCombat() && !stats.isDead()) + return; + } + + MWBase::Environment::get().getWorld()->activate(toActivate, player); + } + bool Player::wasTeleported() const { return mTeleported; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index f0ae13daa9..595dd89fc6 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -82,6 +82,9 @@ namespace MWWorld void setDrawState (MWMechanics::DrawState_ state); MWMechanics::DrawState_ getDrawState(); /// \todo constness + /// Activate the object under the crosshair, if any + void activate(); + bool getAutoMove() const; void setAutoMove (bool enable); From 0ec56d321ac39888831ddb3c80a0f494773e13c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 03:01:40 +0100 Subject: [PATCH 1351/1812] Remove unneeded using namespace --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 688685e74b..0c306da68d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,8 +31,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -using namespace ICS; - namespace MWInput { InputManager::InputManager( From 4e3bbe01b6bfc77e3565bdaf98c1eba7aa22a83e Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 21:40:59 +0100 Subject: [PATCH 1352/1812] OS X: disable `glTexStorage2D` because of OSG/driver issue See http://forum.openscenegraph.org/viewtopic.php?p=65276#65276 for the details. --- apps/opencs/main.cpp | 4 ++++ apps/openmw/main.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index de2e6e83e1..0b7a34cdb6 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -43,6 +43,10 @@ class Application : public QApplication int main(int argc, char *argv[]) { + #ifdef Q_OS_MAC + setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0); + #endif + try { // To allow background thread drawing in OSG diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 3d631c7439..609452a9fd 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -321,6 +321,10 @@ private: int main(int argc, char**argv) { +#if defined(__APPLE__) + setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0); +#endif + // Some objects used to redirect cout and cerr // Scope must be here, so this still works inside the catch block for logging exceptions std::streambuf* cout_rdbuf = std::cout.rdbuf (); From 3ba546628df2babb0b6198c4374a7b2062cdde24 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:33:22 +0100 Subject: [PATCH 1353/1812] OS X: always copy Cocoa platform plugin into OpenMW bundle --- CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b88f6219..d7c5efa5f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -710,6 +710,18 @@ endif() # Apple bundling if (APPLE) + get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE) + get_filename_component(QT_COCOA_PLUGIN_DIR "${QT_COCOA_PLUGIN_PATH}" DIRECTORY) + get_filename_component(QT_COCOA_PLUGIN_GROUP "${QT_COCOA_PLUGIN_DIR}" NAME) + get_filename_component(QT_COCOA_PLUGIN_NAME "${QT_COCOA_PLUGIN_PATH}" NAME) + configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + + if (BUILD_OPENCS) + get_property(OPENCS_BUNDLE_NAME_TMP TARGET openmw-cs PROPERTY OUTPUT_NAME) + set(OPENCS_BUNDLE_NAME "${OPENCS_BUNDLE_NAME_TMP}.app") + configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + endif () + set(INSTALL_SUBDIR OpenMW) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) @@ -726,8 +738,6 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - - set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") install(CODE " From 4dcb1a1b1785426a2a7766b3fb22f0c21c7ca4ac Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:34:00 +0100 Subject: [PATCH 1354/1812] OS X: remove QPlastiqueStyle usage --- apps/launcher/playpage.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index 6cfb9686fa..99b74fdd39 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -2,20 +2,11 @@ #include -#ifdef Q_OS_MAC -#include -#endif - Launcher::PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { setObjectName ("PlayPage"); setupUi(this); - // Hacks to get the stylesheet look properly -#ifdef Q_OS_MAC - QPlastiqueStyle *style = new QPlastiqueStyle; - profilesComboBox->setStyle(style); -#endif profilesComboBox->setView(new QListView()); connect(profilesComboBox, SIGNAL(activated(int)), this, SIGNAL (signalProfileChanged(int))); From 014a2fc0e924b9229e8da812eddf85b883cd8a8e Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 22:34:20 +0100 Subject: [PATCH 1355/1812] OS X: do not override Qt plugin path --- apps/launcher/main.cpp | 9 --------- apps/opencs/main.cpp | 9 --------- 2 files changed, 18 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 32fe8c93a7..282b3fb89f 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -41,15 +41,6 @@ int main(int argc, char *argv[]) dir.cdUp(); dir.cdUp(); } - - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); - - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - app.setLibraryPaths(libraryPaths); #endif QDir::setCurrent(dir.absolutePath()); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 0b7a34cdb6..c6fe348356 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -68,15 +68,6 @@ int main(int argc, char *argv[]) dir.cdUp(); } QDir::setCurrent(dir.absolutePath()); - - // force Qt to load only LOCAL plugins, don't touch system Qt installation - QDir pluginsPath(QCoreApplication::applicationDirPath()); - pluginsPath.cdUp(); - pluginsPath.cd("Plugins"); - - QStringList libraryPaths; - libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath(); - application.setLibraryPaths(libraryPaths); #endif application.setWindowIcon (QIcon (":./openmw-cs.png")); From 5c4899580f1cb6dccc5d06995811b30079ff6ea6 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 12 Nov 2015 23:37:03 +0100 Subject: [PATCH 1356/1812] OS X: use less ambiguous variable names in packaging code --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7c5efa5f4..3d66d8ebec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -737,8 +737,8 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) - set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") + set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") + set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) @@ -758,12 +758,12 @@ if (APPLE) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () - get_filename_component(PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) + get_filename_component(OSG_PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) # and returns list of install paths for all installed plugins function (install_plugins_for_bundle bundle_path plugins_var) - set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${PLUGIN_PREFIX_DIR}") + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${OSG_PLUGIN_PREFIX_DIR}") set(PLUGINS "") set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") @@ -790,15 +790,15 @@ if (APPLE) install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) - if (\${item} MATCHES ${PLUGIN_PREFIX_DIR}) - set(path \"@executable_path/../PlugIns/${PLUGIN_PREFIX_DIR}\") + if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) + set(path \"@executable_path/../PlugIns/${OSG_PLUGIN_PREFIX_DIR}\") set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) endif() endfunction() cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From fff6b5fde1014714ebde324b81a1a0a9bab42156 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 00:53:54 +0100 Subject: [PATCH 1357/1812] OS X: remove custom bundle utilities, ones from CMake versions >= 3.1.0 are good enough --- CMakeLists.txt | 3 +- cmake/BundleUtilitiesWithRPath.cmake | 961 ------------------------- cmake/COPYING-CMAKE-SCRIPTS | 266 ------- cmake/GetPrerequisitesWithRPath.cmake | 990 -------------------------- 4 files changed, 2 insertions(+), 2218 deletions(-) delete mode 100644 cmake/BundleUtilitiesWithRPath.cmake delete mode 100644 cmake/GetPrerequisitesWithRPath.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d66d8ebec..e218923bf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -743,7 +743,8 @@ if (APPLE) install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) - include(BundleUtilitiesWithRPath) + include(BundleUtilities) + cmake_minimum_required(VERSION 3.1) " COMPONENT Runtime) set(ABSOLUTE_PLUGINS "") diff --git a/cmake/BundleUtilitiesWithRPath.cmake b/cmake/BundleUtilitiesWithRPath.cmake deleted file mode 100644 index 5254e1a529..0000000000 --- a/cmake/BundleUtilitiesWithRPath.cmake +++ /dev/null @@ -1,961 +0,0 @@ -#.rst: -# BundleUtilities -# --------------- -# -# Functions to help assemble a standalone bundle application. -# -# A collection of CMake utility functions useful for dealing with .app -# bundles on the Mac and bundle-like directories on any OS. -# -# The following functions are provided by this module: -# -# :: -# -# fixup_bundle -# copy_and_fixup_bundle -# verify_app -# get_bundle_main_executable -# get_dotapp_dir -# get_bundle_and_executable -# get_bundle_all_executables -# get_item_key -# clear_bundle_keys -# set_bundle_key_values -# get_bundle_keys -# copy_resolved_item_into_bundle -# copy_resolved_framework_into_bundle -# fixup_bundle_item -# verify_bundle_prerequisites -# verify_bundle_symlinks -# -# Requires CMake 2.6 or greater because it uses function, break and -# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. -# -# :: -# -# FIXUP_BUNDLE( ) -# -# Fix up a bundle in-place and make it standalone, such that it can be -# drag-n-drop copied to another machine and run on that machine as long -# as all of the system libraries are compatible. -# -# If you pass plugins to fixup_bundle as the libs parameter, you should -# install them or copy them into the bundle before calling fixup_bundle. -# The "libs" parameter is a list of libraries that must be fixed up, but -# that cannot be determined by otool output analysis. (i.e., plugins) -# -# Gather all the keys for all the executables and libraries in a bundle, -# and then, for each key, copy each prerequisite into the bundle. Then -# fix each one up according to its own list of prerequisites. -# -# Then clear all the keys and call verify_app on the final bundle to -# ensure that it is truly standalone. -# -# :: -# -# COPY_AND_FIXUP_BUNDLE( ) -# -# Makes a copy of the bundle at location and then fixes up -# the new copied bundle in-place at ... -# -# :: -# -# VERIFY_APP() -# -# Verifies that an application appears valid based on running -# analysis tools on it. Calls "message(FATAL_ERROR" if the application -# is not verified. -# -# :: -# -# GET_BUNDLE_MAIN_EXECUTABLE( ) -# -# The result will be the full path name of the bundle's main executable -# file or an "error:" prefixed string if it could not be determined. -# -# :: -# -# GET_DOTAPP_DIR( ) -# -# Returns the nearest parent dir whose name ends with ".app" given the -# full path to an executable. If there is no such parent dir, then -# simply return the dir containing the executable. -# -# The returned directory may or may not exist. -# -# :: -# -# GET_BUNDLE_AND_EXECUTABLE( ) -# -# Takes either a ".app" directory name or the name of an executable -# nested inside a ".app" directory and returns the path to the ".app" -# directory in and the path to its main executable in -# -# -# :: -# -# GET_BUNDLE_ALL_EXECUTABLES( ) -# -# Scans the given bundle recursively for all executable files and -# accumulates them into a variable. -# -# :: -# -# GET_ITEM_KEY( ) -# -# Given a file (item) name, generate a key that should be unique -# considering the set of libraries that need copying or fixing up to -# make a bundle standalone. This is essentially the file name including -# extension with "." replaced by "_" -# -# This key is used as a prefix for CMake variables so that we can -# associate a set of variables with a given item based on its key. -# -# :: -# -# CLEAR_BUNDLE_KEYS() -# -# Loop over the list of keys, clearing all the variables associated with -# each key. After the loop, clear the list of keys itself. -# -# Caller of get_bundle_keys should call clear_bundle_keys when done with -# list of keys. -# -# :: -# -# SET_BUNDLE_KEY_VALUES( -# ) -# -# Add a key to the list (if necessary) for the given item. If added, -# also set all the variables associated with that key. -# -# :: -# -# GET_BUNDLE_KEYS( ) -# -# Loop over all the executable and library files within the bundle (and -# given as extra ) and accumulate a list of keys representing -# them. Set values associated with each key such that we can loop over -# all of them and copy prerequisite libs into the bundle and then do -# appropriate install_name_tool fixups. -# -# :: -# -# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) -# -# Copy a resolved item into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# :: -# -# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) -# -# Copy a resolved framework into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want -# full frameworks embedded in your bundles, set -# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By -# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework -# dylib itself plus the framework Resources directory. -# -# :: -# -# IS_RESOLVED_ITEM_EMBEDDED( ) -# -# Set variable to True if the resolved item is -# embedded into the bundle. The function does NOT check for the existence of the -# item, instead if checks if the provided path would correspond to an embeddable -# item. If is True, extra information will be displayed in case the item -# is not embedded. -# -# :: -# -# FIXUP_BUNDLE_ITEM( ) -# -# Get the direct/non-system prerequisites of the resolved embedded item. -# For each prerequisite, change the way it is referenced to the value of -# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely -# changing to an "@executable_path" style reference.) -# -# This function requires that the resolved_embedded_item be "inside" the -# bundle already. In other words, if you pass plugins to fixup_bundle -# as the libs parameter, you should install them or copy them into the -# bundle before calling fixup_bundle. The "libs" parameter is a list of -# libraries that must be fixed up, but that cannot be determined by -# otool output analysis. (i.e., plugins) -# -# Also, change the id of the item being fixed up to its own -# _EMBEDDED_ITEM value. -# -# Accumulate changes in a local variable and make *one* call to -# install_name_tool at the end of the function with all the changes at -# once. -# -# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be -# marked writable before install_name_tool tries to change them. -# -# :: -# -# VERIFY_BUNDLE_PREREQUISITES( ) -# -# Verifies that the sum of all prerequisites of all files inside the -# bundle are contained within the bundle or are "system" libraries, -# presumed to exist everywhere. -# -# :: -# -# VERIFY_BUNDLE_SYMLINKS( ) -# -# Verifies that any symlinks found in the bundle point to other files -# that are already also in the bundle... Anything that points to an -# external file causes this function to fail the verification. - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org -# -# Redistribution AND use is allowed according to the terms of the -# BSD-style license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -# The functions defined in this file depend on the get_prerequisites function -# (and possibly others) found in: -# -get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) -include("${BundleUtilities_cmake_dir}/GetPrerequisitesWithRPath.cmake") - - -function(get_bundle_main_executable bundle result_var) - set(result "error: '${bundle}/Contents/Info.plist' file does not exist") - - if(EXISTS "${bundle}/Contents/Info.plist") - set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") - set(line_is_main_executable 0) - set(bundle_executable "") - - # Read Info.plist as a list of lines: - # - set(eol_char "E") - file(READ "${bundle}/Contents/Info.plist" info_plist) - string(REPLACE ";" "\\;" info_plist "${info_plist}") - string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") - string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") - - # Scan the lines for "CFBundleExecutable" - the line after that - # is the name of the main executable. - # - foreach(line ${info_plist}) - if(line_is_main_executable) - string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") - break() - endif() - - if(line MATCHES "CFBundleExecutable") - set(line_is_main_executable 1) - endif() - endforeach() - - if(NOT "${bundle_executable}" STREQUAL "") - if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") - set(result "${bundle}/Contents/MacOS/${bundle_executable}") - else() - - # Ultimate goal: - # If not in "Contents/MacOS" then scan the bundle for matching files. If - # there is only one executable file that matches, then use it, otherwise - # it's an error... - # - #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") - - # But for now, pragmatically, it's an error. Expect the main executable - # for the bundle to be in Contents/MacOS, it's an error if it's not: - # - set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") - endif() - endif() - else() - # - # More inclusive technique... (This one would work on Windows and Linux - # too, if a developer followed the typical Mac bundle naming convention...) - # - # If there is no Info.plist file, try to find an executable with the same - # base name as the .app directory: - # - endif() - - set(${result_var} "${result}" PARENT_SCOPE) -endfunction() - - -function(get_dotapp_dir exe dotapp_dir_var) - set(s "${exe}") - - if(s MATCHES "/.*\\.app/") - # If there is a ".app" parent directory, - # ascend until we hit it: - # (typical of a Mac bundle executable) - # - set(done 0) - while(NOT ${done}) - get_filename_component(snamewe "${s}" NAME_WE) - get_filename_component(sname "${s}" NAME) - get_filename_component(sdir "${s}" PATH) - set(s "${sdir}") - if(sname MATCHES "\\.app$") - set(done 1) - set(dotapp_dir "${sdir}/${sname}") - endif() - endwhile() - else() - # Otherwise use a directory containing the exe - # (typical of a non-bundle executable on Mac, Windows or Linux) - # - is_file_executable("${s}" is_executable) - if(is_executable) - get_filename_component(sdir "${s}" PATH) - set(dotapp_dir "${sdir}") - else() - set(dotapp_dir "${s}") - endif() - endif() - - - set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) -endfunction() - - -function(get_bundle_and_executable app bundle_var executable_var valid_var) - set(valid 0) - - if(EXISTS "${app}") - # Is it a directory ending in .app? - if(IS_DIRECTORY "${app}") - if(app MATCHES "\\.app$") - get_bundle_main_executable("${app}" executable) - if(EXISTS "${app}" AND EXISTS "${executable}") - set(${bundle_var} "${app}" PARENT_SCOPE) - set(${executable_var} "${executable}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled .app directory case...") - else() - message(STATUS "warning: *NOT* handled - .app directory case...") - endif() - else() - message(STATUS "warning: *NOT* handled - directory but not .app case...") - endif() - else() - # Is it an executable file? - is_file_executable("${app}" is_executable) - if(is_executable) - get_dotapp_dir("${app}" dotapp_dir) - if(EXISTS "${dotapp_dir}") - set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in .app dir case...") - else() - get_filename_component(app_dir "${app}" PATH) - set(${bundle_var} "${app_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in any dir case...") - endif() - else() - message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") - endif() - endif() - else() - message(STATUS "warning: *NOT* handled - directory/file does not exist...") - endif() - - if(NOT valid) - set(${bundle_var} "error: not a bundle" PARENT_SCOPE) - set(${executable_var} "error: not a bundle" PARENT_SCOPE) - endif() - - set(${valid_var} ${valid} PARENT_SCOPE) -endfunction() - - -function(get_bundle_all_executables bundle exes_var) - set(exes "") - - file(GLOB_RECURSE file_list "${bundle}/*") - if(UNIX) - find_program(find_cmd "find") - mark_as_advanced(find_cmd) - endif() - - # find command is much quicker than checking every file one by one on Unix - # which can take long time for large bundles, and since anyway we expect - # executable to have execute flag set we can narrow the list much quicker. - if(find_cmd) - execute_process(COMMAND "${find_cmd}" "${bundle}" - -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) - OUTPUT_VARIABLE file_list - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(REPLACE "\n" ";" file_list "${file_list}") - else() - file(GLOB_RECURSE file_list "${bundle}/*") - endif() - - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - set(exes ${exes} "${f}") - endif() - endforeach() - - set(${exes_var} "${exes}" PARENT_SCOPE) -endfunction() - - -function(get_item_key item key_var) - get_filename_component(item_name "${item}" NAME) - if(WIN32) - string(TOLOWER "${item_name}" item_name) - endif() - string(REPLACE "." "_" ${key_var} "${item_name}") - set(${key_var} ${${key_var}} PARENT_SCOPE) -endfunction() - - -function(clear_bundle_keys keys_var) - foreach(key ${${keys_var}}) - set(${key}_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_ITEM PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_COPYFLAG PARENT_SCOPE) - endforeach() - set(${keys_var} PARENT_SCOPE) -endfunction() - - -function(set_bundle_key_values keys_var context item exepath dirs copyflag) - get_filename_component(item_name "${item}" NAME) - - get_item_key("${item}" key) - - list(LENGTH ${keys_var} length_before) - gp_append_unique(${keys_var} "${key}") - list(LENGTH ${keys_var} length_after) - - if(NOT length_before EQUAL length_after) - gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) - - gp_item_default_embedded_path("${item}" default_embedded_path) - - if(item MATCHES "[^/]+\\.framework/") - # For frameworks, construct the name under the embedded path from the - # opening "${item_name}.framework/" to the closing "/${item_name}": - # - string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") - else() - # For other items, just use the same name as the original, but in the - # embedded path: - # - set(embedded_item "${default_embedded_path}/${item_name}") - - if(APPLE) - # For executables inside the bundle, extract the expected path. - # This remove the hack introduced in commit 6f8bdd27 consisting in - # reseting the value of 'resolved_embedded_item' with 'resolved_item'. - get_dotapp_dir("${exepath}" exe_dotapp_dir) - if(NOT DEFINED gp_bundle_executables) - get_bundle_all_executables("${exe_dotapp_dir}" gp_bundle_executables) - endif() - foreach(exe ${gp_bundle_executables}) - get_item_key("${exe}" exe_key) - list(APPEND exe_keys ${exe_key}) - endforeach() - list(FIND exe_keys ${key} is_executable) - if(NOT is_executable EQUAL "-1") - get_filename_component(resolved_item_path ${resolved_item} PATH) - file(RELATIVE_PATH exe_relative_path_from_dir ${exe_dotapp_dir} ${resolved_item_path}) - # For example, if input variables are: - # resolved_item: /path/to/MyApp.app/Contents/bin/myapp - # exe_dotapp_dir: /path/to/MyApp.app - # Computed variables will be: - # resolved_item_path: /path/to/MyApp.app/Contents/bin - # exe_relative_path_from_dir: Contents/bin - set(embedded_item "@executable_path/../../${exe_relative_path_from_dir}/${item_name}") - set(show_status 0) - if(show_status) - message(STATUS "resolved_item='${resolved_item}'") - message(STATUS "exe_dotapp_dir='${exe_dotapp_dir}'") - message(STATUS "exe_relative_path_from_dir='${exe_relative_path_from_dir}'") - message(STATUS "item_name='${item_name}'") - message(STATUS "embedded_item='${embedded_item}'") - message(STATUS "") - endif() - endif() - endif() - endif() - - gp_resolve_embedded_item("${context}" "${embedded_item}" "${exepath}" resolved_embedded_item) - get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) - - # Do not copy already embedded item - set(verbose 0) - is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) - if(EXISTS "${resolved_embedded_item}" AND is_embedded) - set(copyflag 0) - set(resolved_item "${resolved_embedded_item}") - endif() - - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - set(${key}_ITEM "${item}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) - set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) - else() - #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") - endif() -endfunction() - - -function(get_bundle_keys app libs dirs keys_var) - set(${keys_var} PARENT_SCOPE) - - get_bundle_and_executable("${app}" bundle executable valid) - if(valid) - # Always use the exepath of the main bundle executable for @executable_path - # replacements: - # - get_filename_component(exepath "${executable}" PATH) - - # But do fixups on all executables in the bundle: - # - get_bundle_all_executables("${bundle}" gp_bundle_executables) - - # For each extra lib, accumulate a key as well and then also accumulate - # any of its prerequisites. (Extra libs are typically dynamically loaded - # plugins: libraries that are prerequisites for full runtime functionality - # but that do not show up in otool -L output...) - # - foreach(lib ${libs}) - set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) - - set(prereqs "") - get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # For each executable found in the bundle, accumulate keys as we go. - # The list of keys should be complete when all prerequisites of all - # binaries in the bundle have been analyzed. - # - foreach(exe ${gp_bundle_executables}) - # Add the exe itself to the keys: - # - set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) - - # Add each prerequisite to the keys: - # - set(prereqs "") - get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # Propagate values to caller's scope: - # - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - foreach(key ${${keys_var}}) - set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) - endforeach() - endif() -endfunction() - - -function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - - -function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - if(BU_COPY_FULL_FRAMEWORK_CONTENTS) - # Full Framework (everything): - get_filename_component(resolved_dir "${resolved_item}" PATH) - get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) - get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) - get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") - else() - # Framework lib itself: - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - - # Plus Resources, if they exist: - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") - if(EXISTS "${resolved_resources}") - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") - endif() - - # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is - # missing in resources, copy it from other well known incorrect locations: - if(NOT EXISTS "${resolved_resources}/Info.plist") - # Check for Contents/Info.plist in framework root (older Qt SDK): - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") - if(EXISTS "${resolved_info_plist}") - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") - endif() - endif() - - # Check if framework is versioned and fix it layout - string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") - string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") - if(resolved_embedded_versions_basename STREQUAL "Versions") - # Ensure Current symlink points to the framework version - if(NOT EXISTS "${resolved_embedded_versions}/Current") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") - endif() - # Restore symlinks in framework root pointing to current framework - # binary and resources: - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}") - string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}") - if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}") - endif() - if(NOT EXISTS "${resolved_embedded_root}/Resources") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources") - endif() - endif() - endif() - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - -function(is_resolved_item_embedded resolved_item exepath verbose is_embedded_var) - get_dotapp_dir("${exepath}" exe_dotapp_dir) - string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) - string(LENGTH "${resolved_item}" resolved_item_length) - set(path_too_short 0) - set(is_embedded 0) - if(${resolved_item_length} LESS ${exe_dotapp_dir_length}) - set(path_too_short 1) - endif() - if(NOT path_too_short) - string(SUBSTRING "${resolved_item}" 0 ${exe_dotapp_dir_length} item_substring) - if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") - set(is_embedded 1) - endif() - endif() - if(verbose AND NOT is_embedded) - message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") - message(" item_substring='${item_substring}'") - message(" resolved_item='${resolved_item}'") - message("") - endif() - set(${is_embedded_var} ${is_embedded} PARENT_SCOPE) -endfunction() - -function(fixup_bundle_item resolved_embedded_item exepath dirs) - # This item's key is "ikey": - # - get_item_key("${resolved_embedded_item}" ikey) - - # Ensure the item is "inside the .app bundle" -- it should not be fixed up if - # it is not in the .app bundle... Otherwise, we'll modify files in the build - # tree, or in other varied locations around the file system, with our call to - # install_name_tool. Make sure that doesn't happen here: - # - set(verbose 1) - is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) - if(NOT is_embedded) - message("Install or copy the item into the bundle before calling fixup_bundle.") - message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") - message("") - message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") - endif() - - set(prereqs "") - get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") - - set(changes "") - - foreach(pr ${prereqs}) - # Each referenced item's key is "rkey" in the loop: - # - get_item_key("${pr}" rkey) - - if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") - set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") - else() - message("warning: unexpected reference to '${pr}'") - endif() - endforeach() - - if(BU_CHMOD_BUNDLE_ITEMS) - execute_process(COMMAND chmod u+w "${resolved_embedded_item}") - endif() - - # Change this item's id and all of its references in one call - # to install_name_tool: - # - execute_process(COMMAND install_name_tool - ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" - ) -endfunction() - - -function(fixup_bundle app libs dirs) - message(STATUS "fixup_bundle") - message(STATUS " app='${app}'") - message(STATUS " libs='${libs}'") - message(STATUS " dirs='${dirs}'") - - get_bundle_and_executable("${app}" bundle executable valid) - message(STATUS " bundle='${bundle}'") - message(STATUS " executable='${executable}'") - if(valid) - get_filename_component(exepath "${executable}" PATH) - - # TODO: Extract list of rpath dirs automatically. On MacOSX, the following could be - # done: otool -l path/to/executable | grep -A 3 LC_RPATH | grep path - # See http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html#comment-87ea054b4839586412727dcfc94c79d2 - set(GP_RPATH_DIR ${bundle}/Contents) - message(STATUS " GP_RPATH_DIR='${GP_RPATH_DIR}'") - - message(STATUS "fixup_bundle: preparing...") - get_bundle_keys("${app}" "${libs}" "${dirs}" keys) - - message(STATUS "fixup_bundle: copying...") - list(LENGTH keys n) - math(EXPR n ${n}*2) - - set(i 0) - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(${${key}_COPYFLAG}) - message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") - else() - message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") - endif() - - set(show_status 0) - if(show_status) - message(STATUS "key='${key}'") - message(STATUS "item='${${key}_ITEM}'") - message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") - message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") - message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") - message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") - message(STATUS "copyflag='${${key}_COPYFLAG}'") - message(STATUS "") - endif() - - if(${${key}_COPYFLAG}) - set(item "${${key}_ITEM}") - if(item MATCHES "[^/]+\\.framework/") - copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - else() - copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - endif() - endif() - endforeach() - - message(STATUS "fixup_bundle: fixing...") - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(APPLE) - message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") - fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") - else() - message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") - endif() - endforeach() - - message(STATUS "fixup_bundle: cleaning up...") - clear_bundle_keys(keys) - - message(STATUS "fixup_bundle: verifying...") - verify_app("${app}") - else() - message(SEND_ERROR "error: fixup_bundle: not a valid bundle") - endif() - - message(STATUS "fixup_bundle: done") -endfunction() - - -function(copy_and_fixup_bundle src dst libs dirs) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") - fixup_bundle("${dst}" "${libs}" "${dirs}") -endfunction() - - -function(verify_bundle_prerequisites bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - get_bundle_main_executable("${bundle}" main_bundle_exe) - - file(GLOB_RECURSE file_list "${bundle}/*") - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - get_filename_component(exepath "${f}" PATH) - math(EXPR count "${count} + 1") - - message(STATUS "executable file ${count}: ${f}") - - set(prereqs "") - get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") - - # On the Mac, - # "embedded" and "system" prerequisites are fine... anything else means - # the bundle's prerequisites are not verified (i.e., the bundle is not - # really "standalone") - # - # On Windows (and others? Linux/Unix/...?) - # "local" and "system" prereqs are fine... - # - set(external_prereqs "") - - foreach(p ${prereqs}) - set(p_type "") - gp_file_type("${f}" "${p}" p_type) - - if(APPLE) - if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - else() - if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - endif() - endforeach() - - if(external_prereqs) - # Found non-system/somehow-unacceptable prerequisites: - set(result 0) - set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") - endif() - endif() - endforeach() - - if(result) - set(info "Verified ${count} executable files in '${bundle}'") - endif() - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_bundle_symlinks bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - # TODO: implement this function for real... - # Right now, it is just a stub that verifies unconditionally... - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_app app) - set(verified 0) - set(info "") - - get_bundle_and_executable("${app}" bundle executable valid) - - message(STATUS "===========================================================================") - message(STATUS "Analyzing app='${app}'") - message(STATUS "bundle='${bundle}'") - message(STATUS "executable='${executable}'") - message(STATUS "valid='${valid}'") - - # Verify that the bundle does not have any "external" prerequisites: - # - verify_bundle_prerequisites("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - - if(verified) - # Verify that the bundle does not have any symlinks to external files: - # - verify_bundle_symlinks("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - endif() - - if(NOT verified) - message(FATAL_ERROR "error: verify_app failed") - endif() -endfunction() diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index 21f1dbf7d1..d33c6f33bd 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -25,269 +25,3 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The following files are derived from the Slicer project -(https://github.com/Slicer/Slicer), which in turn derived from CMake project (http://cmake.org) and are covered under the licenses below. - -BundleUtilitiesWithRPath.cmake, GetPrerequisitesWithRPath.cmake - -# Slicer - -For more information, please see: - - http://www.slicer.org - -The 3D Slicer license below is a BSD style license, with extensions -to cover contributions and other issues specific to 3D Slicer. - - -3D Slicer Contribution and Software License Agreement ("Agreement") -Version 1.0 (December 20, 2005) - -This Agreement covers contributions to and downloads from the 3D -Slicer project ("Slicer") maintained by The Brigham and Women's -Hospital, Inc. ("Brigham"). Part A of this Agreement applies to -contributions of software and/or data to Slicer (including making -revisions of or additions to code and/or data already in Slicer). Part -B of this Agreement applies to downloads of software and/or data from -Slicer. Part C of this Agreement applies to all transactions with -Slicer. If you distribute Software (as defined below) downloaded from -Slicer, all of the paragraphs of Part B of this Agreement must be -included with and apply to such Software. - -Your contribution of software and/or data to Slicer (including prior -to the date of the first publication of this Agreement, each a -"Contribution") and/or downloading, copying, modifying, displaying, -distributing or use of any software and/or data from Slicer -(collectively, the "Software") constitutes acceptance of all of the -terms and conditions of this Agreement. If you do not agree to such -terms and conditions, you have no right to contribute your -Contribution, or to download, copy, modify, display, distribute or use -the Software. - -PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to -Sublicense ("Contribution Agreement"). - -1. As used in this Contribution Agreement, "you" means the individual - contributing the Contribution to Slicer and the institution or - entity which employs or is otherwise affiliated with such - individual in connection with such Contribution. - -2. This Contribution Agreement applies to all Contributions made to - Slicer, including without limitation Contributions made prior to - the date of first publication of this Agreement. If at any time you - make a Contribution to Slicer, you represent that (i) you are - legally authorized and entitled to make such Contribution and to - grant all licenses granted in this Contribution Agreement with - respect to such Contribution; (ii) if your Contribution includes - any patient data, all such data is de-identified in accordance with - U.S. confidentiality and security laws and requirements, including - but not limited to the Health Insurance Portability and - Accountability Act (HIPAA) and its regulations, and your disclosure - of such data for the purposes contemplated by this Agreement is - properly authorized and in compliance with all applicable laws and - regulations; and (iii) you have preserved in the Contribution all - applicable attributions, copyright notices and licenses for any - third party software or data included in the Contribution. - -3. Except for the licenses granted in this Agreement, you reserve all - right, title and interest in your Contribution. - -4. You hereby grant to Brigham, with the right to sublicense, a - perpetual, worldwide, non-exclusive, no charge, royalty-free, - irrevocable license to use, reproduce, make derivative works of, - display and distribute the Contribution. If your Contribution is - protected by patent, you hereby grant to Brigham, with the right to - sublicense, a perpetual, worldwide, non-exclusive, no-charge, - royalty-free, irrevocable license under your interest in patent - rights covering the Contribution, to make, have made, use, sell and - otherwise transfer your Contribution, alone or in combination with - any other code. - -5. You acknowledge and agree that Brigham may incorporate your - Contribution into Slicer and may make Slicer available to members - of the public on an open source basis under terms substantially in - accordance with the Software License set forth in Part B of this - Agreement. You further acknowledge and agree that Brigham shall - have no liability arising in connection with claims resulting from - your breach of any of the terms of this Agreement. - -6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION - DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN - SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting - example, the GNU General Public License or other so-called - "reciprocal" license that requires any derived work to be licensed - under the GNU General Public License or other "open source - license"). - -PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to -Sublicense ("Software License"). - -1. As used in this Software License, "you" means the individual - downloading and/or using, reproducing, modifying, displaying and/or - distributing the Software and the institution or entity which - employs or is otherwise affiliated with such individual in - connection therewith. The Brigham and Women?s Hospital, - Inc. ("Brigham") hereby grants you, with right to sublicense, with - respect to Brigham's rights in the software, and data, if any, - which is the subject of this Software License (collectively, the - "Software"), a royalty-free, non-exclusive license to use, - reproduce, make derivative works of, display and distribute the - Software, provided that: - -(a) you accept and adhere to all of the terms and conditions of this -Software License; - -(b) in connection with any copy of or sublicense of all or any portion -of the Software, all of the terms and conditions in this Software -License shall appear in and shall apply to such copy and such -sublicense, including without limitation all source and executable -forms and on any user documentation, prefaced with the following -words: "All or portions of this licensed product (such portions are -the "Software") have been obtained under license from The Brigham and -Women's Hospital, Inc. and are subject to the following terms and -conditions:" - -(c) you preserve and maintain all applicable attributions, copyright -notices and licenses included in or applicable to the Software; - -(d) modified versions of the Software must be clearly identified and -marked as such, and must not be misrepresented as being the original -Software; and - -(e) you consider making, but are under no obligation to make, the -source code of any of your modifications to the Software freely -available to others on an open source basis. - -2. The license granted in this Software License includes without - limitation the right to (i) incorporate the Software into - proprietary programs (subject to any restrictions applicable to - such programs), (ii) add your own copyright statement to your - modifications of the Software, and (iii) provide additional or - different license terms and conditions in your sublicenses of - modifications of the Software; provided that in each case your use, - reproduction or distribution of such modifications otherwise - complies with the conditions stated in this Software License. - -3. This Software License does not grant any rights with respect to - third party software, except those rights that Brigham has been - authorized by a third party to grant to you, and accordingly you - are solely responsible for (i) obtaining any permissions from third - parties that you need to use, reproduce, make derivative works of, - display and distribute the Software, and (ii) informing your - sublicensees, including without limitation your end-users, of their - obligations to secure any such required permissions. - -4. The Software has been designed for research purposes only and has - not been reviewed or approved by the Food and Drug Administration - or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL - APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any - commercialization of the Software is at the sole risk of the party - or parties engaged in such commercialization. You further agree to - use, reproduce, make derivative works of, display and distribute - the Software in compliance with all applicable governmental laws, - regulations and orders, including without limitation those relating - to export and import control. - -5. The Software is provided "AS IS" and neither Brigham nor any - contributor to the software (each a "Contributor") shall have any - obligation to provide maintenance, support, updates, enhancements - or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY - DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, - BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR - A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, - INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY - RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS - BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM - EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL - LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, - DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO - INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND - AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS - ARISING THEREFROM. - -6. None of the names, logos or trademarks of Brigham or any of - Brigham's affiliates or any of the Contributors, or any funding - agency, may be used to endorse or promote products produced in - whole or in part by operation of the Software or derived from or - based on the Software without specific prior written permission - from the applicable party. - -7. Any use, reproduction or distribution of the Software which is not - in accordance with this Software License shall automatically revoke - all rights granted to you under this Software License and render - Paragraphs 1 and 2 of this Software License null and void. - -8. This Software License does not grant any rights in or to any - intellectual property owned by Brigham or any Contributor except - those rights expressly granted hereunder. - -PART C. MISCELLANEOUS - -This Agreement shall be governed by and construed in accordance with -the laws of The Commonwealth of Massachusetts without regard to -principles of conflicts of law. This Agreement shall supercede and -replace any license terms that you may have agreed to previously with -respect to Slicer. - -# CMake - -CMake - Cross Platform Makefile Generator -Copyright 2000-2015 Kitware, Inc. -Copyright 2000-2011 Insight Software Consortium -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the names of Kitware, Inc., the Insight Software Consortium, - nor the names of their contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -The above copyright and license notice applies to distributions of -CMake in source and binary form. Some source files contain additional -notices of original copyright by their contributors; see each source -for details. Third-party software packages supplied with CMake under -compatible licenses provide their own copyright notices documented in -corresponding subdirectories. - ------------------------------------------------------------------------------- - -CMake was initially developed by Kitware with the following sponsorship: - - * National Library of Medicine at the National Institutes of Health - as part of the Insight Segmentation and Registration Toolkit (ITK). - - * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel - Visualization Initiative. - - * National Alliance for Medical Image Computing (NAMIC) is funded by the - National Institutes of Health through the NIH Roadmap for Medical Research, - Grant U54 EB005149. - - * Kitware, Inc. diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake deleted file mode 100644 index 5b5751ead3..0000000000 --- a/cmake/GetPrerequisitesWithRPath.cmake +++ /dev/null @@ -1,990 +0,0 @@ -# - Functions to analyze and list executable file prerequisites. -# This module provides functions to list the .dll, .dylib or .so -# files that an executable or shared library file depends on. (Its -# prerequisites.) -# -# It uses various tools to obtain the list of required shared library files: -# dumpbin (Windows) -# objdump (MinGW on Windows) -# ldd (Linux/Unix) -# otool (Mac OSX) -# The following functions are provided by this module: -# get_prerequisites -# list_prerequisites -# list_prerequisites_by_glob -# gp_append_unique -# is_file_executable -# gp_item_default_embedded_path -# (projects can override with gp_item_default_embedded_path_override) -# gp_resolve_item -# (projects can override with gp_resolve_item_override) -# gp_resolve_embedded_item -# (projects can override with gp_resolve_embedded_item_override) -# gp_resolved_file_type -# (projects can override with gp_resolved_file_type_override) -# gp_file_type -# Requires CMake 2.6 or greater because it uses function, break, return and -# PARENT_SCOPE. -# -# GET_PREREQUISITES( -# ) -# Get the list of shared library files required by . The list in -# the variable named should be empty on first entry to -# this function. On exit, will contain the list of -# required shared library files. -# -# is the full path to an executable file. is the -# name of a CMake variable to contain the results. must be 0 -# or 1 indicating whether to include or exclude "system" prerequisites. If -# is set to 1 all prerequisites will be found recursively, if set to -# 0 only direct prerequisites are listed. is the path to the top -# level executable used for @executable_path replacment on the Mac. is -# a list of paths where libraries might be found: these paths are searched -# first when a target without any path info is given. Then standard system -# locations are also searched: PATH, Framework locations, /usr/lib... -# -# LIST_PREREQUISITES( [ [ []]]) -# Print a message listing the prerequisites of . -# -# is the name of a shared library or executable target or the full -# path to a shared library or executable file. If is set to 1 all -# prerequisites will be found recursively, if set to 0 only direct -# prerequisites are listed. must be 0 or 1 indicating whether -# to include or exclude "system" prerequisites. With set to 0 only -# the full path names of the prerequisites are printed, set to 1 extra -# informatin will be displayed. -# -# LIST_PREREQUISITES_BY_GLOB( ) -# Print the prerequisites of shared library and executable files matching a -# globbing pattern. is GLOB or GLOB_RECURSE and is a -# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve -# a list of matching files. If a matching file is executable, its prerequisites -# are listed. -# -# Any additional (optional) arguments provided are passed along as the -# optional arguments to the list_prerequisites calls. -# -# GP_APPEND_UNIQUE( ) -# Append to the list variable only if the value is not -# already in the list. -# -# IS_FILE_EXECUTABLE( ) -# Return 1 in if is a binary executable, 0 otherwise. -# -# GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX can be set to a regular expression used -# to give a hint to identify more quickly if a given file is an executable or not. -# This is particularly useful on unix platform where it can avoid a lot of -# time-consuming call to "file" external process. For packages bundling hundreds -# of libraries, executables, resources and data, it largely speeds up the function -# "get_bundle_all_executables". -# On unix, a convenient command line allowing to collect recursively all file extensions -# useful to generate a regular expression like "\\.(dylib|py|pyc|so)$" is: -# find . -type f -name '*.*' | sed 's@.*/.*\.@@' | sort | uniq | tr "\\n" "|" -# -# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) -# Return the path that others should refer to the item by when the item -# is embedded inside a bundle. -# -# Override on a per-project basis by providing a project-specific -# gp_item_default_embedded_path_override function. -# -# GP_RESOLVE_ITEM( ) -# Resolve an item into an existing full path file. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_item_override function. -# -# GP_RESOLVE_EMBEDDED_ITEM( ) -# Resolve an embedded item into the full path within the full path. Since the item can be -# copied later, it doesn't have to exist when calling this function. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_embedded_item_override function. -# -# If GP_RPATH_DIR variable is set then item matching '@rpath' are -# resolved using the provided directory. Currently setting this variable -# has an effect only on MacOSX when fixing up application bundle. The directory -# are also assumed to be located within the application bundle. It is -# usually the directory passed to the 'rpath' linker option. -# -# GP_RESOLVED_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Use and if necessary to resolve non-absolute -# values -- but only for non-embedded items. -# -# Possible types are: -# system -# local -# embedded -# other -# Override on a per-project basis by providing a project-specific -# gp_resolved_file_type_override function. -# -# GP_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Possible types are: -# system -# local -# embedded -# other - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org -# -# Redistribution AND use is allowed according to the terms of the -# BSD-style license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -function(gp_append_unique list_var value) - set(contains 0) - - foreach(item ${${list_var}}) - if("${item}" STREQUAL "${value}") - set(contains 1) - break() - endif() - endforeach() - - if(NOT contains) - set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) - endif() -endfunction() - - -function(is_file_executable file result_var) - # - # A file is not executable until proven otherwise: - # - set(${result_var} 0 PARENT_SCOPE) - - get_filename_component(file_full "${file}" ABSOLUTE) - string(TOLOWER "${file_full}" file_full_lower) - - # If file name ends in .exe on Windows, *assume* executable: - # - if(WIN32 AND NOT UNIX) - if("${file_full_lower}" MATCHES "\\.exe$") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - # A clause could be added here that uses output or return value of dumpbin - # to determine ${result_var}. In 99%+? practical cases, the exe name - # match will be sufficient... - # - endif() - - # Use the information returned from the Unix shell command "file" to - # determine if ${file_full} should be considered an executable file... - # - # If the file command's output contains "executable" and does *not* contain - # "text" then it is likely an executable suitable for prerequisite analysis - # via the get_prerequisites macro. - # - if(UNIX) - - if(NOT "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}" STREQUAL "") - if(${file_full} MATCHES "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}") - set(${result_var} 0 PARENT_SCOPE) - return() - endif() - endif() - - if(NOT file_cmd) - find_program(file_cmd "file") - mark_as_advanced(file_cmd) - endif() - - if(file_cmd) - execute_process(COMMAND "${file_cmd}" "${file_full}" - OUTPUT_VARIABLE file_ov - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Replace the name of the file in the output with a placeholder token - # (the string " _file_full_ ") so that just in case the path name of - # the file contains the word "text" or "executable" we are not fooled - # into thinking "the wrong thing" because the file name matches the - # other 'file' command output we are looking for... - # - string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") - string(TOLOWER "${file_ov}" file_ov) - - #message(STATUS "file_ov='${file_ov}'") - if("${file_ov}" MATCHES "executable") - #message(STATUS "executable!") - if("${file_ov}" MATCHES "text") - #message(STATUS "but text, so *not* a binary executable!") - else() - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - endif() - - # Also detect position independent executables on Linux, - # where "file" gives "shared object ... (uses shared libraries)" - if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - else() - message(STATUS "warning: No 'file' command, skipping execute_process...") - endif() - endif() -endfunction() - - -function(gp_item_default_embedded_path item default_embedded_path_var) - - # On Windows and Linux, "embed" prerequisites in the same directory - # as the executable by default: - # - set(path "@executable_path") - set(overridden 0) - - # On the Mac, relative to the executable depending on the type - # of the thing we are embedding: - # - if(APPLE) - # - # The assumption here is that all executables in the bundle will be - # in same-level-directories inside the bundle. The parent directory - # of an executable inside the bundle should be MacOS or a sibling of - # MacOS and all embedded paths returned from here will begin with - # "@executable_path/../" and will work from all executables in all - # such same-level-directories inside the bundle. - # - - # By default, embed things right next to the main bundle executable: - # - set(path "@executable_path/../../Contents/MacOS") - - # Embed .dylibs right next to the main bundle executable: - # - if(item MATCHES "\\.dylib$") - set(path "@executable_path/../MacOS") - set(overridden 1) - endif() - - # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): - # - if(NOT overridden) - if(item MATCHES "[^/]+\\.framework/") - set(path "@executable_path/../Frameworks") - set(overridden 1) - endif() - endif() - endif() - - # Provide a hook so that projects can override the default embedded location - # of any given library by whatever logic they choose: - # - if(COMMAND gp_item_default_embedded_path_override) - gp_item_default_embedded_path_override("${item}" path) - endif() - - set(${default_embedded_path_var} "${path}" PARENT_SCOPE) -endfunction() - - -function(gp_resolve_item context item exepath dirs resolved_item_var) - set(resolved 0) - set(resolved_item "${item}") - - # Is it already resolved? - # - if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") - set(resolved 1) - endif() - - if(NOT resolved) - if(item MATCHES "@executable_path") - # - # @executable_path references are assumed relative to exepath - # - string(REPLACE "@executable_path" "${exepath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@loader_path") - # - # @loader_path references are assumed relative to the - # PATH of the given "context" (presumably another library) - # - get_filename_component(contextpath "${context}" PATH) - string(REPLACE "@loader_path" "${contextpath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@rpath") - # - # @rpath references are relative to the paths built into the binaries with -rpath - # We handle this case like we do for other Unixes. - # - # Two cases of item resolution are considered: - # - # (1) item has been copied into the bundle - # - # (2) item has NOT been copied into the bundle: Since the item can exist in a build or - # install tree outside of the bundle, the item is resolved using its name and the - # passed list of directories. - # - string(REPLACE "@rpath/" "" norpath_item "${item}") - - set(ri "ri-NOTFOUND") - if(EXISTS ${GP_RPATH_DIR}/${norpath_item}) - set(ri ${GP_RPATH_DIR}/${norpath_item}) - set(_msg "'find_file' in GP_RPATH_DIR (${ri})") - else() - get_filename_component(norpath_item_name ${norpath_item} NAME) - find_file(ri "${norpath_item_name}" ${exepath} ${dirs} NO_DEFAULT_PATH) - set(_msg "'find_file' in exepath/dirs (${ri})") - endif() - if(ri) - #message(STATUS "info: ${_msg}") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - - endif() - endif() - - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) - find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) - if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - - if(NOT resolved) - if(item MATCHES "[^/]+\\.framework/") - set(fw "fw-NOTFOUND") - find_file(fw "${item}" - "~/Library/Frameworks" - "/Library/Frameworks" - "/System/Library/Frameworks" - ) - if(fw) - #message(STATUS "info: 'find_file' found framework (${fw})") - set(resolved 1) - set(resolved_item "${fw}") - set(fw "fw-NOTFOUND") - endif() - endif() - endif() - - # Using find_program on Windows will find dll files that are in the PATH. - # (Converting simple file names into full path names if found.) - # - if(WIN32 AND NOT UNIX) - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) - find_program(ri "${item}" PATHS "${exepath};${dirs}") - if(ri) - #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - endif() - - # Provide a hook so that projects can override item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_item_override) - gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) - endif() - - if(NOT resolved) - message(STATUS " -warning: cannot resolve item '${item}' - - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? -") -# message(STATUS " -#****************************************************************************** -#warning: cannot resolve item '${item}' -# -# possible problems: -# need more directories? -# need to use InstallRequiredSystemLibraries? -# run in install tree instead of build tree? -# -# context='${context}' -# item='${item}' -# exepath='${exepath}' -# dirs='${dirs}' -# resolved_item_var='${resolved_item_var}' -#****************************************************************************** -#") - endif() - - set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) -endfunction() - -function(gp_resolve_embedded_item context embedded_item exepath resolved_embedded_item_var) - #message(STATUS "**") - set(resolved 0) - set(resolved_embedded_item "${embedded_item}") - - if(embedded_item MATCHES "@executable_path") - string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") - set(resolved 1) - endif() - if(EXISTS "${GP_RPATH_DIR}" AND embedded_item MATCHES "@rpath") - string(REPLACE "@rpath" "${GP_RPATH_DIR}" resolved_embedded_item "${embedded_item}") - set(resolved 1) - endif() - - # Provide a hook so that projects can override embedded item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_embedded_item_override) - gp_resolve_embedded_item_override( - "${context}" "${embedded_item}" "${exepath}" resolved_embedded_item resolved) - endif() - - if(NOT resolved) - message(STATUS " -warning: cannot resolve embedded item '${embedded_item}' - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? - - context='${context}' - embedded_item='${embedded_item}' - GP_RPATH_DIR='${GP_RPATH_DIR}' - exepath='${exepath}' - resolved_embedded_item_var='${resolved_embedded_item_var}' -") - endif() - - set(${resolved_embedded_item_var} "${resolved_embedded_item}" PARENT_SCOPE) -endfunction() - -function(gp_resolved_file_type original_file file exepath dirs type_var) - #message(STATUS "**") - - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") - endif() - - set(is_embedded 0) - set(is_local 0) - set(is_system 0) - - set(resolved_file "${file}") - - if("${file}" MATCHES "^@(executable_|loader_|r)path") - set(is_embedded 1) - endif() - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${file}") - gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) - endif() - - string(TOLOWER "${original_file}" original_lower) - string(TOLOWER "${resolved_file}" lower) - - if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/)") - set(is_system 1) - endif() - endif() - - if(APPLE) - if(resolved_file MATCHES "^(/System/Library/|/usr/lib/|/opt/X11/)") - set(is_system 1) - endif() - endif() - - if(WIN32) - string(TOLOWER "$ENV{SystemRoot}" sysroot) - string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") - - string(TOLOWER "$ENV{windir}" windir) - string(REGEX REPLACE "\\\\" "/" windir "${windir}") - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - - if(UNIX) - # if cygwin, we can get the properly formed windows paths from cygpath - find_program(CYGPATH_EXECUTABLE cygpath) - - if(CYGPATH_EXECUTABLE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W - OUTPUT_VARIABLE env_windir - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S - OUTPUT_VARIABLE env_sysdir - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(TOLOWER "${env_windir}" windir) - string(TOLOWER "${env_sysdir}" sysroot) - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - endif() - endif() - endif() - - if(NOT is_system) - get_filename_component(original_path "${original_lower}" PATH) - get_filename_component(path "${lower}" PATH) - if("${original_path}" STREQUAL "${path}") - set(is_local 1) - else() - string(LENGTH "${original_path}/" original_length) - string(LENGTH "${lower}" path_length) - if(${path_length} GREATER ${original_length}) - string(SUBSTRING "${lower}" 0 ${original_length} path) - if("${original_path}/" STREQUAL "${path}") - set(is_embedded 1) - endif() - endif() - endif() - endif() - endif() - - # Return type string based on computed booleans: - # - set(type "other") - - if(is_system) - set(type "system") - elseif(is_embedded) - set(type "embedded") - elseif(is_local) - set(type "local") - endif() - - #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") - #message(STATUS " type: '${type}'") - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${resolved_file}") - if(lower MATCHES "^msvc[^/]+dll" AND is_system) - message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") - else() - message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") - endif() - endif() - endif() - - # Provide a hook so that projects can override the decision on whether a - # library belongs to the system or not by whatever logic they choose: - # - if(COMMAND gp_resolved_file_type_override) - gp_resolved_file_type_override("${resolved_file}" type) - endif() - - set(${type_var} "${type}" PARENT_SCOPE) - - #message(STATUS "**") -endfunction() - - -function(gp_file_type original_file file type_var) - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") - endif() - - get_filename_component(exepath "${original_file}" PATH) - - set(type "") - gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) - - set(${type_var} "${type}" PARENT_SCOPE) -endfunction() - - -function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) - set(verbose 0) - set(eol_char "E") - - if(NOT IS_ABSOLUTE "${target}") - message("warning: target '${target}' is not absolute...") - endif() - - if(NOT EXISTS "${target}") - message("warning: target '${target}' does not exist...") - endif() - - set(gp_cmd_paths ${gp_cmd_paths} - "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" - "/usr/local/bin" - "/usr/bin" - ) - - # - # - # Try to choose the right tool by default. Caller can set gp_tool prior to - # calling this function to force using a different tool. - # - if("${gp_tool}" STREQUAL "") - set(gp_tool "ldd") - - if(APPLE) - set(gp_tool "otool") - endif() - - if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! - find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) - if(gp_dumpbin) - set(gp_tool "dumpbin") - else() # Try harder. Maybe we're on MinGW - set(gp_tool "objdump") - endif() - endif() - endif() - - find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) - - if(NOT gp_cmd) - message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") - return() - endif() - - set(gp_tool_known 0) - - if("${gp_tool}" STREQUAL "ldd") - set(gp_cmd_args "") - set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") - set(gp_regex_error "not found${eol_char}$") - set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "otool") - set(gp_cmd_args "-L") - set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 3) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "dumpbin") - set(gp_cmd_args "/dependents") - set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. - endif() - - if("${gp_tool}" STREQUAL "objdump") - set(gp_cmd_args "-p") - set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if(NOT gp_tool_known) - message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") - message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") - message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") - return() - endif() - - - if("${gp_tool}" STREQUAL "dumpbin") - # When running dumpbin, it also needs the "Common7/IDE" directory in the - # PATH. It will already be in the PATH if being run from a Visual Studio - # command prompt. Add it to the PATH here in case we are running from a - # different command prompt. - # - get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) - get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) - # Use cmake paths as a user may have a PATH element ending with a backslash. - # This will escape the list delimiter and create havoc! - if(EXISTS "${gp_cmd_dlls_dir}") - # only add to the path if it is not already in the path - set(gp_found_cmd_dlls_dir 0) - file(TO_CMAKE_PATH "$ENV{PATH}" env_path) - foreach(gp_env_path_element ${env_path}) - if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") - set(gp_found_cmd_dlls_dir 1) - endif() - endforeach() - - if(NOT gp_found_cmd_dlls_dir) - file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) - set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") - endif() - endif() - endif() - # - # - - if("${gp_tool}" STREQUAL "ldd") - set(old_ld_env "$ENV{LD_LIBRARY_PATH}") - foreach(dir ${exepath} ${dirs}) - set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") - endforeach() - endif() - - - # Track new prerequisites at each new level of recursion. Start with an - # empty list at each level: - # - set(unseen_prereqs) - - # Run gp_cmd on the target: - # - execute_process( - COMMAND ${gp_cmd} ${gp_cmd_args} ${target} - OUTPUT_VARIABLE gp_cmd_ov - ) - - if("${gp_tool}" STREQUAL "ldd") - set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") - endif() - - if(verbose) - message(STATUS "") - message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") - message(STATUS "") - endif() - - get_filename_component(target_dir "${target}" PATH) - - # Convert to a list of lines: - # - string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") - string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") - - # check for install id and remove it from list, since otool -L can include a - # reference to itself - set(gp_install_id) - if("${gp_tool}" STREQUAL "otool") - execute_process( - COMMAND otool -D ${target} - OUTPUT_VARIABLE gp_install_id_ov - ) - # second line is install name - string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") - if(gp_install_id) - # trim - string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") - #message("INSTALL ID is \"${gp_install_id}\"") - endif() - endif() - - # Analyze each line for file names that match the regular expression: - # - foreach(candidate ${candidates}) - if("${candidate}" MATCHES "${gp_regex}") - - # Extract information from each candidate: - if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") - string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") - else() - string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") - endif() - - if(gp_regex_cmp_count GREATER 1) - string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") - endif() - - if(gp_regex_cmp_count GREATER 2) - string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") - endif() - - # Use the raw_item as the list entries returned by this function. Use the - # gp_resolve_item function to resolve it to an actual full path file if - # necessary. - # - set(item "${raw_item}") - - # Add each item unless it is excluded: - # - set(add_item 1) - - if("${item}" STREQUAL "${gp_install_id}") - set(add_item 0) - endif() - - if(add_item AND ${exclude_system}) - set(type "") - gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) - - if("${type}" STREQUAL "system") - set(add_item 0) - endif() - endif() - - if(add_item) - list(LENGTH ${prerequisites_var} list_length_before_append) - gp_append_unique(${prerequisites_var} "${item}") - list(LENGTH ${prerequisites_var} list_length_after_append) - - if(${recurse}) - # If item was really added, this is the first time we have seen it. - # Add it to unseen_prereqs so that we can recursively add *its* - # prerequisites... - # - # But first: resolve its name to an absolute full path name such - # that the analysis tools can simply accept it as input. - # - if(NOT list_length_before_append EQUAL list_length_after_append) - gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) - set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") - endif() - endif() - endif() - else() - if(verbose) - message(STATUS "ignoring non-matching line: '${candidate}'") - endif() - endif() - endforeach() - - list(LENGTH ${prerequisites_var} prerequisites_var_length) - if(prerequisites_var_length GREATER 0) - list(SORT ${prerequisites_var}) - endif() - if(${recurse}) - set(more_inputs ${unseen_prereqs}) - foreach(input ${more_inputs}) - get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") - endforeach() - endif() - - set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) -endfunction() - - -function(list_prerequisites target) - if("${ARGV1}" STREQUAL "") - set(all 1) - else() - set(all "${ARGV1}") - endif() - - if("${ARGV2}" STREQUAL "") - set(exclude_system 0) - else() - set(exclude_system "${ARGV2}") - endif() - - if("${ARGV3}" STREQUAL "") - set(verbose 0) - else() - set(verbose "${ARGV3}") - endif() - - set(count 0) - set(count_str "") - set(print_count "${verbose}") - set(print_prerequisite_type "${verbose}") - set(print_target "${verbose}") - set(type_str "") - - get_filename_component(exepath "${target}" PATH) - - set(prereqs "") - get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") - - if(print_target) - message(STATUS "File '${target}' depends on:") - endif() - - foreach(d ${prereqs}) - math(EXPR count "${count} + 1") - - if(print_count) - set(count_str "${count}. ") - endif() - - if(print_prerequisite_type) - gp_file_type("${target}" "${d}" type) - set(type_str " (${type})") - endif() - - message(STATUS "${count_str}${d}${type_str}") - endforeach() -endfunction() - - -function(list_prerequisites_by_glob glob_arg glob_exp) - message(STATUS "=============================================================================") - message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") - message(STATUS "") - file(${glob_arg} file_list ${glob_exp}) - foreach(f ${file_list}) - is_file_executable("${f}" is_f_executable) - if(is_f_executable) - message(STATUS "=============================================================================") - list_prerequisites("${f}" ${ARGN}) - message(STATUS "") - endif() - endforeach() -endfunction() From d5aeb354495b9bfc834ebbc463e5ed0a14ec04f9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 01:19:56 +0100 Subject: [PATCH 1358/1812] OS X: use link path for packaging to allow CMake infer library search dirs for @rpath resolving --- CMakeLists.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e218923bf9..5c996e3b47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,8 +297,7 @@ if (APPLE) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") if (OPENMW_OSX_DEPLOYMENT) - SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() else (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") @@ -787,8 +786,6 @@ if (APPLE) install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) - set(DIRS "${CMAKE_PREFIX_PATH}/lib") - install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) @@ -798,8 +795,8 @@ if (APPLE) endfunction() cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\") + fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") " COMPONENT Runtime) include(CPack) endif (APPLE) From 63c47a78d6edc8d7519b740271cceaf90ec6e5ab Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 13 Nov 2015 20:20:34 +0100 Subject: [PATCH 1359/1812] OS X: fixup Qt plugin during packaging --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c996e3b47..0f168be169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,6 +786,9 @@ if (APPLE) install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) if (\${item} MATCHES ${OSG_PLUGIN_PREFIX_DIR}) From d2a417580446deec3c465875ae9f85a2d455be1d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 14 Nov 2015 16:02:42 +0100 Subject: [PATCH 1360/1812] Add FFMPEG to include path for OpenMW I'm a bit confused; `mwsound/ffmpeg_decoder.hpp/cpp` requires FFMPEG headers to compile, how did this work in the first place? --- apps/openmw/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 887eedebbf..bf21805d00 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -113,7 +113,10 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. -include_directories(${SOUND_INPUT_INCLUDES}) +include_directories( + ${SOUND_INPUT_INCLUDES} + ${FFMPEG_INCLUDE_DIRS} +) target_link_libraries(openmw ${OPENSCENEGRAPH_LIBRARIES} From 0220e82259bd799e93eb6ae5f2288ba4c71fcd3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:17:22 +0100 Subject: [PATCH 1361/1812] Remove unused SOUND_INPUT_INCLUDES cmake variable. --- CMakeLists.txt | 2 -- apps/openmw/CMakeLists.txt | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b88f6219..08608972b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,8 +115,6 @@ endif() # Required for building the FFmpeg headers add_definitions(-D__STDC_CONSTANT_MACROS) -set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) - # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) if(USE_SYSTEM_TINYXML) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bf21805d00..59a523023f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -114,7 +114,6 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. include_directories( - ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS} ) @@ -125,7 +124,7 @@ target_link_libraries(openmw ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPENAL_LIBRARY} - ${SOUND_INPUT_LIBRARY} + ${FFMPEG_LIBRARIES} ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} From af4923577b4f97ef4f5c6e89c58bf4badf3228ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 16:04:52 +0100 Subject: [PATCH 1362/1812] Fix double writing of Dialogue NAME in OpenCS --- apps/opencs/model/doc/savingstages.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 16a91c8651..db38c4779b 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -131,14 +131,12 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message && topic.mState != CSMWorld::RecordBase::State_ModifiedOnly) { mState.getWriter().startRecord (topic.mBase.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mBase.mId); topic.mBase.save (mState.getWriter(), topic.mState == CSMWorld::RecordBase::State_Deleted); mState.getWriter().endRecord (topic.mBase.sRecordId); } else { mState.getWriter().startRecord (topic.mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); topic.mModified.save (mState.getWriter(), topic.mState == CSMWorld::RecordBase::State_Deleted); mState.getWriter().endRecord (topic.mModified.sRecordId); } From 8b7bdcd127ad696a8e64070ffcc864fdf32ae75d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 21:32:34 +0100 Subject: [PATCH 1363/1812] Fix the global map overlay viewport (Bug #3018) --- apps/openmw/mwrender/globalmap.cpp | 5 +++-- apps/openmw/mwrender/globalmap.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index f91f7674f8..b4015b7094 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -251,6 +251,7 @@ namespace MWRender camera->setProjectionMatrix(osg::Matrix::identity()); camera->setProjectionResizePolicy(osg::Camera::FIXED); camera->setRenderOrder(osg::Camera::PRE_RENDER); + y = mHeight - y - height; // convert top-left origin to bottom-left camera->setViewport(x, y, width, height); if (clear) @@ -311,12 +312,12 @@ namespace MWRender return; int originX = (cellX - mMinX) * mCellSize; - int originY = (cellY - mMinY) * mCellSize; + int originY = (cellY - mMinY + 1) * mCellSize; // +1 because we want the top left corner of the cell, not the bottom left if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; - requestOverlayTextureUpdate(originX, originY, mCellSize, mCellSize, localMapTexture, false, true); + requestOverlayTextureUpdate(originX, mHeight - originY, mCellSize, mCellSize, localMapTexture, false, true); } void GlobalMap::clear() diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 91c17c06f1..07ae7cdae7 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -70,7 +70,7 @@ namespace MWRender private: /** * Request rendering a 2d quad onto mOverlayTexture. - * x, y, width and height are the destination coordinates. + * x, y, width and height are the destination coordinates (top-left coordinate origin) * @param cpuCopy copy the resulting render onto mOverlayImage as well? */ void requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr texture, bool clear, bool cpuCopy, From 0f347eccbf43197dbdd404dbbef061ca854281b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Nov 2015 21:36:41 +0100 Subject: [PATCH 1364/1812] Flip the origin of global map texture Now it's consistent with the overlay texture. --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2df1c8f3c2..0ebb595ddf 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -746,7 +746,7 @@ namespace MWGui mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); - mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index b4015b7094..9e8a545f85 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -165,7 +165,7 @@ namespace MWRender int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; - int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); + int texelY = (y-mMinY) * mCellSize + cellY; unsigned char r,g,b; From 71d9e7dc523aadfda49993db619c3060b4504e84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 16:29:59 +0100 Subject: [PATCH 1365/1812] Read Ambient Loop Sound ID and Rain Loop Sound ID from the INI file --- apps/openmw/mwworld/weather.cpp | 29 +++++++++++++++++++---------- apps/openmw/mwworld/weather.hpp | 2 -- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 24b45fcea6..37f5e094de 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -103,7 +103,6 @@ Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, float rainSpeed, - const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), @@ -130,7 +129,6 @@ Weather::Weather(const std::string& name, , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) - , mAmbientLoopSoundID(ambientLoopSoundID) , mIsStorm(mWindSpeed > stormWindSpeed) , mRainSpeed(rainSpeed) , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) @@ -148,6 +146,18 @@ Weather::Weather(const std::string& name, mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); mThunderSoundID[3] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_3"); + + // TODO: support weathers that have both "Ambient Loop Sound ID" and "Rain Loop Sound ID", need to play both sounds at the same time. + + if (!mRainEffect.empty()) // NOTE: in vanilla, the weathers with rain seem to be hardcoded; changing Using_Precip has no effect + { + mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Rain_Loop_Sound_ID"); + if (mAmbientLoopSoundID.empty()) // default to "rain" if not set + mAmbientLoopSoundID = "rain"; + } + else + mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Ambient_Loop_Sound_ID"); + /* Unhandled: Rain Diameter=600 ? @@ -528,12 +538,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo addWeather("Cloudy", fallback); // 1 addWeather("Foggy", fallback); // 2 addWeather("Overcast", fallback); // 3 - addWeather("Rain", fallback, "rain"); // 4 - addWeather("Thunderstorm", fallback, "rain heavy"); // 5 - addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6 - addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7 - addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8 - addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9 + addWeather("Rain", fallback); // 4 + addWeather("Thunderstorm", fallback); // 5 + addWeather("Ashstorm", fallback, "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) @@ -852,12 +862,11 @@ void WeatherManager::clear() inline void WeatherManager::addWeather(const std::string& name, const MWWorld::Fallback& fallback, - const std::string& ambientLoopSoundID, const std::string& particleEffect) { static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); - Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, particleEffect); mWeatherSettings.push_back(weather); } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4a78350fe4..a5627a507c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -69,7 +69,6 @@ namespace MWWorld const MWWorld::Fallback& fallback, float stormWindSpeed, float rainSpeed, - const std::string& ambientLoopSoundID, const std::string& particleEffect); std::string mCloudTexture; @@ -290,7 +289,6 @@ namespace MWWorld void addWeather(const std::string& name, const MWWorld::Fallback& fallback, - const std::string& ambientLoopSoundID = "", const std::string& particleEffect = ""); void importRegions(); From 52901ec10cd0d15731de93be3e46d49eec8fcd05 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 15:11:20 +0100 Subject: [PATCH 1366/1812] Do not create terrain geodes when built with OSG 3.4 --- components/terrain/terraingrid.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 732936aa99..ceb39a24b0 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -126,10 +127,6 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu osg::BoundingBox bounds(min, max); geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); - - std::vector layerList; std::vector > blendmaps; mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); @@ -169,11 +166,20 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu effect->addCullCallback(new SceneUtil::LightListCallback); transform->addChild(effect); - effect->addChild(geode); + +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + osg::Node* toAttach = geometry.get(); +#else + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); + osg::Node* toAttach = geode.get(); +#endif + + effect->addChild(toAttach); if (mIncrementalCompileOperation) { - mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(toAttach); mIncrementalCompileOperation->add(textureCompileDummy); } From 21e25f4756df2bb1ddbf24fc7d8747ae76defe9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 20:03:45 +0100 Subject: [PATCH 1367/1812] Use the traversalNumber as frame number --- components/nifosg/nifloader.cpp | 9 ++++----- components/sceneutil/lightmanager.cpp | 4 ++-- components/sceneutil/riggeometry.cpp | 4 ++-- components/sceneutil/skeleton.cpp | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 73b72811a5..21bf8a0962 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -100,14 +100,13 @@ namespace virtual void traverse(osg::NodeVisitor& nv) { - const osg::FrameStamp* stamp = nv.getFrameStamp(); - if (!stamp || nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) osg::Group::traverse(nv); else { for (unsigned int i=0; igetFrameNumber()%2) + if (i%2 == nv.getTraversalNumber()%2) getChild(i)->accept(nv); } } @@ -182,9 +181,9 @@ namespace if (!geom) return false; - if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber == nv->getTraversalNumber()) return false; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); geom->transformSoftwareMethod(); return false; diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index dc6da73a66..d3e11050d7 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -294,9 +294,9 @@ namespace SceneUtil // update light list if necessary // makes sure we don't update it more than once per frame when rendering with multiple cameras - if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber != nv->getTraversalNumber()) { - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); // Don't use Camera::getViewMatrix, that one might be relative to another camera! const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index bd3d613a31..023ac12d5d 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -218,9 +218,9 @@ void RigGeometry::update(osg::NodeVisitor* nv) if (!mSkeleton->getActive() && mLastFrameNumber != 0) return; - if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber()) + if (mLastFrameNumber == nv->getTraversalNumber()) return; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); mSkeleton->updateBoneMatrices(nv); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 5c2af4397e..d66131b4e9 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -104,10 +104,10 @@ Bone* Skeleton::getBone(const std::string &name) void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) { - if (nv->getFrameStamp()->getFrameNumber() != mLastFrameNumber) + if (nv->getTraversalNumber() != mLastFrameNumber) mNeedToUpdateBoneMatrices = true; - mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + mLastFrameNumber = nv->getTraversalNumber(); if (mNeedToUpdateBoneMatrices) { From eb2f16d682b692ade3ef97307ab534ab07ea9b52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 23:26:43 +0100 Subject: [PATCH 1368/1812] Support for loading .osg mesh format --- apps/opencs/model/world/resourcesmanager.cpp | 4 +- apps/openmw/mwphysics/physicssystem.cpp | 7 +- apps/openmw/mwrender/animation.cpp | 2 +- components/nifbullet/bulletshapemanager.cpp | 7 ++ components/resource/scenemanager.cpp | 80 +++++++++++++++++++- components/resource/texturemanager.cpp | 51 +++++++++++++ components/resource/texturemanager.hpp | 4 +- 7 files changed, 145 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 2ec661cb1a..016799be35 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -19,7 +19,9 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) mVFS = vfs; mResources.clear(); - static const char * const sMeshTypes[] = { "nif", 0 }; + // maybe we could go over the osgDB::Registry to list all supported node formats + + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 55144afe75..f5e9ce2fa6 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -975,7 +975,7 @@ namespace MWPhysics void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); - if (!shapeInstance->getCollisionShape()) + if (!shapeInstance || !shapeInstance->getCollisionShape()) return; Object *obj = new Object(ptr, shapeInstance); @@ -1114,9 +1114,10 @@ namespace MWPhysics } } - void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) - { + void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + if (!shapeInstance) + return; Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld); mActors.insert(std::make_pair(ptr, actor)); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 55a47d4b69..6ef6fab239 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ namespace MWRender animsrc.reset(new AnimSource); animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); - if (animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) + if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) return; for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 6acfdd4085..23b461953b 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -30,6 +30,13 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: Files::IStreamPtr file = mVFS->get(normalized); // TODO: add support for non-NIF formats + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + + if (ext != "nif") + return NULL; BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index eb4a4992de..3717ecb16d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -20,6 +20,8 @@ #include #include +#include "texturemanager.hpp" + namespace { @@ -112,6 +114,73 @@ namespace Resource SceneManager::~SceneManager() { // this has to be defined in the .cpp file as we can't delete incomplete types + + } + + /// @brief Callback to read image files from the VFS. + class ImageReadCallback : public osgDB::ReadFileCallback + { + public: + ImageReadCallback(Resource::TextureManager* textureMgr) + : mTextureManager(textureMgr) + { + } + + virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) + { + try + { + mTextureManager->getTexture2D(filename, osg::Texture::CLAMP_TO_EDGE, osg::Texture::CLAMP_TO_EDGE); + return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); + } + catch (std::exception& e) + { + return osgDB::ReaderWriter::ReadResult(e.what()); + } + } + + private: + Resource::TextureManager* mTextureManager; + }; + + std::string getFileExtension(const std::string& file) + { + size_t extPos = file.find_last_of('.'); + if (extPos != std::string::npos && extPos+1 < file.size()) + return file.substr(extPos+1); + return std::string(); + } + + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr) + { + std::string ext = getFileExtension(normalizedFilename); + if (ext == "nif") + return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr); + else + { + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::stringstream errormsg; + errormsg << "Error loading " << normalizedFilename << ": no readerwriter for '" << ext << "' found" << std::endl; + throw std::runtime_error(errormsg.str()); + } + + osg::ref_ptr options (new osgDB::Options); + // Set a ReadFileCallback so that image files referenced in the model are read from our virtual file system instead of the osgDB. + // Note, for some formats (.obj/.mtl) that reference other (non-image) files a findFileCallback would be necessary. + // but findFileCallback does not support virtual files, so we can't implement it. + options->setReadFileCallback(new ImageReadCallback(textureMgr)); + + osgDB::ReaderWriter::ReadResult result = reader->readNode(*file, options); + if (!result.success()) + { + std::stringstream errormsg; + errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl; + throw std::runtime_error(errormsg.str()); + } + return result.getNode(); + } } osg::ref_ptr SceneManager::getTemplate(const std::string &name) @@ -122,19 +191,19 @@ namespace Resource Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - // TODO: add support for non-NIF formats osg::ref_ptr loaded; try { Files::IStreamPtr file = mVFS->get(normalized); - loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + loaded = load(file, normalized, mTextureManager); } catch (std::exception& e) { std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); - loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + normalized = "meshes/marker_error.nif"; + loaded = load(file, normalized, mTextureManager); } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); @@ -174,6 +243,11 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); + std::string ext = getFileExtension(normalized); + + if (ext != "nif" && ext != "kf") + return NULL; + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 8b80efcdca..15ac375142 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -143,6 +143,57 @@ namespace Resource return true; } + osg::ref_ptr TextureManager::getImage(const std::string &filename) + { + std::string normalized = filename; + mVFS->normalizeFilename(normalized); + std::map >::iterator found = mImages.find(normalized); + if (found != mImages.end()) + return found->second; + else + { + Files::IStreamPtr stream; + try + { + stream = mVFS->get(normalized.c_str()); + } + catch (std::exception& e) + { + std::cerr << "Failed to open image: " << e.what() << std::endl; + return NULL; + } + + osg::ref_ptr opts (new osgDB::Options); + opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option + size_t extPos = normalized.find_last_of('.'); + std::string ext; + if (extPos != std::string::npos && extPos+1 < normalized.size()) + ext = normalized.substr(extPos+1); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + if (!reader) + { + std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl; + return NULL; + } + + osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); + if (!result.success()) + { + std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; + return NULL; + } + + osg::Image* image = result.getImage(); + if (!checkSupported(image, filename)) + { + return NULL; + } + + mImages.insert(std::make_pair(normalized, image)); + return image; + } + } + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) { std::string normalized = filename; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 2ee3baa773..1a7d41a7b1 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -34,7 +34,7 @@ namespace Resource osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); /// Create or retrieve an Image - //osg::ref_ptr getImage(const std::string& filename); + osg::ref_ptr getImage(const std::string& filename); const VFS::Manager* getVFS() { return mVFS; } @@ -49,7 +49,7 @@ namespace Resource typedef std::pair, std::string> MapKey; - std::map > mImages; + std::map > mImages; std::map > mTextures; From 8cf57ef6ac1eaf4a0ba51c230f3ad4d222ba4fc0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Nov 2015 23:30:10 +0100 Subject: [PATCH 1369/1812] Move BulletShapeManager and BulletShape to resource/ --- apps/openmw/mwphysics/actor.cpp | 4 +- apps/openmw/mwphysics/actor.hpp | 4 +- apps/openmw/mwphysics/physicssystem.cpp | 12 +- apps/openmw/mwphysics/physicssystem.hpp | 4 +- components/CMakeLists.txt | 4 +- components/nifbullet/bulletnifloader.cpp | 114 +----------------- components/nifbullet/bulletnifloader.hpp | 47 +------- components/resource/bulletshape.cpp | 102 ++++++++++++++++ components/resource/bulletshape.hpp | 78 ++++++++++++ .../bulletshapemanager.cpp | 6 +- .../bulletshapemanager.hpp | 6 +- 11 files changed, 208 insertions(+), 173 deletions(-) create mode 100644 components/resource/bulletshape.cpp create mode 100644 components/resource/bulletshape.hpp rename components/{nifbullet => resource}/bulletshapemanager.cpp (93%) rename components/{nifbullet => resource}/bulletshapemanager.hpp (96%) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 98ccefe71c..8cd0dfeb92 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include "../mwworld/class.hpp" @@ -17,7 +17,7 @@ namespace MWPhysics { -Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) +Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false) , mInternalCollisionMode(true) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index bcbc256d0e..3ea64840e2 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -13,7 +13,7 @@ class btCollisionWorld; class btCollisionShape; class btCollisionObject; -namespace NifBullet +namespace Resource { class BulletShapeInstance; } @@ -43,7 +43,7 @@ namespace MWPhysics class Actor : public PtrHolder { public: - Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); + Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world); ~Actor(); /** diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f5e9ce2fa6..6960d28019 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -17,9 +17,9 @@ #include #include -#include #include #include +#include #include @@ -520,7 +520,7 @@ namespace MWPhysics class Object : public PtrHolder { public: - Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) + Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) : mShapeInstance(shapeInstance) { mPtr = ptr; @@ -599,13 +599,13 @@ namespace MWPhysics private: std::auto_ptr mCollisionObject; - osg::ref_ptr mShapeInstance; + osg::ref_ptr mShapeInstance; }; // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) @@ -974,7 +974,7 @@ namespace MWPhysics void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance || !shapeInstance->getCollisionShape()) return; @@ -1115,7 +1115,7 @@ namespace MWPhysics } void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) { - osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); + osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance) return; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 7c5be0b6e3..283c857256 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -21,7 +21,7 @@ namespace MWRender class DebugDrawer; } -namespace NifBullet +namespace Resource { class BulletShapeManager; } @@ -154,7 +154,7 @@ namespace MWPhysics btCollisionDispatcher* mDispatcher; btCollisionWorld* mCollisionWorld; - std::auto_ptr mShapeManager; + std::auto_ptr mShapeManager; typedef std::map ObjectMap; ObjectMap mObjects; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f8f4c64ab0..b7865cb8af 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape ) add_component_dir (sceneutil @@ -55,7 +55,7 @@ add_component_dir (nifosg ) add_component_dir (nifbullet - bulletnifloader bulletshapemanager + bulletnifloader ) add_component_dir (to_utf8 diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 2496c68cde..5de6d51ca0 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -40,21 +40,6 @@ btVector3 getbtVector(const osg::Vec3f &v) namespace NifBullet { -// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface -struct TriangleMeshShape : public btBvhTriangleMeshShape -{ - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } - - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } -}; - BulletNifLoader::BulletNifLoader() : mCompoundShape(NULL) , mStaticMesh(NULL) @@ -65,9 +50,9 @@ BulletNifLoader::~BulletNifLoader() { } -osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { - mShape = new BulletShape; + mShape = new Resource::BulletShape; mCompoundShape = NULL; mStaticMesh = NULL; @@ -126,11 +111,11 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { btTransform trans; trans.setIdentity(); - mCompoundShape->addChildShape(trans, new TriangleMeshShape(mStaticMesh,true)); + mCompoundShape->addChildShape(trans, new Resource::TriangleMeshShape(mStaticMesh,true)); } } else if (mStaticMesh) - mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true); + mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh,true); return mShape; } @@ -306,7 +291,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); } - TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); + Resource::TriangleMeshShape* childShape = new Resource::TriangleMeshShape(childMesh,true); float scale = shape->trafo.scale; const Nif::Node* parent = shape; @@ -346,93 +331,4 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, } } -BulletShape::BulletShape() - : mCollisionShape(NULL) -{ - -} - -BulletShape::~BulletShape() -{ - deleteShape(mCollisionShape); -} - -void BulletShape::deleteShape(btCollisionShape* shape) -{ - if(shape!=NULL) - { - if(shape->isCompound()) - { - btCompoundShape* ms = static_cast(shape); - int a = ms->getNumChildShapes(); - for(int i=0; i getChildShape(i)); - } - delete shape; - } -} - -btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const -{ - if(shape->isCompound()) - { - btCompoundShape *comp = static_cast(shape); - btCompoundShape *newShape = new btCompoundShape; - - int numShapes = comp->getNumChildShapes(); - for(int i = 0;i < numShapes;++i) - { - btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); - btTransform trans = comp->getChildTransform(i); - newShape->addChildShape(trans, child); - } - - return newShape; - } - - if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) - { -#if BT_BULLET_VERSION >= 283 - btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); -#else - // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions - btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); - btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - NifBullet::TriangleMeshShape* newShape = new NifBullet::TriangleMeshShape(newMesh, true); -#endif - return newShape; - } - - if (btBoxShape* boxshape = dynamic_cast(shape)) - { - return new btBoxShape(*boxshape); - } - - throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); -} - -btCollisionShape *BulletShape::getCollisionShape() -{ - return mCollisionShape; -} - -osg::ref_ptr BulletShape::makeInstance() -{ - osg::ref_ptr instance (new BulletShapeInstance(this)); - return instance; -} - -BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) - : BulletShape() - , mSource(source) -{ - mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; - mCollisionBoxTranslate = source->mCollisionBoxTranslate; - - mAnimatedShapes = source->mAnimatedShapes; - - if (source->mCollisionShape) - mCollisionShape = duplicateCollisionShape(source->mCollisionShape); -} - } // namespace NifBullet diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 52428cc74a..a30bf8fdf1 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -13,6 +13,7 @@ #include #include +#include class btTriangleMesh; class btCompoundShape; @@ -28,48 +29,6 @@ namespace Nif namespace NifBullet { -class BulletShapeInstance; -class BulletShape : public osg::Referenced -{ -public: - BulletShape(); - virtual ~BulletShape(); - - btCollisionShape* mCollisionShape; - - // Used for actors. Note, ideally actors would use a separate loader - as it is - // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. - // For now, use one file <-> one resource for simplicity. - osg::Vec3f mCollisionBoxHalfExtents; - osg::Vec3f mCollisionBoxTranslate; - - // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape - // will be a btCompoundShape (which consists of one or more child shapes). - // In this map, for each animated collision shape, - // we store the node's record index mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; - - osg::ref_ptr makeInstance(); - - btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; - - btCollisionShape* getCollisionShape(); - -private: - void deleteShape(btCollisionShape* shape); -}; - -// An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. -// Vertex data is shallow-copied where possible. A ref_ptr to the original shape needs to be held to keep vertex pointers intact. -class BulletShapeInstance : public BulletShape -{ -public: - BulletShapeInstance(osg::ref_ptr source); - -private: - osg::ref_ptr mSource; -}; - /** *Load bulletShape from NIF files. */ @@ -91,7 +50,7 @@ public: abort(); } - osg::ref_ptr load(const Nif::NIFFilePtr file); + osg::ref_ptr load(const Nif::NIFFilePtr file); private: bool findBoundingBox(const Nif::Node* node, int flags = 0); @@ -106,7 +65,7 @@ private: btTriangleMesh* mStaticMesh; - osg::ref_ptr mShape; + osg::ref_ptr mShape; }; } diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp new file mode 100644 index 0000000000..00bcb9e046 --- /dev/null +++ b/components/resource/bulletshape.cpp @@ -0,0 +1,102 @@ +#include "bulletshape.hpp" + +#include + +#include +#include +#include +#include + +namespace Resource +{ + +BulletShape::BulletShape() + : mCollisionShape(NULL) +{ + +} + +BulletShape::~BulletShape() +{ + deleteShape(mCollisionShape); +} + +void BulletShape::deleteShape(btCollisionShape* shape) +{ + if(shape!=NULL) + { + if(shape->isCompound()) + { + btCompoundShape* ms = static_cast(shape); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); + } + delete shape; + } +} + +btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const +{ + if(shape->isCompound()) + { + btCompoundShape *comp = static_cast(shape); + btCompoundShape *newShape = new btCompoundShape; + + int numShapes = comp->getNumChildShapes(); + for(int i = 0;i < numShapes;++i) + { + btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); + btTransform trans = comp->getChildTransform(i); + newShape->addChildShape(trans, child); + } + + return newShape; + } + + if(btBvhTriangleMeshShape* trishape = dynamic_cast(shape)) + { +#if BT_BULLET_VERSION >= 283 + btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f)); +#else + // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); + btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); + TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true); +#endif + return newShape; + } + + if (btBoxShape* boxshape = dynamic_cast(shape)) + { + return new btBoxShape(*boxshape); + } + + throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); +} + +btCollisionShape *BulletShape::getCollisionShape() +{ + return mCollisionShape; +} + +osg::ref_ptr BulletShape::makeInstance() +{ + osg::ref_ptr instance (new BulletShapeInstance(this)); + return instance; +} + +BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) + : BulletShape() + , mSource(source) +{ + mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; + mCollisionBoxTranslate = source->mCollisionBoxTranslate; + + mAnimatedShapes = source->mAnimatedShapes; + + if (source->mCollisionShape) + mCollisionShape = duplicateCollisionShape(source->mCollisionShape); +} + +} diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp new file mode 100644 index 0000000000..78e509db71 --- /dev/null +++ b/components/resource/bulletshape.hpp @@ -0,0 +1,78 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H +#define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H + +#include + +#include +#include +#include + +#include + +class btCollisionShape; + +namespace Resource +{ + + class BulletShapeInstance; + class BulletShape : public osg::Referenced + { + public: + BulletShape(); + virtual ~BulletShape(); + + btCollisionShape* mCollisionShape; + + // Used for actors. Note, ideally actors would use a separate loader - as it is + // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. + // For now, use one file <-> one resource for simplicity. + osg::Vec3f mCollisionBoxHalfExtents; + osg::Vec3f mCollisionBoxTranslate; + + // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape + // will be a btCompoundShape (which consists of one or more child shapes). + // In this map, for each animated collision shape, + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; + + osg::ref_ptr makeInstance(); + + btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const; + + btCollisionShape* getCollisionShape(); + + private: + void deleteShape(btCollisionShape* shape); + }; + + + // An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape. + // Vertex data is shallow-copied where possible. A ref_ptr to the original shape is held to keep vertex pointers intact. + class BulletShapeInstance : public BulletShape + { + public: + BulletShapeInstance(osg::ref_ptr source); + + private: + osg::ref_ptr mSource; + }; + + // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface + struct TriangleMeshShape : public btBvhTriangleMeshShape + { + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } + }; + + +} + +#endif diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp similarity index 93% rename from components/nifbullet/bulletshapemanager.cpp rename to components/resource/bulletshapemanager.cpp index 23b461953b..3254a5c97a 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -4,7 +4,9 @@ #include -namespace NifBullet +#include "bulletshape.hpp" + +namespace Resource { BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) @@ -38,7 +40,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (ext != "nif") return NULL; - BulletNifLoader loader; + NifBullet::BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp similarity index 96% rename from components/nifbullet/bulletshapemanager.hpp rename to components/resource/bulletshapemanager.hpp index 6b9ec60de1..3e1f05ce5a 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -6,6 +6,8 @@ #include +#include "bulletshape.hpp" + namespace VFS { class Manager; @@ -14,10 +16,6 @@ namespace VFS namespace Resource { class SceneManager; -} - -namespace NifBullet -{ class BulletShape; class BulletShapeInstance; From e62470d67411c665231162959c764c27f4f19e2e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 00:18:27 +0100 Subject: [PATCH 1370/1812] Auto-generate the collision shape for native mesh formats --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/resource/bulletshapemanager.cpp | 105 +++++++++++++++++++-- components/resource/bulletshapemanager.hpp | 3 +- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6960d28019..1898a3de11 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -605,7 +605,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 3254a5c97a..d573b455da 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -1,16 +1,99 @@ #include "bulletshapemanager.hpp" +#include +#include +#include + +#include + #include #include #include "bulletshape.hpp" +#include "scenemanager.hpp" + namespace Resource { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) +struct GetTriangleFunctor +{ + GetTriangleFunctor() + : mTriMesh(NULL) + { + } + + void setTriMesh(btTriangleMesh* triMesh) + { + mTriMesh = triMesh; + } + + void setMatrix(const osg::Matrixf& matrix) + { + mMatrix = matrix; + } + + inline btVector3 toBullet(const osg::Vec3f& vec) + { + return btVector3(vec.x(), vec.y(), vec.z()); + } + + void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3, bool _temp ) + { + if (mTriMesh) + mTriMesh->addTriangle( toBullet(mMatrix.preMult(v1)), toBullet(mMatrix.preMult(v2)), toBullet(mMatrix.preMult(v3))); + } + + btTriangleMesh* mTriMesh; + osg::Matrixf mMatrix; +}; + +/// Creates a BulletShape out of a Node hierarchy. +class NodeToShapeVisitor : public osg::NodeVisitor +{ +public: + NodeToShapeVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mTriangleMesh(NULL) + { + + } + + virtual void apply(osg::Geode& geode) + { + for (unsigned int i=0; i functor; + functor.setTriMesh(mTriangleMesh); + functor.setMatrix(worldMat); + drawable.accept(functor); + } + + osg::ref_ptr getShape() + { + osg::ref_ptr shape (new BulletShape); + TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); + shape->mCollisionShape = meshShape; + mTriangleMesh = NULL; + return shape; + } + +private: + btTriangleMesh* mTriangleMesh; +}; + +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr) : mVFS(vfs) + , mSceneManager(sceneMgr) { } @@ -37,12 +120,22 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (extPos != std::string::npos && extPos+1 < normalized.size()) ext = normalized.substr(extPos+1); - if (ext != "nif") - return NULL; + if (ext == "nif") + { + NifBullet::BulletNifLoader loader; + // might be worth sharing NIFFiles with SceneManager in some way + shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + } + else + { + // TODO: support .bullet shape files - NifBullet::BulletNifLoader loader; - // might be worth sharing NIFFiles with SceneManager in some way - shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + osg::ref_ptr constNode (mSceneManager->getTemplate(normalized)); + osg::ref_ptr node (const_cast(constNode.get())); // const-trickery required because there is no const version of NodeVisitor + NodeToShapeVisitor visitor; + node->accept(visitor); + shape = visitor.getShape(); + } mIndex[normalized] = shape; } diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 3e1f05ce5a..6b8e64c21b 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -23,13 +23,14 @@ namespace Resource class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs); + BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; + SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; From 83e9a649e5910c186331d99e861ec9244d16df67 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 01:43:19 +0100 Subject: [PATCH 1371/1812] Cleanup --- components/resource/bulletshapemanager.cpp | 1 - components/resource/scenemanager.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index d573b455da..c4e46321fd 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -114,7 +114,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: { Files::IStreamPtr file = mVFS->get(normalized); - // TODO: add support for non-NIF formats size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3717ecb16d..d5b0088d3b 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -130,7 +130,6 @@ namespace Resource { try { - mTextureManager->getTexture2D(filename, osg::Texture::CLAMP_TO_EDGE, osg::Texture::CLAMP_TO_EDGE); return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED); } catch (std::exception& e) From d68ea994d56fc03d009eccbab079a7f51883d8ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Nov 2015 01:51:21 +0100 Subject: [PATCH 1372/1812] Deal with empty meshes --- components/resource/bulletshapemanager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index c4e46321fd..9aae1cad43 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -80,6 +80,9 @@ public: osg::ref_ptr getShape() { + if (!mTriangleMesh) + return osg::ref_ptr(); + osg::ref_ptr shape (new BulletShape); TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); shape->mCollisionShape = meshShape; @@ -134,6 +137,8 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: NodeToShapeVisitor visitor; node->accept(visitor); shape = visitor.getShape(); + if (!shape) + return osg::ref_ptr(); } mIndex[normalized] = shape; From 0bdfd1b0d7c625eb8cd82bb402f3c6c9a528515b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 16:47:03 +0100 Subject: [PATCH 1373/1812] Ignore Creature INDX subrecords Found in some .ess files, not sure what they mean. --- components/esm/loadcrea.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 0b53e5737d..b517820896 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -1,5 +1,7 @@ #include "loadcrea.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -83,6 +85,12 @@ namespace ESM { esm.skipHSub(); isDeleted = true; break; + case ESM::FourCC<'I','N','D','X'>::value: + // seems to occur only in .ESS files, unsure of purpose + int index; + esm.getHT(index); + std::cerr << "Creature::load: Unhandled INDX " << index << std::endl; + break; default: esm.fail("Unknown subrecord"); break; From 345335309193b865a3c01b27a1e42b219a099dc3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 19:00:43 +0100 Subject: [PATCH 1374/1812] AiCombat distance check takes into account collision box (Fixes #1699) --- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 31 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 7 ++++++ apps/openmw/mwworld/worldimp.cpp | 7 ++++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 52 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7332a26be1..39c1910df5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -543,6 +543,9 @@ namespace MWBase /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + + /// Return the distance between actor's weapon and target's collision box. + virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6270779a49..3cea00e45b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -347,7 +347,7 @@ namespace MWMechanics osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); - float distToTarget = (vTargetPos - vActorPos).length(); + float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1898a3de11..1393832bba 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -218,6 +218,7 @@ namespace MWPhysics resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; collisionWorld->rayTest(from, to, resultCallback1); + if (resultCallback1.hasHit() && ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) @@ -748,6 +749,36 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } + float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::Ptr &target) const + { + btCollisionObject* targetCollisionObj = NULL; + const Actor* actor = getActor(target); + if (actor) + targetCollisionObj = actor->getCollisionObject(); + if (!targetCollisionObj) + return 0.f; + + btTransform rayFrom; + rayFrom.setIdentity(); + rayFrom.setOrigin(toBullet(point)); + + // target the collision object's world origin, this should be the center of the collision object + btTransform rayTo; + rayTo.setIdentity(); + rayTo.setOrigin(targetCollisionObj->getWorldTransform().getOrigin()); + + btCollisionWorld::ClosestRayResultCallback cb(rayFrom.getOrigin(), rayTo.getOrigin()); + + btCollisionWorld::rayTestSingle(rayFrom, rayTo, targetCollisionObj, targetCollisionObj->getCollisionShape(), targetCollisionObj->getWorldTransform(), cb); + if (!cb.hasHit()) + { + // didn't hit the target. this could happen if point is already inside the collision box + return 0.f; + } + else + return (point - toOsg(cb.m_hitPointWorld)).length(); + } + class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 283c857256..a045638ef4 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -89,6 +89,13 @@ namespace MWPhysics const osg::Quat &orientation, float queryDistance); + + /// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the + /// target vector hits the collision shape and then calculates distance from the intersection point. + /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. + /// \note Only Actor targets are supported at the moment. + float getHitDistance(const osg::Vec3f& point, const MWWorld::Ptr& target) const; + struct RayResult { bool mHit; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7e78bef8c6..57a20a993d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3238,4 +3238,11 @@ namespace MWWorld osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } + + float World::getHitDistance(const Ptr &actor, const Ptr &target) + { + osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + return mPhysics->getHitDistance(weaponPos, target); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9f49281208..72093d281b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -633,6 +633,9 @@ namespace MWWorld /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Return the distance between actor's weapon and target's collision box. + virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); }; } From 9fce428929cce5b0f1be761683ec3d937f0ef00b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 20:41:49 +0100 Subject: [PATCH 1375/1812] ContactTestResultCallback: do not rely on col1 being the object tested against Unsure why, but in some cases col0 and col1 are swapped. --- apps/openmw/mwphysics/physicssystem.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1393832bba..5d8fa2da23 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -936,6 +936,13 @@ namespace MWPhysics class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: + ContactTestResultCallback(const btCollisionObject* testedAgainst) + : mTestedAgainst(testedAgainst) + { + } + + const btCollisionObject* mTestedAgainst; + std::vector mResult; #if BT_BULLET_VERSION >= 281 @@ -944,11 +951,15 @@ namespace MWPhysics const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) { const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; + if (collisionObject == mTestedAgainst) + collisionObject = col1Wrap->m_collisionObject; #else virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { const btCollisionObject* collisionObject = col0; + if (collisionObject == mTestedAgainst) + collisionObject = col1; #endif const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) @@ -967,7 +978,7 @@ namespace MWPhysics else return std::vector(); - ContactTestResultCallback resultCallback; + ContactTestResultCallback resultCallback (me); resultCallback.m_collisionFilterGroup = collisionGroup; resultCallback.m_collisionFilterMask = collisionMask; mCollisionWorld->contactTest(me, resultCallback); From a49058721e4c6dedb2e19c89f508f38c290a6422 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 21:20:12 +0100 Subject: [PATCH 1376/1812] Use a contactTest for collision script functions The previous method didn't work for stationary actors. This change fixes the grinder in "Sotha Sil, Dome of Kasia" not registering collisions if the player stands still. (Fixes #1934) --- apps/openmw/mwphysics/physicssystem.cpp | 36 +++++++------------------ apps/openmw/mwphysics/physicssystem.hpp | 8 +++--- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5d8fa2da23..5734f4827a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -234,9 +234,8 @@ namespace MWPhysics } static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld - , std::map& collisionTracker - , std::map& standingCollisionTracker) + bool isFlying, float waterlevel, float slowFall, btCollisionWorld* collisionWorld, + std::map& standingCollisionTracker) { const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); @@ -345,13 +344,6 @@ namespace MWPhysics newPosition = tracer.mEndPos; // ok to move, so set newPosition break; } - else - { - const btCollisionObject* standingOn = tracer.mHitObject; - const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); - if (ptrHolder) - collisionTracker[ptr] = ptrHolder->getPtr(); - } } else { @@ -968,11 +960,11 @@ namespace MWPhysics } }; - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) + std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = NULL; - ObjectMap::iterator found = mObjects.find(ptr); + ObjectMap::const_iterator found = mObjects.find(ptr); if (found != mObjects.end()) me = found->second->getCollisionObject(); else @@ -1081,7 +1073,6 @@ namespace MWPhysics mActors.insert(std::make_pair(updated, actor)); } - updateCollisionMapPtr(mCollisions, old, updated); updateCollisionMapPtr(mStandingCollisions, old, updated); } @@ -1197,7 +1188,6 @@ namespace MWPhysics void PhysicsSystem::clearQueuedMovement() { mMovementQueue.clear(); - mCollisions.clear(); mStandingCollisions.clear(); } @@ -1209,7 +1199,6 @@ namespace MWPhysics if(mTimeAccum >= 1.0f/60.0f) { // Collision events should be available on every frame - mCollisions.clear(); mStandingCollisions.clear(); const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1243,7 +1232,7 @@ namespace MWPhysics osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), - waterlevel, slowFall, mCollisionWorld, mCollisions, mStandingCollisions); + waterlevel, slowFall, mCollisionWorld, mStandingCollisions); float heightDiff = newpos.z() - oldHeight; @@ -1296,21 +1285,14 @@ namespace MWPhysics bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const { - for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) - { - if (it->first == actor && it->second == object) - return true; - } - return false; + std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); + return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); } void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const { - for (CollisionMap::const_iterator it = mCollisions.begin(); it != mCollisions.end(); ++it) - { - if (it->second == object) - out.push_back(it->first); - } + std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); + out.insert(out.end(), collisions.begin(), collisions.end()); } void PhysicsSystem::disableWater() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index a045638ef4..1ccfb21cdd 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -81,7 +81,7 @@ namespace MWPhysics void stepSimulation(float dt); void debugDraw(); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with + std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::Ptr& actor, @@ -174,11 +174,9 @@ namespace MWPhysics bool mDebugDrawEnabled; - // Tracks all movement collisions happening during a single frame. - // This will detect e.g. running against a vertical wall. It will not detect climbing up stairs, - // stepping up small objects, etc. + // Tracks standing collisions happening during a single frame. + // This will detect standing on an object, but won't detect running e.g. against a wall. typedef std::map CollisionMap; - CollisionMap mCollisions; CollisionMap mStandingCollisions; // replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value From 3bd2aaddea168f4e27fdd2e3244b64bc6daf4af7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Nov 2015 23:14:01 +0100 Subject: [PATCH 1377/1812] Adjust PulseSlow light controller (Fixes #1963) --- components/sceneutil/lightcontroller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d31e3d1075..ccfd836f72 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -76,7 +76,7 @@ namespace SceneUtil if(mType == LT_Pulse || mType == LT_PulseSlow) { cycle_time = 2.0f * pi; - time_distortion = 20.0f; + time_distortion = mType == LT_Pulse ? 20.0f : 4.f; } else { @@ -114,9 +114,9 @@ namespace SceneUtil else if(mType == LT_FlickerSlow) brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; else if(mType == LT_Pulse) - brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; + brightness = 0.7f + pulseAmplitude(mDeltaCount*fast)*0.3f; else if(mType == LT_PulseSlow) - brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; + brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); } From f08cfa19ea15f43816dedeb3f49d69c75f54f0b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 01:06:51 +0100 Subject: [PATCH 1378/1812] Fix SoundManager::isPlaying to consider multiple entries with the same Ptr/id Now it returns true if *any* sounds matching the given Ptr and id are playing. The previous behaviour was causing problems with "zombie" sounds (sounds that have finished playing, but weren't removed from the map yet) making the isPlaying method return false even though there's another legitimately playing sound in the map. --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bc97f16016..6e309e28e3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -168,8 +168,8 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id) - return snditer->first->isPlaying(); + if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) + return true; ++snditer; } return false; From ccc721ba3fb39d8f6e348ec0a9ab1f1b1c0b1613 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 02:56:26 +0100 Subject: [PATCH 1379/1812] Print the OpenMW version to the logfile --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 609452a9fd..17ef46246a 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -210,6 +210,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat cfgMgr.readConfiguration(variables, desc); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + std::cout << v.describe() << std::endl; + engine.setGrabMouse(!variables.count("no-grab")); // Font encoding settings From 9b96fcc224ce65a0fde625ad2850787810ae7128 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:49:42 +0100 Subject: [PATCH 1380/1812] Set the particle scaleReferenceFrame to local space --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 21bf8a0962..45e7c16df8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -866,6 +866,8 @@ namespace NifOsg partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); } + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); From 8c268f239e1b5019cd804bcb82975db514a63a75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:57:12 +0100 Subject: [PATCH 1381/1812] Set the object node scale before inserting model This fixes initWorldSpaceParticles not taking object scale into account. Still not taking into account object rotation or node animations. Ideally the initWorldSpaceParticles needs to run in an updateCallback. --- apps/openmw/mwrender/objects.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9f4fe2de2d..40cbb65119 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -125,6 +125,11 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + const float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec, true); + insert->setScale(scaleVec); + ptr.getRefData().setBaseNode(insert); } From 36e91617c900a0887c5d1decbd6bf83d56bf9437 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 22:09:32 +0100 Subject: [PATCH 1382/1812] Revert "NifOsg::Emitter: ignore psToWorld scale" This reverts commit 7c16630874230d886aa1d94f620c8b332676d93a. Fixes #3022 --- components/nifosg/particle.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 44d062d8ba..68f3de8aa1 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -264,9 +264,7 @@ void Emitter::emitParticles(double dt) osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { - osg::Matrix psToWorld = worldMats[0]; - // ignore scales in particlesystem world matrix. this seems wrong, but have to do so for MW compatibility. - psToWorld.orthoNormalize(psToWorld); + const osg::Matrix psToWorld = worldMats[0]; worldToPs = osg::Matrix::inverse(psToWorld); } From 894477849a4fdd48509b3c0337136776c020bf9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 23:33:08 +0100 Subject: [PATCH 1383/1812] Store animated collision objects in a separate container --- apps/openmw/mwphysics/physicssystem.cpp | 15 +++++++++++++-- apps/openmw/mwphysics/physicssystem.hpp | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5734f4827a..71a1553928 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -549,6 +549,11 @@ namespace MWPhysics return mCollisionObject.get(); } + bool isAnimated() const + { + return !mShapeInstance->mAnimatedShapes.empty(); + } + void animateCollisionShapes(btCollisionWorld* collisionWorld) { if (mShapeInstance->mAnimatedShapes.empty()) @@ -1015,6 +1020,9 @@ namespace MWPhysics Object *obj = new Object(ptr, shapeInstance); mObjects.insert(std::make_pair(ptr, obj)); + if (obj->isAnimated()) + mAnimatedObjects.insert(obj); + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } @@ -1025,6 +1033,9 @@ namespace MWPhysics if (found != mObjects.end()) { mCollisionWorld->removeCollisionObject(found->second->getCollisionObject()); + + mAnimatedObjects.erase(found->second); + delete found->second; mObjects.erase(found); } @@ -1251,8 +1262,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) - it->second->animateCollisionShapes(mCollisionWorld); + for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) + (*it)->animateCollisionShapes(mCollisionWorld); CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 1ccfb21cdd..83729d7ae4 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -166,6 +167,8 @@ namespace MWPhysics typedef std::map ObjectMap; ObjectMap mObjects; + std::set mAnimatedObjects; // stores pointers to elements in mObjects + typedef std::map ActorMap; ActorMap mActors; From cbf344663fc0914098d2c0d0b1679baa81ea1019 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 00:17:07 +0100 Subject: [PATCH 1384/1812] animateCollisionShape checks if the shape is really animated --- apps/openmw/mwphysics/physicssystem.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 71a1553928..b7d02ce362 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -563,7 +563,7 @@ namespace MWPhysics btCompoundShape* compound = dynamic_cast(mShapeInstance->getCollisionShape()); - for (std::map::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it) + for (std::map::iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end();) { int recIndex = it->first; int shapeIndex = it->second; @@ -578,6 +578,24 @@ namespace MWPhysics osg::NodePath path = visitor.mFoundPath; path.erase(path.begin()); + + // Attempt to remove "animated" shapes that are not actually animated + // We may get these because the BulletNifLoader does not know if a .kf file with additional controllers will be attached later on. + // On the first animateCollisionShapes call, we'll consider the graph completely loaded (with extra controllers and what not), + // so now we can better decide if the shape is really animated. + bool animated = false; + for (osg::NodePath::iterator nodePathIt = path.begin(); nodePathIt != path.end(); ++nodePathIt) + { + osg::Node* node = *nodePathIt; + if (node->getUpdateCallback()) + animated = true; + } + if (!animated) + { + mShapeInstance->mAnimatedShapes.erase(it++); + break; + } + osg::Matrixf matrix = osg::computeLocalToWorld(path); osg::Vec3f scale = matrix.getScale(); matrix.orthoNormalize(matrix); @@ -590,6 +608,8 @@ namespace MWPhysics compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); compound->updateChildTransform(shapeIndex, transform); + + ++it; } collisionWorld->updateSingleAabb(mCollisionObject.get()); From 706b1d4c28c131e55b33f46e7ada805acdeed242 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 02:22:37 +0100 Subject: [PATCH 1385/1812] Disable culling of ClipNode --- apps/openmw/mwrender/water.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e93060f7c2..ca099991ea 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -198,6 +198,7 @@ public: mClipNode->getClipPlaneList().clear(); mClipNode->addClipPlane(new osg::ClipPlane(0, osg::Plane(mPlane.getNormal(), 0))); // mPlane.d() applied in FlipCallback mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); + mClipNode->setCullingActive(false); } private: From 61314e1db16ed09d186b871b0a55d671d5a0a0a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:04:03 +0100 Subject: [PATCH 1386/1812] Fix bounding box of bullet debug drawer --- apps/openmw/mwrender/bulletdebugdraw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index c6d7935c54..eaf36cf857 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -78,6 +78,7 @@ void DebugDrawer::step() mWorld->debugDrawWorld(); mDrawArrays->setCount(mVertices->size()); mVertices->dirty(); + mGeometry->dirtyBound(); } } From 5f143dee2d84323ddcbfd95231338913ce275621 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:22:35 +0100 Subject: [PATCH 1387/1812] Fix lighting incontinuity at nightfall and sunrise --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 37f5e094de..49d421a201 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -690,7 +690,7 @@ void WeatherManager::update(float duration, bool paused) if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; + theta = M_PI * (1.f - (adjustedHour - adjustedNightStart) / nightDuration); } osg::Vec3f final( From 27617468c8db06953ba32b7807b46d560a22f0e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:29:58 +0100 Subject: [PATCH 1388/1812] Fix the collision shape not updating when scaling an object via script --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b7d02ce362..9eda6cb064 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1126,9 +1126,9 @@ namespace MWPhysics void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); - float scale = ptr.getCellRef().getScale(); if (found != mObjects.end()) { + float scale = ptr.getCellRef().getScale(); found->second->setScale(scale); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ba17a9675..5598598d05 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -73,6 +73,8 @@ namespace osg::Vec3f scaleVec (scale, scale, scale); ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); + + physics.updateScale(ptr); } } @@ -114,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) From 038f682510e0dc12ddbf5d15a75d6c68774cb78b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 01:06:51 +0100 Subject: [PATCH 1389/1812] Fix SoundManager::isPlaying to consider multiple entries with the same Ptr/id Now it returns true if *any* sounds matching the given Ptr and id are playing. The previous behaviour was causing problems with "zombie" sounds (sounds that have finished playing, but weren't removed from the map yet) making the isPlaying method return false even though there's another legitimately playing sound in the map. --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bc97f16016..6e309e28e3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -168,8 +168,8 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id) - return snditer->first->isPlaying(); + if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) + return true; ++snditer; } return false; From 966737f891d013d3ece6a6de35900399baf322fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:49:42 +0100 Subject: [PATCH 1390/1812] Set the particle scaleReferenceFrame to local space --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3e7f47b6fa..6a536d7af4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -843,6 +843,8 @@ namespace NifOsg partsys->getOrCreateUserDataContainer()->addDescription("worldspace"); } + partsys->setParticleScaleReferenceFrame(osgParticle::ParticleSystem::LOCAL_COORDINATES); + handleParticleInitialState(nifNode, partsys, partctrl); partsys->setQuota(partctrl->numParticles); From 622573f494af36af9c923e26acae7ca56226754f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Nov 2015 15:57:12 +0100 Subject: [PATCH 1391/1812] Set the object node scale before inserting model This fixes initWorldSpaceParticles not taking object scale into account. Still not taking into account object rotation or node animations. Ideally the initWorldSpaceParticles needs to run in an updateCallback. --- apps/openmw/mwrender/objects.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9f4fe2de2d..40cbb65119 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -125,6 +125,11 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) insert->setPosition(osg::Vec3(f[0], f[1], f[2])); + const float scale = ptr.getCellRef().getScale(); + osg::Vec3f scaleVec(scale, scale, scale); + ptr.getClass().adjustScale(ptr, scaleVec, true); + insert->setScale(scaleVec); + ptr.getRefData().setBaseNode(insert); } From e5ce3f62b7db6e46ed8a4648fa0b04ca07410309 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:22:35 +0100 Subject: [PATCH 1392/1812] Fix lighting incontinuity at nightfall and sunrise --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 24b45fcea6..e4fdd62de2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -680,7 +680,7 @@ void WeatherManager::update(float duration, bool paused) if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; + theta = M_PI * (1.f - (adjustedHour - adjustedNightStart) / nightDuration); } osg::Vec3f final( From b2746c8c01794c3241bddcbb16d24efdf996e495 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 03:29:58 +0100 Subject: [PATCH 1393/1812] Fix the collision shape not updating when scaling an object via script --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 55144afe75..0a687d93fd 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1062,9 +1062,9 @@ namespace MWPhysics void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); - float scale = ptr.getCellRef().getScale(); if (found != mObjects.end()) { + float scale = ptr.getCellRef().getScale(); found->second->setScale(scale); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1ba17a9675..5598598d05 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -73,6 +73,8 @@ namespace osg::Vec3f scaleVec (scale, scale, scale); ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); + + physics.updateScale(ptr); } } @@ -114,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - updateObjectScale(ptr, mPhysics, mRendering); ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) From 2d302aef99f804423fc0b837317f47742bc8c1d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 05:05:43 +0100 Subject: [PATCH 1394/1812] Implement stayOutside script variable --- apps/openmw/mwworld/actionteleport.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index cd6698c985..031f07258c 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -3,6 +3,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" + #include "player.hpp" namespace @@ -40,6 +43,11 @@ namespace MWWorld for(std::set::iterator it = followers.begin();it != followers.end();++it) { MWWorld::Ptr follower = *it; + + std::string script = follower.getClass().getScript(follower); + if (!script.empty() && follower.getRefData().getLocals().getIntVar(script, "stayoutside") == 1) + continue; + if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2() <= 800*800) teleport(*it); From 43de13fa993a36edfd37c7c4d3aa4389713a9835 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 19:22:31 +0100 Subject: [PATCH 1395/1812] Do not allow resting on lava --- apps/openmw/mwphysics/physicssystem.cpp | 42 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 6 ++++ apps/openmw/mwworld/worldimp.cpp | 9 ++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9eda6cb064..17014e1623 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -515,6 +515,7 @@ namespace MWPhysics public: Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) : mShapeInstance(shapeInstance) + , mSolid(true) { mPtr = ptr; @@ -549,6 +550,17 @@ namespace MWPhysics return mCollisionObject.get(); } + /// Return solid flag. Not used by the object itself, true by default. + bool isSolid() const + { + return mSolid; + } + + void setSolid(bool solid) + { + mSolid = solid; + } + bool isAnimated() const { return !mShapeInstance->mAnimatedShapes.empty(); @@ -618,6 +630,7 @@ namespace MWPhysics private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; + bool mSolid; }; // --------------------------------------------------------------- @@ -684,6 +697,35 @@ namespace MWPhysics return mDebugDrawEnabled; } + void PhysicsSystem::markAsNonSolid(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found == mObjects.end()) + return; + + found->second->setSolid(false); + } + + bool PhysicsSystem::isOnSolidGround (const MWWorld::Ptr& actor) const + { + const Actor* physactor = getActor(actor); + if (!physactor->getOnGround()) + return false; + + CollisionMap::const_iterator found = mStandingCollisions.find(actor); + if (found == mStandingCollisions.end()) + return true; // assume standing on terrain (which is a non-object, so not collision tracked) + + ObjectMap::const_iterator foundObj = mObjects.find(found->second); + if (foundObj == mObjects.end()) + return false; + + if (!foundObj->second->isSolid()) + return false; + + return true; + } + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback { const btCollisionObject* mMe; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 83729d7ae4..de644e0f3c 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -153,6 +153,12 @@ namespace MWPhysics bool toggleDebugRendering(); + /// Mark the given object as a 'non-solid' object. A non-solid object means that + /// \a isOnSolidGround will return false for actors standing on that object. + void markAsNonSolid (const MWWorld::Ptr& ptr); + + bool isOnSolidGround (const MWWorld::Ptr& actor) const; + private: void updateWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57a20a993d..b1234c8a44 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2059,11 +2059,10 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); - if((!actor->getOnGround()&&actor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) + if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos)) return 2; - if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || - player.getClass().getNpcStats(player).isWerewolf()) + if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; return 0; @@ -2155,6 +2154,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) @@ -2183,6 +2184,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) From cf4f3d9ebcf7ba264d9c688be56b21dcc6e1e768 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Fri, 20 Nov 2015 14:57:42 -0500 Subject: [PATCH 1396/1812] Correct tooltip for Magicka in stats window. --- apps/openmw/mwgui/statswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index efbbeb29ae..e66e012386 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -159,7 +159,7 @@ namespace MWGui else if (id == "MBar") { getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { From 1b1d9a7a9c3d89bbde1c8510961c2c3cac684926 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 02:05:27 +0100 Subject: [PATCH 1397/1812] Fixed another tooltip --- apps/openmw/mwgui/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 3922b1997c..cf0fa3414a 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -196,7 +196,7 @@ namespace MWGui mMagicka->setProgressRange (modified); mMagicka->setProgressPosition (current); getWidget(w, "MagickaFrame"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { From 9d8a1479eb3d0f7a645a6913b38ebec8a68d6514 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 09:31:30 +0100 Subject: [PATCH 1398/1812] updated change log once more --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36700904e0..43e598566c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Bug #2014: Antialiasing setting does nothing on Linux Bug #2037: Some enemies attack the air when spotting the player Bug #2052: NIF rotation matrices including scales are not supported + Bug #2062: Crank in Old Mournhold: Forgotten Sewer turns about the wrong axis Bug #2111: Raindrops in front of fire look wrong Bug #2140: [OpenGL] Water effects, flames and parts of creatures solid black when observed through brazier flame Bug #2147: Trueflame and Hopesfire flame effects not properly aligned with blade @@ -176,6 +177,7 @@ Bug #2980: Editor: Attribute and Skill can be selected for spells that do not require these parameters, leading to non-functional spells Bug #2990: Compiling a script with warning mode 2 and enabled error downgrading leads to infinite recursion Bug #2992: [Mod: Great House Dagoth] Killing Dagoth Gares freezes the game + Bug #3007: PlaceItem takes radians instead of degrees + angle reliability Feature #706: Editor: Script Editor enhancements Feature #872: Editor: Colour values in tables Feature #880: Editor: ID auto-complete From e0e9e7f8c2e2e666f125c2c3a8b1c098ec4ea43a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 11:56:24 +0100 Subject: [PATCH 1399/1812] adjusted startup warning message for recent improvements regarding loading/saving --- apps/opencs/view/doc/startup.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index a9d697f1c2..67ff50dab9 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -104,14 +104,16 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) layout->addWidget (createButtons()); layout->addWidget (createTools()); - /// \todo remove this label once loading and saving are fully implemented - QLabel *warning = new QLabel ("WARNING:

    OpenCS is in alpha stage.
    The code for loading and saving is incomplete.
    This version of OpenCS is only a preview.
    Do NOT use it for real editing!
    You will lose records both on loading and on saving.

    Please note:
    If you lose data and come to the OpenMW forum to complain,
    we will mock you.
    "); + /// \todo remove this label once we are feature complete and convinced that this thing is + /// working properly. + QLabel *warning = new QLabel ("WARNING: OpenMW-CS is in alpha stage.

    The editor is not feature complete and not sufficiently tested.
    In theory your data should be safe. But we strongly advice to make backups regularly if you are working with live data.
    "); QFont font; font.setPointSize (12); font.setBold (true); warning->setFont (font); + warning->setWordWrap (true); layout->addWidget (warning, 1); From b74b274ac0e88ad7c833b908bb301dee3986264f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:14:57 +0100 Subject: [PATCH 1400/1812] Removed validator for filenames in OpenMW-CS (Fixes #2918) --- apps/opencs/view/doc/filewidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index 110d561c17..9e9acdfbe6 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -16,7 +16,6 @@ CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (fal QHBoxLayout *layout = new QHBoxLayout (this); mInput = new QLineEdit (this); - mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9_-\\s]*$"))); layout->addWidget (mInput, 1); From 1093a53cf9f2a85374e145d96bb21bfb46eb13ad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:45:11 +0100 Subject: [PATCH 1401/1812] hide script error list when there are no errors (Fixes #2867) --- apps/opencs/view/world/scriptsubview.cpp | 19 +++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index eb0c706564..7907dca03a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -54,6 +54,7 @@ void CSVWorld::ScriptSubView::updateDeletedState() if (isDeleted()) { mErrors->clear(); + adjustSplitter(); mEditor->setEnabled (false); } else @@ -63,6 +64,22 @@ void CSVWorld::ScriptSubView::updateDeletedState() } } +void CSVWorld::ScriptSubView::adjustSplitter() +{ + QList sizes; + + if (mErrors->rowCount()) + { + sizes << 1 << 1; + } + else + { + sizes << 1 << 0; + } + + mMain->setSizes (sizes); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -347,4 +364,6 @@ void CSVWorld::ScriptSubView::updateRequest() QString source = mModel->data (index).toString(); mErrors->update (source.toUtf8().constData()); + + adjustSplitter(); } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 907dc7958b..c04a7df7cb 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -58,6 +58,8 @@ namespace CSVWorld void updateDeletedState(); + void adjustSplitter(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); From 26640d17eb053176b45482e801236415a42ddf1f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 12:52:32 +0100 Subject: [PATCH 1402/1812] do not adjust error panel height if panal was already open --- apps/opencs/view/world/scriptsubview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 7907dca03a..0faf61f9b0 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -70,6 +70,9 @@ void CSVWorld::ScriptSubView::adjustSplitter() if (mErrors->rowCount()) { + if (mErrors->height()) + return; // keep old height if the error panel was already open + sizes << 1 << 1; } else From f5c61ee616bfaed911a574c6d43aa6842c224773 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 14:19:14 +0100 Subject: [PATCH 1403/1812] remember script error panel height per scriptsubview --- apps/opencs/view/world/scriptsubview.cpp | 12 ++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0faf61f9b0..c45e45f562 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -73,10 +73,13 @@ void CSVWorld::ScriptSubView::adjustSplitter() if (mErrors->height()) return; // keep old height if the error panel was already open - sizes << 1 << 1; + sizes << (mMain->height()-mErrorHeight-mMain->handleWidth()) << mErrorHeight; } else { + if (mErrors->height()) + mErrorHeight = mErrors->height(); + sizes << 1 << 0; } @@ -85,7 +88,8 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), - mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) + mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), + mErrorHeight (100) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); @@ -101,6 +105,10 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mErrors = new ScriptErrorTable (document, this); mMain->addWidget (mErrors); + QList sizes; + sizes << 1 << 0; + mMain->setSizes (sizes); + QWidget *widget = new QWidget (this);; widget->setLayout (&mLayout); setWidget (widget); diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index c04a7df7cb..179430ef90 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -47,6 +47,7 @@ namespace CSVWorld QSplitter *mMain; ScriptErrorTable *mErrors; QTimer *mCompileDelay; + int mErrorHeight; private: From 99500f40212c7b37a536c2692d5b066c26c79bbf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Nov 2015 14:28:40 +0100 Subject: [PATCH 1404/1812] make initial size of script error panel configurable (Fixes #2996) --- apps/opencs/model/settings/usersettings.cpp | 5 +++++ apps/opencs/view/world/scriptsubview.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 8bf24ae343..8e5ab3d874 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -334,6 +334,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() delay->setRange (0, 10000); delay->setToolTip ("Delay in milliseconds"); + Setting *errorHeight = createSetting (Type_SpinBox, "error-height", + "Initial height of the error panel"); + errorHeight->setDefaultValue (100); + errorHeight->setRange (100, 10000); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index c45e45f562..bd66f2bf6b 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -89,7 +89,7 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), - mErrorHeight (100) + mErrorHeight (CSMSettings::UserSettings::instance().setting ("script-editor/error-height").toInt()) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); From b507d5da5dd81b9f2a29a2e1acd3bc1f20a9997a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Sun, 22 Nov 2015 00:50:36 -0500 Subject: [PATCH 1405/1812] One more tooltip fix. This one in the review dialog with Socucius Ergalla. --- apps/openmw/mwgui/review.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index fa07f10207..d7d6c3cdb1 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -154,7 +154,7 @@ namespace MWGui { mMagicka->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); - mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + mMagicka->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) From 34350ddeb1a9f86627fe8f52605cc1fb8b8bd15f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 15:46:04 +0100 Subject: [PATCH 1406/1812] Fix bug #3028 --- files/mygui/openmw_layers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index c6d3df5210..cd8a9f7608 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -4,7 +4,7 @@ - + From 2108e96c159b5834e667699ec0e86e4a372c28e4 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 22 Nov 2015 19:32:13 +0100 Subject: [PATCH 1407/1812] OS X: use TGA, PNG & JPEG plugins instead of ImageIO Using ImageIO is troublesome when one needs to read an image from memory, see for the details: https://forum.openmw.org/viewtopic.php?f=20&t=2949&start=220#p35531 --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f168be169..6716e0e23c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -748,9 +748,10 @@ if (APPLE) set(ABSOLUTE_PLUGINS "") set(USED_OSG_PLUGINS - osgdb_tga osgdb_dds - osgdb_imageio + osgdb_jpeg + osgdb_png + osgdb_tga ) foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) From 62169a70392ebef85aeb2b7cf3d0e1d41573a578 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 21:57:04 +0100 Subject: [PATCH 1408/1812] Use a single-precision PositionAttitudeTransform in speed critical places --- apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 3 +- apps/openmw/mwmechanics/combat.cpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 +- apps/openmw/mwphysics/actor.cpp | 3 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/camera.cpp | 5 +- apps/openmw/mwrender/characterpreview.hpp | 2 + apps/openmw/mwrender/creatureanimation.cpp | 3 +- apps/openmw/mwrender/objects.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/ripplesimulation.hpp | 1 + .../mwscript/transformationextensions.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 1 + apps/openmw/mwworld/refdata.cpp | 4 +- apps/openmw/mwworld/refdata.hpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 3 +- components/CMakeLists.txt | 2 +- .../sceneutil/positionattitudetransform.cpp | 51 ++++++++++++++++++ .../sceneutil/positionattitudetransform.hpp | 53 +++++++++++++++++++ components/terrain/terraingrid.cpp | 4 +- 23 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 components/sceneutil/positionattitudetransform.cpp create mode 100644 components/sceneutil/positionattitudetransform.hpp diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1c26c7dd11..284e237a0d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -3,11 +3,10 @@ #include #include -#include - #include #include #include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b5b4721c04..ff23844dd2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,7 +21,6 @@ #include -#include #include "movement.hpp" #include "npcstats.hpp" @@ -33,6 +32,8 @@ #include +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index f11e6bcfda..a01dc7079c 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,9 +1,9 @@ #include "combat.hpp" -#include - #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 761c5ece9e..e392b309b9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,13 +2,13 @@ #include -#include - #include #include #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 8cd0dfeb92..8438f26a30 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -1,11 +1,10 @@ #include "actor.hpp" -#include - #include #include #include +#include #include #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 17014e1623..1f59c5c997 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -22,6 +21,7 @@ #include #include +#include #include // FindRecIndexVisitor diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6ef6fab239..d530c2c929 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 1d43cde43f..88934414f6 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,8 +1,9 @@ #include "camera.hpp" -#include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -378,7 +379,7 @@ namespace MWRender else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); + SceneUtil::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); mTrackingNode = transform; if (transform) mHeightScale = transform->getScale().z(); diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 32c1850c65..2b7984b009 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index f46736a394..7c447182f2 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -2,12 +2,11 @@ #include -#include - #include #include #include #include +#include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 40cbb65119..d612824e24 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -14,6 +13,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" @@ -116,7 +116,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) else cellnode = found->second; - osg::ref_ptr insert (new osg::PositionAttitudeTransform); + osg::ref_ptr insert (new SceneUtil::PositionAttitudeTransform); cellnode->addChild(insert); insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c55d11795d..f6403a9259 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -26,6 +25,7 @@ #include #include #include +#include #include @@ -706,7 +706,7 @@ namespace MWRender { if (!mPlayerNode) { - mPlayerNode = new osg::PositionAttitudeTransform; + mPlayerNode = new SceneUtil::PositionAttitudeTransform; mPlayerNode->setNodeMask(Mask_Player); mLightRoot->addChild(mPlayerNode); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3e17ef4137..203df22699 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -186,7 +186,7 @@ namespace MWRender std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; - osg::ref_ptr mPlayerNode; + osg::ref_ptr mPlayerNode; std::auto_ptr mCamera; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 1717cca573..17d5fea15f 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -8,6 +8,7 @@ namespace osg { class Group; + class PositionAttitudeTransform; } namespace osgParticle diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f650352262..592168687a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 0aa2efded7..22fc4784cd 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -4,6 +4,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 87cbc586f6..8acba43df7 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -108,12 +108,12 @@ namespace MWWorld {} } - void RefData::setBaseNode(osg::PositionAttitudeTransform *base) + void RefData::setBaseNode(SceneUtil::PositionAttitudeTransform *base) { mBaseNode = base; } - osg::PositionAttitudeTransform* RefData::getBaseNode() + SceneUtil::PositionAttitudeTransform* RefData::getBaseNode() { return mBaseNode; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 13a71ec335..6713334d70 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,7 +7,7 @@ #include -namespace osg +namespace SceneUtil { class PositionAttitudeTransform; } @@ -26,7 +26,7 @@ namespace MWWorld class RefData { - osg::PositionAttitudeTransform* mBaseNode; + SceneUtil::PositionAttitudeTransform* mBaseNode; MWScript::Locals mLocals; @@ -69,10 +69,10 @@ namespace MWWorld RefData& operator= (const RefData& refData); /// Return base node (can be a null pointer). - osg::PositionAttitudeTransform* getBaseNode(); + SceneUtil::PositionAttitudeTransform* getBaseNode(); /// Set base node (can be a null pointer). - void setBaseNode (osg::PositionAttitudeTransform* base); + void setBaseNode (SceneUtil::PositionAttitudeTransform* base); int getCount() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b1234c8a44..d6480b1465 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -22,6 +21,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b7865cb8af..c80e27e4d8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller positionattitudetransform # not used yet #workqueue ) diff --git a/components/sceneutil/positionattitudetransform.cpp b/components/sceneutil/positionattitudetransform.cpp new file mode 100644 index 0000000000..5f6b57e979 --- /dev/null +++ b/components/sceneutil/positionattitudetransform.cpp @@ -0,0 +1,51 @@ +#include "positionattitudetransform.hpp" + +#include + +namespace SceneUtil +{ + +PositionAttitudeTransform::PositionAttitudeTransform(): + _scale(1.0,1.0,1.0) +{ +} + +bool PositionAttitudeTransform::computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const +{ + if (_referenceFrame==RELATIVE_RF) + { + matrix.preMultTranslate(_position); + matrix.preMultRotate(_attitude); + matrix.preMultScale(_scale); + } + else // absolute + { + matrix.makeRotate(_attitude); + matrix.postMultTranslate(_position); + matrix.preMultScale(_scale); + } + return true; +} + + +bool PositionAttitudeTransform::computeWorldToLocalMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const +{ + if (_scale.x() == 0.0 || _scale.y() == 0.0 || _scale.z() == 0.0) + return false; + + if (_referenceFrame==RELATIVE_RF) + { + matrix.postMultTranslate(-_position); + matrix.postMultRotate(_attitude.inverse()); + matrix.postMultScale(osg::Vec3f(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z())); + } + else // absolute + { + matrix.makeRotate(_attitude.inverse()); + matrix.preMultTranslate(-_position); + matrix.postMultScale(osg::Vec3f(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z())); + } + return true; +} + +} diff --git a/components/sceneutil/positionattitudetransform.hpp b/components/sceneutil/positionattitudetransform.hpp new file mode 100644 index 0000000000..b6f92ee84e --- /dev/null +++ b/components/sceneutil/positionattitudetransform.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_COMPONENTS_POSITIONATTITUDE_TRANSFORM_H +#define OPENMW_COMPONENTS_POSITIONATTITUDE_TRANSFORM_H + +#include + +namespace SceneUtil +{ + +/// @brief A customized version of osg::PositionAttitudeTransform optimized for speed. +/// Uses single precision values. Also removed _pivotPoint which we don't need. +class PositionAttitudeTransform : public osg::Transform +{ + public : + PositionAttitudeTransform(); + + PositionAttitudeTransform(const PositionAttitudeTransform& pat,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): + Transform(pat,copyop), + _position(pat._position), + _attitude(pat._attitude), + _scale(pat._scale){} + + + META_Node(SceneUtil, PositionAttitudeTransform) + + inline void setPosition(const osg::Vec3f& pos) { _position = pos; dirtyBound(); } + inline const osg::Vec3f& getPosition() const { return _position; } + + + inline void setAttitude(const osg::Quat& quat) { _attitude = quat; dirtyBound(); } + inline const osg::Quat& getAttitude() const { return _attitude; } + + + inline void setScale(const osg::Vec3f& scale) { _scale = scale; dirtyBound(); } + inline const osg::Vec3f& getScale() const { return _scale; } + + + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; + virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; + + + protected : + + virtual ~PositionAttitudeTransform() {} + + osg::Vec3f _position; + osg::Quat _attitude; + osg::Vec3f _scale; +}; + +} + +#endif diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index ceb39a24b0..aa82e0bd65 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -6,10 +6,10 @@ #include #include +#include #include -#include #include #include #include @@ -91,7 +91,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu return NULL; // no terrain defined osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); - osg::ref_ptr transform (new osg::PositionAttitudeTransform); + osg::ref_ptr transform (new SceneUtil::PositionAttitudeTransform); transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); if (parent) From ffea9ec2c43441de73a0b07c98c7d5330c580f62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 04:13:25 +0100 Subject: [PATCH 1409/1812] Remove comment SharedStateManager::prune is run automatically during the update traversal. --- components/resource/scenemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index d5b0088d3b..cd3aeb3d63 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -206,7 +206,6 @@ namespace Resource } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); - // TODO: run SharedStateManager::prune on unload if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); From fc7456e0a10e31c03057d2b46974c1b05efe218f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 21 Nov 2015 23:35:56 +0100 Subject: [PATCH 1410/1812] Explicitely opt for float matrices in performance critical places --- components/nifosg/particle.cpp | 2 +- components/resource/scenemanager.cpp | 2 +- components/sceneutil/lightmanager.cpp | 4 ++-- components/sceneutil/lightmanager.hpp | 4 ++-- components/sceneutil/util.cpp | 2 +- components/sceneutil/util.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 68f3de8aa1..e30837d394 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -49,7 +49,7 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) osg::Matrix mat = osg::computeLocalToWorld( path ); mat.orthoNormalize(mat); // don't undo the scale - mat = osg::Matrix::inverse(mat); + mat.invert(mat); trans->setMatrix(mat); } traverse(node,nv); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index cd3aeb3d63..b2ba5c4cfa 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -82,7 +82,7 @@ namespace osg::MatrixList mats = node->getWorldMatrices(); if (mats.empty()) return; - osg::Matrix worldMat = mats[0]; + osg::Matrixf worldMat = mats[0]; worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node for (int i=0; inumParticles(); ++i) { diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index d3e11050d7..43f11cf005 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -164,7 +164,7 @@ namespace SceneUtil mStateSetCache.clear(); } - void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) + void LightManager::addLight(LightSource* lightSource, osg::Matrixf worldMat) { LightSourceTransform l; l.mLightSource = lightSource; @@ -221,7 +221,7 @@ namespace SceneUtil for (std::vector::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt) { - osg::Matrix worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); + osg::Matrixf worldViewMat = lightIt->mWorldMatrix * (*viewMatrix); osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius()); transformBoundingSphere(worldViewMat, viewBound); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 27ee1cdaa8..ecee873e86 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -77,12 +77,12 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, osg::Matrix worldMat); + void addLight(LightSource* lightSource, osg::Matrixf worldMat); struct LightSourceTransform { LightSource* mLightSource; - osg::Matrix mWorldMatrix; + osg::Matrixf mWorldMatrix; }; const std::vector& getLights() const; diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 52f9c9e54e..3add3bb236 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -3,7 +3,7 @@ namespace SceneUtil { -void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere) +void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere) { osg::BoundingSphere::vec_type xdash = bsphere._center; xdash.x() += bsphere._radius; diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index c99771c5ea..d8fefdb291 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -11,7 +11,7 @@ namespace SceneUtil // Transform a bounding sphere by a matrix // based off private code in osg::Transform // TODO: patch osg to make public - void transformBoundingSphere (const osg::Matrix& matrix, osg::BoundingSphere& bsphere); + void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere); osg::Vec4f colourFromRGB (unsigned int clr); From 75a464f7ec1abad4957c07ad014f3035d1429180 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 18:43:13 +0100 Subject: [PATCH 1411/1812] Fix a typo --- components/sceneutil/riggeometry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 023ac12d5d..bd24ba785f 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -185,7 +185,7 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return true; } -void accummulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) +void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) { osg::Matrixf m = invBindMatrix * matrix; float* ptr = m.ptr(); @@ -246,7 +246,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) const osg::Matrix& invBindMatrix = weightIt->first.second; float weight = weightIt->second; const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; - accummulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); + accumulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } resultMat = resultMat * geomToSkel; From 6d5aa272fc50e0410cbcabdf7109daf9bd739b91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 19:49:11 +0100 Subject: [PATCH 1412/1812] RigGeometry: do not update the geomToSkelMatrix more than once per frame --- components/sceneutil/riggeometry.cpp | 14 ++++++-------- components/sceneutil/riggeometry.hpp | 4 +++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index bd24ba785f..2de6bc1ad0 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -224,8 +224,6 @@ void RigGeometry::update(osg::NodeVisitor* nv) mSkeleton->updateBoneMatrices(nv); - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); - // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); @@ -248,7 +246,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; accumulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); } - resultMat = resultMat * geomToSkel; + resultMat = resultMat * mGeomToSkelMatrix; for (std::vector::const_iterator vertexIt = it->second.begin(); vertexIt != it->second.end(); ++vertexIt) { @@ -276,13 +274,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) mSkeleton->updateBoneMatrices(nv); - osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + updateGeomToSkelMatrix(nv); + osg::BoundingBox box; for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) { Bone* bone = it->first; osg::BoundingSpheref bs = it->second; - transformBoundingSphere(bone->mMatrixInSkeletonSpace * geomToSkel, bs); + transformBoundingSphere(bone->mMatrixInSkeletonSpace * mGeomToSkelMatrix, bs); box.expandBy(bs); } @@ -297,7 +296,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) getParent(i)->dirtyBound(); } -osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) +void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) { osg::NodePath path; bool foundSkel = false; @@ -311,8 +310,7 @@ osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) else path.push_back(*it); } - return osg::computeWorldToLocal(path); - + mGeomToSkelMatrix = osg::computeWorldToLocal(path); } void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e51fc0cf69..0a39fcde2e 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,8 @@ namespace SceneUtil osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; + osg::Matrixf mGeomToSkelMatrix; + osg::ref_ptr mInfluenceMap; typedef std::pair BoneBindMatrixPair; @@ -69,7 +71,7 @@ namespace SceneUtil bool initFromParentSkeleton(osg::NodeVisitor* nv); - osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); + void updateGeomToSkelMatrix(osg::NodeVisitor* nv); }; } From 94e8560bf811a9fdab641da9a1741161a854dd71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 19:58:21 +0100 Subject: [PATCH 1413/1812] RigGeometry: do not allocate new NodePath every frame --- components/sceneutil/riggeometry.cpp | 6 +++--- components/sceneutil/riggeometry.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 2de6bc1ad0..0006c947e2 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -298,7 +298,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) { - osg::NodePath path; + mSkelToGeomPath.clear(); bool foundSkel = false; for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) { @@ -308,9 +308,9 @@ void RigGeometry::updateGeomToSkelMatrix(osg::NodeVisitor *nv) foundSkel = true; } else - path.push_back(*it); + mSkelToGeomPath.push_back(*it); } - mGeomToSkelMatrix = osg::computeWorldToLocal(path); + mGeomToSkelMatrix = osg::computeWorldToLocal(mSkelToGeomPath); } void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 0a39fcde2e..f61fe62e7c 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,7 @@ namespace SceneUtil osg::ref_ptr mSourceGeometry; Skeleton* mSkeleton; + osg::NodePath mSkelToGeomPath; osg::Matrixf mGeomToSkelMatrix; osg::ref_ptr mInfluenceMap; From 28b20428b9ab8d185067dd9e14844f102f9ce795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 20:33:22 +0100 Subject: [PATCH 1414/1812] Remove dynamic_cast in GeomMorpherController --- components/nifosg/controller.cpp | 31 ++++++++++++++----------------- components/nifosg/controller.hpp | 1 + 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index bb698ed632..8f8b5003cc 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -221,28 +221,25 @@ GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); - if (morphGeom) + osgAnimation::MorphGeometry* morphGeom = static_cast(drawable); + if (hasInput()) { - if (hasInput()) + if (mKeyFrames.size() <= 1) + return; + float input = getInputValue(nv); + int i = 0; + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { - if (mKeyFrames.size() <= 1) - return; - float input = getInputValue(nv); - int i = 0; - for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) - { - float val = 0; - if (!(*it)->mKeys.empty()) - val = interpKey((*it)->mKeys, input); - val = std::max(0.f, std::min(1.f, val)); + float val = 0; + if (!(*it)->mKeys.empty()) + val = interpKey((*it)->mKeys, input); + val = std::max(0.f, std::min(1.f, val)); - morphGeom->setWeight(i, val); - } + morphGeom->setWeight(i, val); } - - morphGeom->transformSoftwareMethod(); } + + morphGeom->transformSoftwareMethod(); } UVController::UVController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d0c6d1de33..803ce77a2d 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -97,6 +97,7 @@ namespace NifOsg virtual float getMaximum() const; }; + /// Must be set on an osgAnimation::MorphGeometry. class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator { public: From 0d49c7fa517bad02387112c916a2a8c648742903 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 21:19:02 +0100 Subject: [PATCH 1415/1812] GeomMorpherController: fix double update of MorphGeometry --- components/nifosg/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 8f8b5003cc..4dfa4b3041 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -239,7 +239,7 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable } } - morphGeom->transformSoftwareMethod(); + // morphGeometry::transformSoftwareMethod() done in cull callback i.e. only for visible morph geometries } UVController::UVController() From 38510a56c206520472e505c7fca24f6f3b6275e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 21:19:55 +0100 Subject: [PATCH 1416/1812] GeomMorpherController: do not dirty the MorphGeometry unless necessary --- components/nifosg/controller.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4dfa4b3041..93c1de89a1 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -235,7 +235,12 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable val = interpKey((*it)->mKeys, input); val = std::max(0.f, std::min(1.f, val)); - morphGeom->setWeight(i, val); + osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); + if (target.getWeight() != val) + { + target.setWeight(val); + morphGeom->dirty(); + } } } From 71cd57a3b54b34b1fa7aa606e5f05aba5e9726e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Nov 2015 22:13:21 +0100 Subject: [PATCH 1417/1812] Optimize World::getTimeStamp World::getTimeStamp was searching through the globals store on every call. Not a big issue, but slow enough to show up in the profiler. --- apps/openmw/mwworld/worldimp.cpp | 60 +++++++++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 9 +++++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d6480b1465..6f63605c78 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -138,8 +138,7 @@ namespace MWWorld { if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - mGlobalVariables["month"].getInteger()); + mRendering->skySetDate (mDay->getInteger(), mMonth->getInteger()); mRendering->setSkyEnabled(true); } @@ -188,18 +187,30 @@ namespace MWWorld if (mEsm[0].getFormat() == 0) ensureNeededRecords(); + fillGlobalVariables(); + mStore.setUp(); mStore.movePlayerRecord(); mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); - mGlobalVariables.fill (mStore); - mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); mWorldScene = new Scene(*mRendering, mPhysics); } + void World::fillGlobalVariables() + { + mGlobalVariables.fill (mStore); + + mGameHour = &mGlobalVariables["gamehour"]; + mDaysPassed = &mGlobalVariables["dayspassed"]; + mDay = &mGlobalVariables["day"]; + mMonth = &mGlobalVariables["month"]; + mYear = &mGlobalVariables["year"]; + mTimeScale = &mGlobalVariables["timescale"]; + } + void World::startNewGame (bool bypass) { mGoToJail = false; @@ -306,7 +317,7 @@ namespace MWWorld mTeleportEnabled = true; mLevitationEnabled = true; - mGlobalVariables.fill (mStore); + fillGlobalVariables(); } int World::countSavedGameRecords() const @@ -798,15 +809,15 @@ namespace MWWorld mWeatherManager->advanceTime (hours, incremental); - hours += mGlobalVariables["gamehour"].getFloat(); + hours += mGameHour->getFloat(); setHour (hours); int days = static_cast(hours / 24); if (days>0) - mGlobalVariables["dayspassed"].setInteger ( - days + mGlobalVariables["dayspassed"].getInteger()); + mDaysPassed->setInteger ( + days + mDaysPassed->getInteger()); } void World::setHour (double hour) @@ -818,10 +829,10 @@ namespace MWWorld hour = std::fmod (hour, 24); - mGlobalVariables["gamehour"].setFloat(static_cast(hour)); + mGameHour->setFloat(static_cast(hour)); if (days>0) - setDay (days + mGlobalVariables["day"].getInteger()); + setDay (days + mDay->getInteger()); } void World::setDay (int day) @@ -829,7 +840,7 @@ namespace MWWorld if (day<1) day = 1; - int month = mGlobalVariables["month"].getInteger(); + int month = mMonth->getInteger(); while (true) { @@ -844,14 +855,14 @@ namespace MWWorld else { month = 0; - mGlobalVariables["year"].setInteger (mGlobalVariables["year"].getInteger()+1); + mYear->setInteger(mYear->getInteger()+1); } day -= days; } - mGlobalVariables["day"].setInteger (day); - mGlobalVariables["month"].setInteger (month); + mDay->setInteger(day); + mMonth->setInteger(month); mRendering->skySetDate(day, month); } @@ -866,30 +877,30 @@ namespace MWWorld int days = getDaysPerMonth (month); - if (mGlobalVariables["day"].getInteger()>days) - mGlobalVariables["day"].setInteger (days); + if (mDay->getInteger()>days) + mDay->setInteger (days); - mGlobalVariables["month"].setInteger (month); + mMonth->setInteger (month); if (years>0) - mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); + mYear->setInteger (years+mYear->getInteger()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); + mRendering->skySetDate (mDay->getInteger(), month); } int World::getDay() const { - return mGlobalVariables["day"].getInteger(); + return mDay->getInteger(); } int World::getMonth() const { - return mGlobalVariables["month"].getInteger(); + return mMonth->getInteger(); } int World::getYear() const { - return mGlobalVariables["year"].getInteger(); + return mYear->getInteger(); } std::string World::getMonthName (int month) const @@ -914,8 +925,7 @@ namespace MWWorld TimeStamp World::getTimeStamp() const { - return TimeStamp (mGlobalVariables["gamehour"].getFloat(), - mGlobalVariables["dayspassed"].getInteger()); + return TimeStamp (mGameHour->getFloat(), mDaysPassed->getInteger()); } bool World::toggleSky() @@ -942,7 +952,7 @@ namespace MWWorld float World::getTimeScaleFactor() const { - return mGlobalVariables["timescale"].getFloat(); + return mTimeScale->getFloat(); } void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 72093d281b..92027868e8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,13 @@ namespace MWWorld MWPhysics::PhysicsSystem *mPhysics; bool mSky; + ESM::Variant* mGameHour; + ESM::Variant* mDaysPassed; + ESM::Variant* mDay; + ESM::Variant* mMonth; + ESM::Variant* mYear; + ESM::Variant* mTimeScale; + Cells mCells; std::string mCurrentWorldSpace; @@ -135,6 +142,8 @@ namespace MWWorld void ensureNeededRecords(); + void fillGlobalVariables(); + /** * @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon) * @param fileCollections- Container which holds content file names and their paths From 7b64b35eb3eea82911763a7eff67761fcd37c377 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Sun, 22 Nov 2015 19:28:09 -0500 Subject: [PATCH 1418/1812] Added comments (and commentary) to the settings-default.cfg file. --- files/settings-default.cfg | 867 ++++++++++++++++++++++++++++--------- 1 file changed, 666 insertions(+), 201 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d68bc2fef7..2c71f483ab 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,244 +1,709 @@ -# WARNING: Editing this file might have no effect, as these -# settings are overwritten by your user settings file. - -[Video] -resolution x = 800 -resolution y = 600 - -fullscreen = false -window border = true -screen = 0 - -# Minimize the window if it loses key focus? -minimize on focus loss = true - -# Valid values: 0 for no antialiasing, or any power of two -antialiasing = 0 - -vsync = false - -gamma = 1.00 -contrast = 1.00 - -# Maximum framerate in frames per second, 0 = unlimited -framerate limit = 0 - -[GUI] -scaling factor = 1.0 - -# 1 is fully opaque -menu transparency = 0.84 - -# 0 - instantly, 1 - max. delay -tooltip delay = 0 - -subtitles = false - -hit fader = true -werewolf overlay = true - -stretch menu background = false - -# colour definitions (red green blue alpha) -color background owned = 0.15 0 0 1 -color crosshair owned = 1 0.15 0.15 1 - -[General] -# Camera field of view -field of view = 55 - -# Texture filtering mode. valid values: -# bilinear -# trilinear -texture filtering = - -anisotropy = 4 - -screenshot format = png - -[Shadows] -# Shadows are only supported when object shaders are on! -enabled = false - -# Split the shadow maps, allows for a larger shadow distance -split = false - -# Increasing shadow distance will lower the shadow quality. -# Uses "shadow distance" or "split shadow distance" depending on "split" setting. -shadow distance = 1300 -# This one shouldn't be too low, otherwise you'll see artifacts. Use at least 2x max viewing distance. -split shadow distance = 14000 - -# Size of the shadow textures, higher means higher quality -texture size = 1024 - -# Turn on/off various shadow casters -actor shadows = true -misc shadows = true -statics shadows = true -terrain shadows = true - -# Fraction of the total shadow distance after which the shadow starts to fade out -fade start = 0.8 - -debug = false - -[HUD] -crosshair = true - -[Objects] -shaders = true - -[Map] -# Adjusts the scale of the global map -global map cell size = 18 - -local map resolution = 256 - -local map widget size = 512 -local map hud widget size = 256 - -[Cells] -exterior cell load distance = 1 +# WARNING: Editing this file might have no effect, as these settings +# are overwritten by your user settings file. Your user settings file +# varies with your operating system: +# +# Linux: $HOME/.config/openmw +# Mac: $HOME/Library/Preferences/openmw +# Windows: C:\Users\Username\Documents\my games\openmw +# This path may vary depending on your installation hard drive, your +# Windows username, and your default language. +# +# Additionally, the user settings file is often written to disk when +# exiting OpenMW, so comments and changes to that file may also be +# discarded after running OpenMW. While most changes to the file will +# reflect setting changes made in game, some settings can have a wider +# range of values in the settings file than the GUI settings widgets +# allow. You may want to exercise some caution and backup this file +# when editing it by hand. [Camera] -near clip = 5 -# The maximum distance with no pop-in will be: (see RenderingManager::configureFog) -# viewing distance * view frustum factor <= cell size (8192) - loading threshold (1024) -# view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. -# exact factor would depend on FOV -viewing distance = 6666 +# This floating point setting controls the distance to the near +# clipping plane. The value must be greater than zero. Values +# greater than approximately 18.0 will occasionally clip objects in +# the world in front of the character. Values greater than +# approximately 8.0 will clip the character's hands in first person +# view and/or the back of their head in third person view. +near clip = 5.0 -# Culling of objects smaller than a pixel +# This boolean setting determines whether objects that render to one +# pixel or smaller will be culled. It generally improves performance +# to enable this feature. small feature culling = true -[Terrain] -distant land = false +# Set the maximum visible distance. Larger values significantly +# improve rendering in exterior spaces, but also increase the amount +# rendered geometry and significantly reduce the frame rate. This +# value is a floating point value that defaults to 6666.0. This value +# interacts with the "exterior cell load distance" setting in that +# it's probably undesired for this value to provide visibility into +# cells that have not yet been loaded. When cells are visible before +# loading, the geometry will "pop-in" suddenly, creating a jarring +# visual effect. To prevent this effect, this value must be less +# than: +# +# 8192 * exterior cell load distance - 1024 +# +# The constant 8192 is the size of a cell, and 1024 is the threshold +# distance for loading a new cell. Additionally, the "field of view" +# setting also interacts with this setting because the view frustrum +# end is a plane, so you can see further at the edges of the screen +# than you should be able to. This can be observed in game by looking +# at distant objects and rotating the camera so the object are near +# the edge of the screen. As a result, the "viewing distance" setting +# should further be reduced by a factor that depends on the "field of +# view" setting. In the default configuration this reduction is 7%. +# Using this factor, approximate values recommended for other +# "exterior cell load distance" settings are: 14285 for 2 cells, 21903 +# for 3 cells, 29522 for 4 cells, and 35924 for 5 cells. +# +# Reductions of up 25% or more can be required to completely eliminate +# pop-in for wide fields of view and long viewing distances near the +# edges of the screen, but such situations are unusual and probably +# not worth the performance penalty introduced by loading geometry +# obscured by fog in the center of the screen. +# +# This setting can be adjusted in game from the ridiculously low value +# of 2000 to a maximum of 6666, using the "View Distance" slider in +# the Detail tab of the Video panel of the Options menu. See +# RenderingManager::configureFog for the relevant source code. +viewing distance = 6666.0 -shader = true +[Cells] -[Water] -shader = false +# This integer setting determines the number of exterior cells +# adjacent to the character that will be loaded for rendering. It +# interacts with "viewing distance" and "field of view" as described +# previously, and it is generally very wasteful for this value to load +# geometry than will almost never be visible due to viewing distance +# and fog. For low frame rate screenshots of scenic vistas, this +# setting should be set high, and viewing distances adjusted +# accordingly. This value must be greater than or equal to 1. +exterior cell load distance = 1 -refraction = false +[GUI] -rtt size = 512 +# These two settings determine the background color of the tool tip +# and the crosshair when hovering over an item owned by an NPC. The +# color definitions are composed of four floating point values between +# 0.0 and 1.0 inclusive, representing the red, green, blue and alpha +# channels. The alpha value is currently ignored. The crosshair +# color will have no effect if the "crosshair" setting in the HUD +# section is disabled. These colors are used only if the "show owned" +# setting is enabled in the Game section. +color background owned = 0.15 0.0 0.0 1.0 +color crosshair owned = 1.0 0.15 0.15 1.0 -[Sound] -# Device name. Blank means default -device = +# This boolean setting enables or disables the "red flash" overlay +# that provides a visual clue when the character has taken damage. +hit fader = true -# Volumes. master volume affects all other volumes. -master volume = 1.0 -sfx volume = 1.0 -music volume = 0.5 -footsteps volume = 0.2 -voice volume = 0.8 +# This floating point setting controls the transparency of the GUI +# windows. The value should be between 0.0 (transparent) and 1.0 +# (opaque). The setting can be adjusted in game with the "Menu +# Transparency" slider in the Prefs panel of the Options menu. +menu transparency = 0.84 +# This floating point setting scales the GUI interface windows. The +# value must be greater than 0.0. A value of 1.0 results in the +# default scale. Values much larger than 2.0 may result in user +# interface components being inaccessible. +scaling factor = 1.0 + +# Stretch or shrink the introductory movie, new game screen, and +# loading screens to fill the specified video resolution. The default +# assets have a 4:3 aspect ratio, but other assets may have other +# resolutions. If this setting is false, the assets will be centered +# in their correct aspect ratio. +stretch menu background = false + +# Enable or disable subtitles for NPC spoken dialog (and some sound +# effects). Subtitles will appear in a tool tip box in the lower +# center of the screen. The setting can be toggled in game with the +# "Subtitles" button in the Prefs panel of Options menu. +subtitles = false + +# Set the delay between when you begin hovering over an item and when +# it's tooltip appears. This setting is a floating point value +# between 0.0, which displays the tool tip instantly and 1.0 which +# results in the maximum delay (approximately 1.5 seconds). This +# setting does not affect the tooltip delay for object under the +# crosshair in the "look mode", only widgets in the GUI windows. This +# setting can be adjusted in game with the "Menu Help Delay" slider in +# the Prefs panel of the Options menu. +tooltip delay = 0.0 + +# Enable or disable the werewolf overlay. Unable to evaluate fully +# due to issues with becoming a werewolf. +werewolf overlay = true + +[Game] + +# If this boolean setting is true, the character will always use the +# most powerful attack when striking with a weapon (chop, slash or +# thrust). If this setting is false, the type of attack is determined +# by the direction that the character is moving at the time the attack +# begins. The setting can be toggled with the "Always Use Best +# Attack" button in the Prefs panel of the Options menu. +best attack = false + +# This integer setting adjusts the difficulty of the game and is +# intended to be in the range -100 to 100 inclusive. Given the +# default game setting for fDifficultyMult of 5.0, a value of -100 +# results in the player taking 80% of the usual damage, doing 6 times +# the normal damage. A value of 100 results in the player taking 6 +# times as much damage, but inflicting only 80% of the usual damage. +# Values less than -500 will result in the player receiving no damage, +# and values greater than 500 will result in the player inflicting no +# damage. The setting can be controlled in game with the Difficulty +# slider in the Prefs panel of the Options menu. +difficulty = 0 + +# Show the remaining duration of magic effects and lights if this +# boolean setting is true. The remaining duration is displayed in the +# tooltip by hovering over the magical effect. +show effect duration = false + +# Enable visual clues for items owned by NPCs when the crosshair is on +# the object. If the setting is 0, no clues are provided which is the +# default Morrowind behavior. If the setting is 1, the background of +# the tool tip for the object is highlight in the color specified by +# the "color background owned" setting in the "GUI" section. If the +# setting is 2, the crosshair is the color of the "color crosshair +# owned" setting in the "GUI" section. If the setting is 3, both the +# tool tip background and the crosshair are colored. Settings 2 and 3 +# only color the crosshair if it's enabled in the "HUD" section. +show owned = 0 + +[General] + +# Set the maximum anisotropic filtering on textures. Anisotropic +# filtering is a method of enhancing the image quality of textures on +# surfaces that are at oblique viewing angles with respect to the +# camera. Valid values range from 0 to 16. Modern video cards can +# often perform 8 or 16 anisotropic filtering with a minimal +# performance impact. This effect of this setting can be seen in the +# Video panel of the Options menu by finding a location with straight +# lines (striped rugs and Balmora cobblestones work well) radiating +# into the distance, and adjusting the anisotropy slider. This +# setting can be changed in game using the "Anisotropy" slider in the +# Detail tab of the Video panel of the Options menu. +anisotropy = 4 + +# Sets the camera field of view in degrees. Recommended values range +# from 30 degrees to 110 degrees. Small values provide a very narrow +# field of view that creates a "zoomed in" effect, while large values +# cause distortion at the edges of the screen. The "field of view" +# setting interacts with aspect ratio of your video resolution in that +# more square aspect ratios (e.g. 4:3) need a wider field of view to +# more resemble the same field of view on a widescreen (e.g. 16:9) +# monitor. This setting can be adjusted in game from the Video tab of +# the Video panel of the Options menu using the "Field of View" +# slider. +field of view = 55.0 + +# Specify the format for screenshots taken by pressing F12. This +# setting should be the file extension commonly associated with the +# desired format. The formats supported will be determined at +# compilation, but "jpg", "png", and "tga" should be allowed. +screenshot format = png + +# Set the isotropic texture filtering mode to bilinear or trilinear. +# Bilinear filtering is a texture filtering method used to smooth +# textures when displayed larger or smaller than they actually are. +# Bilinear filtering is reasonably accurate until the scaling of the +# texture gets below half or above double the original size of the +# texture. Trilinear filtering is an extension of the bilinear +# texture filtering method, which also performs linear interpolation +# between mipmaps. Both methods use mipmaps in OpenMW, and the +# corresponding OpenGL modes are LINEAR_MIPMAP_NEAREST and +# LINEAR_MIPMAP_LINEAR. Trilinear filtering produces better texturing +# at a minimal cost on modern video cards. This setting can be +# changed in game using the "Texture filtering" pull down in the +# Detail tab of the Video panel of the Options menu. +texture filtering = trilinear + +[HUD] + +# This boolean setting determines whether the crosshair or reticle is +# displayed. If this setting is disabled it will override "show +# owned" and "color crosshair owned". This setting can be toggled +# with the "Crosshair" button in the Prefs panel of the Options menu. +crosshair = true [Input] -grab cursor = true - -invert y axis = false - -camera sensitivity = 1.0 - -ui sensitivity = 1.0 - -camera y multiplier = 1.0 - -always run = false - +# Allow zooming in and out using the middle mouse wheel in third +# person view. allow third person zoom = false +# If this boolean setting is true, the character is running by +# default, otherwise the character is walking by default. The shift +# key will temporarily invert this setting, and the caps lock key will +# invert this setting while it's "locked". Confusingly, this setting +# is updated every time you exit the game, based on whether the caps +# lock key was on or off at the time you exited. +always run = false + +# This floating point setting controls the camera/mouse sensitivity +# when in "look mode". The default sensitivity is 1.0, with smaller +# values requiring more mouse movement, and larger values requiring +# less. This setting is multiplicative in magnitude. This setting +# does not affect mouse speed in GUI mode. +camera sensitivity = 1.0 + +# This floating point setting controls the vertical camera/mouse +# sensitivity relative to the horizontal sensitivity (see "camera +# sensitivity") above. It is multiplicative with the previous +# setting, meaning that it should remain set at 1.0 unless the player +# desires to have different sensitivities in the two axes. +camera y multiplier = 1.0 + +# OpenMW will capture control of the cursor if this boolean setting is +# true. In "look mode", OpenMW will capture the cursor regardless of +# the value of this setting (since the cursor/crosshair is always +# centered in the OpenMW window). However, in GUI mode, this setting +# determines the behavior when the cursor is moved outside the OpenMW +# window. If true, the cursor movement stops at the edge of the +# window preventing access to other applications. If false, the +# cursor is allowed to move freely on the desktop. +# +# This setting does not apply to the screen where escape has been +# pressed, where the cursor is never captured. Regardless of this +# setting "Alt-Tab" or some other operating system dependent key +# sequence can be used to allow the operating system to regain control +# of the mouse cursor. This setting interacts with the "minimize on +# focus loss" setting by affecting what counts as a focus loss. +# Specifically on a two-screen configuration it may be more convenient +# to access the second screen with setting disabled. +grab cursor = true + +# Invert the vertical axis while in "look mode". If this setting is +# true, moving the mouse away from the player will look down, while +# moving it towards the player will look up. This setting does not +# affect cursor movement in GUI mode. +invert y axis = false + +# This boolean setting causes the behavior of the sneak key (Ctrl by +# default) to toggle sneaking on and off rather than requiring the key +# to be held while sneaking. Players that spend significant time +# sneaking may find the character easier to control with this option +# enabled. toggle sneak = false -[Game] -# Always use the most powerful attack when striking with a weapon (chop, slash or thrust) -best attack = false +# This setting continues to be loaded and saved, but has no known +# effect. Presumably it and a related but also removed option named +# "ui y sensitivity" used to control mouse sensitivity while in GUI +# mode. The default value is 1.0. +ui sensitivity = 1.0 -difficulty = 0 +[Map] -# Change crosshair/toolTip color when pointing on owned object -#0: nothing changed -#1: tint toolTip -#2: tint crosshair -#3: both -show owned = 0 -# Show the remaining duration of magic effects and lights -show effect duration = false +# It is not currently possible to control how many adjacent cells are +# displayed in the map. It appears that this is hardcoded to one +# adjacent cell (3x3) in the code. These settings control the canvas +# and resolution sizes, and therefore the amount of panning required +# to see the entire map, and the level of detail visible. + +# This integer setting adjusts the scale of the world map in the GUI +# mode map display. The value is the width in pixels of each cell in +# the map, so larger values result in larger more detailed world maps, +# while smaller values result in smaller less detailed world maps. +# However, the native resolution of the map source material appears to +# be 9 pixels per unexplored cell and approximately 18 pixels per +# explored cell, so values larger than 36 don't produce much +# additional detail. Similarly, the size of place markers is +# currently fixed at 12 pixels, so values smaller than this result in +# overlapping place markers. Values from 12 to 36 are recommended. +# For reference, Vvardenfell is approximately 41x36 cells. +global map cell size = 18 + +# This integer setting controls the zoom level for the HUD map display +# (the map in the lower right corner while not in GUI mode). A value +# of 64 results in the HUD map displaying one exterior cell. Since +# the GUI mode map displays 3x3 cells, a value of approximately 21 +# displays the same area as the GUI mode map. Larger values increase +# the level of zoom, while smaller values are wasteful. +# +# Note that the actual size of the widget is always the same on the +# screen unless the "scaling factor" setting in the "GUI" section is +# changed. Increasing both the scaling factor of the GUI and this +# setting does result in a higher resolution HUD map, but +# unfortunately with a scaled direction pointer on top of it. +local map hud widget size = 256 + +# This integer setting controls the resolution of the GUI mode local +# map widget. Larger values generally increase the visible detail in +# map. If this setting is half the "local map widget size" or +# smaller, the map will generally be be fairly blurry. Setting the +# both options to the same value results in a map with good detail. +# Values that exceed the "local map widget size" setting by more than +# a factor of two are unlikely to provide much of an improvement in +# detail since they're subsequently scaled back to the approximately +# the map widget size before display. The video resolution setting +# interacts with this setting in that regard. +local map resolution = 256 + +# This integer setting controls the canvas size of the GUI mode local +# map widget. Larger values result in a larger physical map size on +# screen, and typically require more panning to see all available +# portions of the map. This larger size also enables an overall +# greater level of detail if the "local map resolution" setting is +# also increased. +local map widget size = 512 + +[Objects] + +# This boolean setting currently has no known impact, but is +# presumably intended to enable shaders for objects other than water. +# Whenever the setting file is written by the game, this option is +# currently reset to false. +shaders = true [Saves] + +# This string setting contains the default character name for loading +# saved games. This setting is automatically updated from the Load +# game menu option when a different character is selected. character = -# Save when resting + +# This boolean setting determines whether the game will be +# automatically saved when the character rests. This setting can be +# toggled in game with the "Auto-Save when Rest" button in the Prefs +# panel of the Options menu. autosave = true -# display time played + +# This boolean setting determines whether the amount of the time the +# player has spent playing will displayed for each saved game in the +# menu for saving and loading games. This setting can not currently +# be adjusted in game. This setting is disabled by default for players +# who would prefer not to know how many hours they've spent +# playing. :-) timeplayed = false +[Shadows] + +# Shadows in general are dependent on the "shaders" setting be enabled +# in the Objects section. Additionally, the "enabled" setting in this +# section must be true for any other options in this section to have +# effect. Both that setting and the Shadows section options are +# temporarily disabled following the conversion to the OpenSceneGraph +# engine. None of these option can be adjusted in game at the present +# time. + +# This boolean setting enables actors to cast shadows. +actor shadows = true + +# Enable debugging of shadows? +debug = false + +# Are shadows enabled in general? +enabled = false + +# This floating point setting determines the fraction of the total +# shadow distance after which the shadow starts to fade out. +fade start = 0.8 + +# Allows miscellaneous object to cast shadows. +misc shadows = true + +# This setting will only have effect if the "split" setting in the +# Shadows section is false. Increasing shadow distance will lower the +# shadow quality. +shadow distance = 1300 + +# Split the shadow maps, allowing for a larger shadow distance? +split = false + +# This setting will only have effect if the "split" setting in the +# Shadows section is true. # This one shouldn't be too low, otherwise +# you'll see artifacts. Use at least 2x max viewing distance. +split shadow distance = 14000 + +# Allow static objects to cast shadows. +statics shadows = true + +# Allow terrain to cast shadows. +terrain shadows = true + +# Size of the shadow textures. Higher resolution texture produce more +# detailed shadows and a better visual effect. +texture size = 1024 + +[Sound] + +# This string setting determines which audio device to use. A blank or +# missing setting means to use the default device, which should +# usually be sufficient, but if you need to explicitly specify a +# device name try doing so here. +device = + +# The settings in the Sound section are generally floating point +# settings in the range from 0.0 (silent) to 1.0 (maximum volume). +# All sound settings are multiplied by the "master volume" setting, and +# will thus have no effect if the master volume is set to 0.0. These +# settings can be adjusted in game from the Audio panel of the Options +# menu under the appropriately labeled slider. + +# The volume of footsteps from the character and other actors. +footsteps volume = 0.2 + +# The master volume is multiplied with all other volume settings to +# determine the final volume +master volume = 1.0 + +# The volume for music tracks. +music volume = 0.5 + +# The volume for special effect sounds such as combat noises, etc. +sfx volume = 1.0 + +# The volume for spoken dialog from NPCs. +voice volume = 0.8 + +[Terrain] + +# Not currently used, presumably due to the OpenSceneGraph upgrade. +distant land = false + +# Not currently used, presumably due to the OpenSceneGraph upgrade. +shader = true + +[Video] + +# This integer setting controls anti-aliasing. Anti-aliasing is +# technique designed to reduce distortions called aliasing caused by +# displaying high resolution textures at a lower resolution. +# Anti-aliasing can correct these distortions at the cost of a minor +# reduction in the frame rate. A value of 0 disables anti-aliasing. +# Other powers of two (e.g. 2, 4, 8, 16) are supported according to +# the capabilities of your graphics hardware. Higher values do a +# better job of correcting the distortion and have a greater impact on +# frame rate. This setting can be configured from a list of valid +# choices in the Graphics panel of the OpenMW Launcher. +antialiasing = 0 + +# This floating point setting controls the contrast correction for all +# video in the game. This setting does not currently work under +# Linux, and the in-game setting in the Options menu has been +# disabled. +contrast = 1.00 + +# This floating point setting determines the maximum frame rate in +# frames per second. If this setting is 0.0, the frame rate is +# unlimited. There are several reasons to consider capping your frame +# rate, especially if you're already experiencing a relatively high +# frame rate (greater than 60 frames per second). Lower frame rates +# will consume less power and generate less heat and noise. Frame +# rates above 60 frames per second rarely produce perceptible +# improvements in visual quality. Capping the frame rate may in some +# situations reduce the perception of choppiness (highly variable +# frame rates during game play) by lowering the peak frame rates. +# This setting interacts with the "vsync" setting in the Video section +# in the sense that enabling vertical sync limits the frame rate to +# the refresh rate of your monitor (often 60 frames per second). +framerate limit = 0.0 + +# This boolean setting determines whether the entire screen is used +# for the specified resolution. This setting can be toggled in game +# using the "Fullscreen" button in the Video tab of the Video panel in +# the Options menu. It can also be toggled with the "Full Screen" +# check box in the Graphic tab of the OpenMW Launcher. +fullscreen = false + +# Theses two setting determine the horizontal and vertical resolution +# of the OpenMW game window. Larger values produce more detailed +# images within the constraints of your graphics hardware but also +# significantly reduce the frame rate. The window resolution can be +# selected from a menu of common screen sizes in the Video tab of the +# Video Panel of the Options menu. The resolution can also be set to +# a custom value in the Graphics tab of the OpenMW Launcher. +resolution x = 800 +resolution y = 600 + +# This boolean setting determines whether there's an operating system +# border drawn around the OpenMW window. If this setting is true, the +# window can be moved and resized with the operating system window +# controls. If this setting is false, the window has no operating +# system border. This setting has no effect if the "fullscreen" +# setting in the Video section is true. This setting can be toggled +# in game using the "Window Border" button in the Video tab of the +# Video panel in the Options menu. It can also be toggled with the +# "Window Border" check box in the OpenMW Launcher. +window border = true + +# This integer setting determines which screen the game will open on +# in multi-monitor configurations. This setting is particularly +# important when "fullscreen" setting in the Video section is true, +# since this is the only way to control which screen is used, but it +# can also be used to control which screen a normal window or a +# borderless window opens on as well. This setting can be selected +# from a pull down menu in the Graphics tab of the OpenMW Launcher, +# but not adjusted during game play. +screen = 0 + +# Minimize the OpenMW window if it loses cursor focus. This setting +# has no effect if the "fullscreen" setting is false. This setting is +# primarily useful for single screen configurations, so that the +# OpenMW screen in full screen mode can be minimized when the +# operating system regains control of the mouse and keyboard. On +# multiple screen configurations, disabling this option make make it +# easier to switch between screens while playing OpenMW. +minimize on focus loss = true + +# This boolean setting determines whether frame draws are synchronized +# with the vertical refresh rate of your monitor. Enabling this +# setting can reduce "tearing", a visual defect caused by updating the +# image buffer in the middle of a screen draw. Enabling this option +# typically implies limiting the framerate to 60 frames per second, +# but may also introduce additional delays caused by having to wait +# until the appropriate time (the vertical blanking interval) to draw +# a frame. + +# This setting can be adjusted in game using the "VSync" button in the +# Video tab of the Video panel in the Options menu. It can also be +# changed by toggling the "Vertical Sync" check box in the Graphics +# tab of the OpenMW Launcher. +vsync = false + +# This floating point setting controls the gamma correction for all +# video in the game. This setting does not currently work under +# Linux, and the in-game setting in the Options menu has been +# disabled. +gamma = 1.00 + +[Water] + +# The water settings can be tested experimentally in the Water tab of +# the Video panel in the Options menu. Changes there will be saved to +# these settings. + +# This boolean setting enables the refraction rendering feature of the +# water shader. Refraction causes deep water to be more opaque and +# objects seen through the plane of the water to have a wavy +# appearance. Enabling this feature results in better visuals, and a +# marginally lower framerate depending on your graphics hardware. The +# "shader" setting in the Water section must be enabled for this +# setting to have any effect. +refraction = false + +# Refracted texture size. In the Video panel of the options menu, the +# choices are Low (512), Medium (1024) and High (2048). This setting +# determines the resolution of the textures used for rendering objects +# on the other wide of the plane of water (which have a wavy +# appearance caused the by the refraction). Higher values produces +# better visuals and result in a marginally lower framerate depending +# on your graphics hardware. The "refraction" setting in the "Water" +# section must be enabled for this setting to have any effect. +rtt size = 512 + +# This boolean setting enables or disables the water shader, which +# results in much more realistic looking water surfaces, including +# shadows of reflected objects. +shader = false + [Windows] -inventory x = 0 -inventory y = 0.4275 -inventory w = 0.6225 -inventory h = 0.5725 -inventory container x = 0 -inventory container y = 0.4275 -inventory container w = 0.6225 -inventory container h = 0.5725 - -inventory barter x = 0 -inventory barter y = 0.4275 -inventory barter w = 0.6225 -inventory barter h = 0.5725 - -inventory companion x = 0 -inventory companion y = 0.4275 -inventory companion w = 0.6225 -inventory companion h = 0.5725 - -container x = 0.25 -container y = 0 -container w = 0.75 -container h = 0.375 - -companion x = 0.25 -companion y = 0 -companion w = 0.75 -companion h = 0.375 - -map x = 0.625 -map y = 0 -map w = 0.375 -map h = 0.5725 - -barter x = 0.25 -barter y = 0 -barter w = 0.75 -barter h = 0.375 +# Each window in the GUI mode remembers it's previous location. Each +# setting is a floating point number representing a fraction of the +# "resolution x" or "resolution y" setting in the Video section. The +# X and Y values locate the top left corner, while the W value +# determines the width of the window and the H value determines the +# height of the window. +# The alchemy window, for crafting potions. Activated by dragging an +# alchemy tool on to the rag doll. Unlike most other windows, this +# window hides all other windows when opened. +alchemy h = 0.5 +alchemy w = 0.5 alchemy x = 0.25 alchemy y = 0.25 -alchemy w = 0.5 -alchemy h = 0.5 -stats x = 0 -stats y = 0 -stats w = 0.375 -stats h = 0.4275 +# The NPC bartering window, displaying goods owned by the shopkeeper +# while bartering. Activated by clicking on the "Barter" choice in +# the dialog window for an NPC. +barter h = 0.375 +barter w = 0.75 +barter x = 0.25 +barter y = 0 -spells x = 0.625 -spells y = 0.5725 -spells w = 0.375 -spells h = 0.4275 +# Unused? +companion h = 0.375 +companion w = 0.75 +companion x = 0.25 +companion y = 0 +# The console command window. Activated by pressing the tilde (~) key. +console h = 0.5 +console w = 1 console x = 0 console y = 0 -console w = 1 -console h = 0.5 +# The container window, showing the contents of the container. +# Activated by clicking on a container. The same window is used for +# searching dead bodies, and pickpocketing people. +container h = 0.375 +container w = 0.75 +container x = 0.25 +container y = 0 + +# The dialog window, for talking with NPCs. Activated by clicking on a +# NPC. dialogue h = 0.810 dialogue w = 0.810 dialogue x = 0.095 dialogue y = 0.095 + +# The character inventory window while bartering. It displays goods +# owned by the character while bartering. Activated by clicking on the +# "Barter" choice in the dialog window for an NPC. +inventory barter h = 0.5725 +inventory barter w = 0.6225 +inventory barter x = 0 +inventory barter y = 0.4275 + +# Unused? +inventory companion h = 0.5725 +inventory companion w = 0.6225 +inventory companion x = 0 +inventory companion y = 0.4275 + +# The character inventory window while searching a container, showing +# the contents of the character's inventory. Activated by clicking on +# a container. The same window is used for searching dead bodies, and +# pickpocketing people. +inventory container h = 0.5725 +inventory container w = 0.6225 +inventory container x = 0 +inventory container y = 0.4275 + +# The inventory window, displaying the paper doll and possessions. +# Activated by clicking on the inventory widget (second from left) in +# the bottom left corner of the HUD. +inventory h = 0.5725 +inventory w = 0.6225 +inventory x = 0 +inventory y = 0.4275 + +# The local and world map window. Activated by clicking on the map +# widget in the bottom right corner of the HUD. +map h = 0.5725 +map w = 0.375 +map x = 0.625 +map y = 0 + +# The spells window, displaying powers, spells, and magical items. +# Activated by clicking on the spells widget (third from left) in the +# bottom left corner of the HUD. +spells h = 0.4275 +spells w = 0.375 +spells x = 0.625 +spells y = 0.5725 + +# The stats window, displaying level, race, class, skills and stats. +# Activated by clicking on any of the three bars in the lower left +# corner of the HUD. +stats h = 0.4275 +stats w = 0.375 +stats x = 0 +stats y = 0 From 3fe38e3556d31194d8c293426b7b7e2c5dc4bd3b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Nov 2015 03:26:21 +0100 Subject: [PATCH 1419/1812] Remove unused setting --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ---- apps/openmw/mwinput/inputmanagerimp.hpp | 1 - files/settings-default.cfg | 2 -- 3 files changed, 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0c306da68d..0d1dc0e625 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,7 +53,6 @@ namespace MWInput , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mControlsDisabled(false) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) - , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) @@ -586,9 +585,6 @@ namespace MWInput if (it->first == "Input" && it->second == "camera sensitivity") mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input"); - if (it->first == "Input" && it->second == "ui sensitivity") - mUISensitivity = Settings::Manager::getFloat("ui sensitivity", "Input"); - if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index fc539f5222..3b11e04c09 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -174,7 +174,6 @@ namespace MWInput bool mControlsDisabled; float mCameraSensitivity; - float mUISensitivity; float mCameraYMultiplier; float mPreviewPOVDelay; float mTimeIdle; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d68bc2fef7..85434ff326 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -145,8 +145,6 @@ invert y axis = false camera sensitivity = 1.0 -ui sensitivity = 1.0 - camera y multiplier = 1.0 always run = false From 69acacefff5237a851d813e51c67c7b7116a7a57 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Mon, 23 Nov 2015 20:28:35 +0300 Subject: [PATCH 1420/1812] openmw building on Android with Opengl es --- CMakeLists.txt | 44 +++-- apps/openmw/CMakeLists.txt | 34 +++- apps/openmw/android_main.c | 1 - apps/openmw/main.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 5 + apps/openmw/mwrender/sky.cpp | 5 + apps/openmw/mwrender/water.cpp | 11 +- cmake/FindOpenGLES.cmake | 94 +++++++++++ cmake/FindOpenGLES2.cmake | 170 +++++++++++++++++++ components/CMakeLists.txt | 103 +++++++----- components/sdlutil/sdlcursormanager.cpp | 3 + files/shaders/CMakeLists.txt | 20 ++- files/shaders/watergles_fragment.glsl | 209 ++++++++++++++++++++++++ files/shaders/watergles_vertex.glsl | 24 +++ 14 files changed, 655 insertions(+), 70 deletions(-) create mode 100644 cmake/FindOpenGLES.cmake create mode 100644 cmake/FindOpenGLES2.cmake create mode 100644 files/shaders/watergles_fragment.glsl create mode 100644 files/shaders/watergles_vertex.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fac1b77f2..4b46542e7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,8 +47,20 @@ include(OpenMWMacros) if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") + set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) + add_definitions (-DOSG_PLUGINS_DIR) + set(OPENGLES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) +option(OPENGLES "enable opengl es support" FALSE ) + +if (OPENGLES) + INCLUDE(cmake/FindOpenGLES.cmake) + INCLUDE(cmake/FindOpenGLES2.cmake) + add_definitions (-DOPENGLES) + INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) +endif (OPENGLES) + # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -145,21 +157,21 @@ if (WIN32) endif() # Dependencies +if (NOT ANDROID) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + message(STATUS "Using Qt${DESIRED_QT_VERSION}") -set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") -message(STATUS "Using Qt${DESIRED_QT_VERSION}") - -if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) -else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) + if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) + else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) + endif() endif() - # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) @@ -189,7 +201,11 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +if (NOT ANDROID) + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +else() + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +endif() include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 59a523023f..1f0fe71ab9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -134,18 +134,50 @@ target_link_libraries(openmw ) if (ANDROID) + set (OSG_PLUGINS + -Wl,--whole-archive + ${OSG_PLUGINS_DIR}/libosgdb_dds.a + ${OSG_PLUGINS_DIR}/libosgdb_bmp.a + ${OSG_PLUGINS_DIR}/libosgdb_tga.a + ${OSG_PLUGINS_DIR}/libosgdb_gif.a + ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a + ${OSG_PLUGINS_DIR}/libosgdb_png.a + -Wl,--no-whole-archive + ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic - cpufeatures BulletCollision LinearMath + z + osg + osgDB + osgAnimation + osgText + osgUtil + osgShadow + ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_PLUGINS} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + jpeg + gif + png ) endif (ANDROID) +if (OPENGLES) + target_link_libraries(openmw + ${OPENGLES_gl_LIBRARY} + ${OPENGLES2_gl_LIBRARY} + ) +endif (OPENGLES) + if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 47b77a8b38..8cd69e8f01 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,4 +1,3 @@ -#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 17ef46246a..c3f0f8688e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 14ec770e84..077d215127 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -24,6 +24,11 @@ #include "vismask.hpp" +#ifdef OPENGLES + #include +#endif + + namespace { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 66253f70d5..7572d7e92f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -45,6 +45,11 @@ #include "vismask.hpp" #include "renderbin.hpp" +#ifdef OPENGLES + #include +#endif + + namespace { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ca099991ea..5a9bc664a9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -40,6 +40,10 @@ #include "ripplesimulation.hpp" #include "renderbin.hpp" +#ifdef OPENGLES +#include +#endif + namespace { @@ -575,10 +579,13 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R // use a define map to conditionally compile the shader std::map defineMap; defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); - +#ifdef OPENGLES + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/watergles_vertex.glsl", defineMap)); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/watergles_fragment.glsl", defineMap)); +#else osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); - +#endif osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake new file mode 100644 index 0000000000..7ee2c07f18 --- /dev/null +++ b/cmake/FindOpenGLES.cmake @@ -0,0 +1,94 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES +# Once done this will define +# +# OPENGLES_FOUND - system has OpenGLES +# OPENGLES_INCLUDE_DIR - the GL include directory +# OPENGLES_LIBRARIES - Link these to use OpenGLES + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") + ELSE(BORLAND) + #MS compiler - todo - fix the following line: + SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES) + #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h + /opt/vc/include + /opt/graphics/OpenGL/include + /usr/openwin/share/include + /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY + NAMES GLES_CM GLESv1_CM + PATHS /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + + #IF (OPENGLES_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES_FOUND "NO" ) +IF(OPENGLES_gl_LIBRARY) + + SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) + + SET( OPENGLES_FOUND "YES" ) + +ENDIF(OPENGLES_gl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES_INCLUDE_DIR + OPENGLES_gl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/cmake/FindOpenGLES2.cmake b/cmake/FindOpenGLES2.cmake new file mode 100644 index 0000000000..136e7618be --- /dev/null +++ b/cmake/FindOpenGLES2.cmake @@ -0,0 +1,170 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES and EGL +# If using ARM Mali emulation you can specify the parent directory that contains the bin and include directories by +# setting the MALI_SDK_ROOT variable in the environment. +# +# For AMD emulation use the AMD_SDK_ROOT variable +# +# Once done this will define +# +# OPENGLES2_FOUND - system has OpenGLES +# OPENGLES2_INCLUDE_DIR - the GL include directory +# OPENGLES2_LIBRARIES - Link these to use OpenGLES +# +# EGL_FOUND - system has EGL +# EGL_INCLUDE_DIR - the EGL include directory +# EGL_LIBRARIES - Link these to use EGL + +#include(FindPkgMacros) + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32") + ELSE(BORLAND) + #getenv_path(AMD_SDK_ROOT) + #getenv_path(MALI_SDK_ROOT) + + SET(POWERVR_SDK_PATH "C:/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds") + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + ${POWERVR_SDK_PATH}/Include + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" + ) + + FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + ${POWERVR_SDK_PATH}/Include + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" + ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY + NAMES libGLESv2 + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + ${POWERVR_SDK_PATH}/Windows/x86_32/Lib + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" + ) + + FIND_LIBRARY(EGL_egl_LIBRARY + NAMES libEGL + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + ${POWERVR_SDK_PATH}/Windows/x86_32/Lib + "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" + ) + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES2) + #set(OPENGLES2_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + #getenv_path(AMD_SDK_ROOT) + #getenv_path(MALI_SDK_ROOT) + + FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include + /opt/vc/include + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES2_gl_LIBRARY + NAMES GLESv2 + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib + /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h + ${ENV_AMD_SDK_ROOT}/include + ${ENV_MALI_SDK_ROOT}/include + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include + /opt/vc/include + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(EGL_egl_LIBRARY + NAMES EGL + PATHS ${ENV_AMD_SDK_ROOT}/x86 + ${ENV_MALI_SDK_ROOT}/bin + /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib + /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + # It's not true on OSX. + + #IF (OPENGLES2_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # IF (NOT APPLE) + # SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (NOT APPLE) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES2_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES2_FOUND "YES" ) +IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) + + SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES}) + SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES}) + SET( OPENGLES2_FOUND "YES" ) + +ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES2_INCLUDE_DIR + OPENGLES2_gl_LIBRARY + EGL_INCLUDE_DIR + EGL_egl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES2 REQUIRED_VARS OPENGLES2_LIBRARIES OPENGLES2_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c80e27e4d8..7bfbf6d935 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,8 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -find_package(OpenGL REQUIRED) - +if (NOT ANDROID) + find_package(OpenGL REQUIRED) +endif() # source files add_component_dir (settings @@ -137,31 +138,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) -add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) +if (NOT ANDROID) + add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) + add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) -add_component_qt_dir (process - processinvoker -) - -if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) -else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + add_component_qt_dir (process + processinvoker + ) + if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + endif() endif() - if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) @@ -172,32 +173,46 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} -) +if (NOT ANDROID) + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} + ) +else() + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + ${MYGUI_LIBRARIES} + ) +endif() if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) -else() - qt5_use_modules(components Widgets Core) +if (NOT ANDROID) + if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) + else() + qt5_use_modules(components Widgets Core) + endif() endif() - if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index e1a67aff81..23f01f3a7b 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,6 +217,9 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { + #ifdef ANDROID + return; + #endif if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index fc4706c1f6..da25502755 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -1,11 +1,17 @@ # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) - -set(SHADER_FILES - water_vertex.glsl - water_fragment.glsl - water_nm.png -) - +if (OPENGLES) + set(SHADER_FILES + watergles_vertex.glsl + watergles_fragment.glsl + water_nm.png + ) +else() + set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png + ) +endif() copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/watergles_fragment.glsl b/files/shaders/watergles_fragment.glsl new file mode 100644 index 0000000000..e3f756087b --- /dev/null +++ b/files/shaders/watergles_fragment.glsl @@ -0,0 +1,209 @@ +#version 100 +precision mediump float; +precision mediump int; + +struct osg_LightSourceParameters { + mediump vec4 ambient; + mediump vec4 diffuse; + mediump vec4 specular; + mediump vec4 position; + mediump vec4 halfVector; + mediump vec3 spotDirection; + mediump float spotExponent; + mediump float spotCutoff; + mediump float spotCosCutoff; + mediump float constantAttenuation; + mediump float linearAttenuation; + mediump float quadraticAttenuation; + }; +uniform osg_LightSourceParameters osg_LightSource[1]; + +#define REFRACTION @refraction_enabled + +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) + +// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +const float VISIBILITY = 1200.0; // how far you can look through water + +const float BIG_WAVES_X = 0.1; // strength of big waves +const float BIG_WAVES_Y = 0.1; + +const float MID_WAVES_X = 0.1; // strength of middle sized waves +const float MID_WAVES_Y = 0.1; + +const float SMALL_WAVES_X = 0.1; // strength of small waves +const float SMALL_WAVES_Y = 0.1; + +const float WAVE_CHOPPYNESS = 0.05; // wave choppyness +const float WAVE_SCALE = 75.0; // overall wave scale + +const float BUMP = 0.5; // overall water surface bumpiness +const float REFL_BUMP = 0.10; // reflection distortion amount +const float REFR_BUMP = 0.07; // refraction distortion amount + +const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering +const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering + +const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction + +const float SPEC_HARDNESS = 256.0; // specular highlights hardness + +const vec2 WIND_DIR = vec2(0.5, -0.8); +const float WIND_SPEED = 0.2; + +const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + +// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + +float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +{ + 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; + + return result; +} + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +uniform sampler2D normalMap; + +uniform sampler2D reflectionMap; +#if REFRACTION +uniform sampler2D refractionMap; +uniform sampler2D refractionDepthMap; +#endif + +uniform float osg_SimulationTime; + +uniform float near; +uniform float far; +uniform vec3 nodePosition; + +void main(void) +{ + vec3 worldPos = position.xyz + nodePosition.xyz; + vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; + UV.y *= -1.0; + + float shadow = 1.0; + + vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; + screenCoords.y = (1.0-screenCoords.y); + + vec2 nCoord = vec2(0.0,0.0); + + #define waterTimer osg_SimulationTime + + nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); + vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; + vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; + vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; + vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; + + + + vec3 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); + + normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); + + normal = vec3(-normal.x, -normal.y, normal.z); + + // normal for sunlight scattering + vec3 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).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); + + + vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(osg_LightSource[0].position.xyz, 0.0)).xyz); + + vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0)).xyz; + vec3 vVec = normalize(position.xyz - cameraPos.xyz); + + float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; + + // sunlight scattering + vec3 pNormal = vec3(0.0,0.0,1.0); + vec3 lR = reflect(lVec, lNormal); + vec3 llR = reflect(lVec, pNormal); + + float sunHeight = lVec.z; + float sunFade = length(gl_LightModel.ambient.xyz); + + float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); + float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + + // fresnel + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float fresnel = fresnel_dielectric(vVec, normal, ior); + + fresnel = clamp(fresnel, 0.0, 1.0); + + // reflection + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + + // refraction +#if REFRACTION + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + + // brighten up the refraction underwater + refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; +#endif + + // specular + vec3 R = reflect(vVec, normal); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; + + vec3 waterColor = WATER_COLOR; + waterColor = waterColor * length(gl_LightModel.ambient.xyz); +#if REFRACTION + float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; + float z_n = 2.0 * refractionDepth - 1.0; + refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); + + float waterDepth = refractionDepth - depthPassthrough; + + if (cameraPos.z > 0.0) + refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + + gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * osg_LightSource[0].specular.xyz; +#else + gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * osg_LightSource[0].specular.xyz; +#endif + + // fog + float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); + gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + +#if REFRACTION + gl_FragData[0].w = 1.0; +#else + gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); +#endif +} diff --git a/files/shaders/watergles_vertex.glsl b/files/shaders/watergles_vertex.glsl new file mode 100644 index 0000000000..71cc9718b8 --- /dev/null +++ b/files/shaders/watergles_vertex.glsl @@ -0,0 +1,24 @@ +#version 100 +precision mediump float; +precision mediump int; + +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + 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); + + vec4 texcoordProj = ((scalemat) * ( gl_Position)); + screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + position = gl_Vertex; + + depthPassthrough = gl_Position.z; +} From 16c6816a6fd9c6c94db15b97681b72d6150531e7 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Mon, 23 Nov 2015 20:42:30 +0300 Subject: [PATCH 1421/1812] add forgotten file for building on opengles --- components/myguiplatform/myguirendermanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5bd56dc8f4..5fb3054a61 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -17,6 +17,10 @@ #include #include "myguitexture.hpp" + +#ifdef OPENGLES + #include +#endif #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) From d7e27fa9f443bcc1aa6394314456ad457ef7cf70 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 16:36:59 -0500 Subject: [PATCH 1422/1812] New brief comments version of settings.cfg. --- files/settings-default.cfg | 612 ++++++++----------------------------- 1 file changed, 120 insertions(+), 492 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9a8d8c67e5..6ad4ccff9c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,713 +1,341 @@ -# WARNING: Editing this file might have no effect, as these settings -# are overwritten by your user settings file. Your user settings file -# varies with your operating system: +# This file provides minimal documentation for each setting, and +# ranges of recommended values. For detailed explanations of the +# significance of each setting, interaction with other settings, hard +# limits on value ranges and more information in general, please read +# the detailed documentation at the OpenMW Wiki page: +# +# https://wiki.openmw.org/index.php?title=Settings # -# Linux: $HOME/.config/openmw -# Mac: $HOME/Library/Preferences/openmw -# Windows: C:\Users\Username\Documents\my games\openmw -# This path may vary depending on your installation hard drive, your -# Windows username, and your default language. -# -# Additionally, the user settings file is often written to disk when -# exiting OpenMW, so comments and changes to that file may also be -# discarded after running OpenMW. While most changes to the file will -# reflect setting changes made in game, some settings can have a wider -# range of values in the settings file than the GUI settings widgets -# allow. You may want to exercise some caution and backup this file -# when editing it by hand. +# The version of this file that actually controls the behavior of +# OpenMW is user specific, and it's location can be found in the +# documentation above. This file is probably NOT that file. [Camera] -# This floating point setting controls the distance to the near -# clipping plane. The value must be greater than zero. Values -# greater than approximately 18.0 will occasionally clip objects in -# the world in front of the character. Values greater than -# approximately 8.0 will clip the character's hands in first person -# view and/or the back of their head in third person view. +# Near clipping plane (0.01 to 18.0). near clip = 5.0 -# This boolean setting determines whether objects that render to one -# pixel or smaller will be culled. It generally improves performance -# to enable this feature. +# Cull objects smaller than one pixel. small feature culling = true -# Set the maximum visible distance. Larger values significantly -# improve rendering in exterior spaces, but also increase the amount -# rendered geometry and significantly reduce the frame rate. This -# value is a floating point value that defaults to 6666.0. This value -# interacts with the "exterior cell load distance" setting in that -# it's probably undesired for this value to provide visibility into -# cells that have not yet been loaded. When cells are visible before -# loading, the geometry will "pop-in" suddenly, creating a jarring -# visual effect. To prevent this effect, this value must be less -# than: -# -# 8192 * exterior cell load distance - 1024 -# -# The constant 8192 is the size of a cell, and 1024 is the threshold -# distance for loading a new cell. Additionally, the "field of view" -# setting also interacts with this setting because the view frustrum -# end is a plane, so you can see further at the edges of the screen -# than you should be able to. This can be observed in game by looking -# at distant objects and rotating the camera so the object are near -# the edge of the screen. As a result, the "viewing distance" setting -# should further be reduced by a factor that depends on the "field of -# view" setting. In the default configuration this reduction is 7%. -# Using this factor, approximate values recommended for other -# "exterior cell load distance" settings are: 14285 for 2 cells, 21903 -# for 3 cells, 29522 for 4 cells, and 35924 for 5 cells. -# -# Reductions of up 25% or more can be required to completely eliminate -# pop-in for wide fields of view and long viewing distances near the -# edges of the screen, but such situations are unusual and probably -# not worth the performance penalty introduced by loading geometry -# obscured by fog in the center of the screen. -# -# This setting can be adjusted in game from the ridiculously low value -# of 2000 to a maximum of 6666, using the "View Distance" slider in -# the Detail tab of the Video panel of the Options menu. See -# RenderingManager::configureFog for the relevant source code. +# Maximum visible distance (2000.0 to 6666.0+). Caution: this setting +# can dramatically affect performance, see documentation for details. viewing distance = 6666.0 [Cells] -# This integer setting determines the number of exterior cells -# adjacent to the character that will be loaded for rendering. It -# interacts with "viewing distance" and "field of view" as described -# previously, and it is generally very wasteful for this value to load -# geometry than will almost never be visible due to viewing distance -# and fog. For low frame rate screenshots of scenic vistas, this -# setting should be set high, and viewing distances adjusted -# accordingly. This value must be greater than or equal to 1. +# Adjacent exterior cells loaded (>0). Caution: this setting can +# dramatically affect performance, see documentation for details. exterior cell load distance = 1 [GUI] -# These two settings determine the background color of the tool tip -# and the crosshair when hovering over an item owned by an NPC. The -# color definitions are composed of four floating point values between -# 0.0 and 1.0 inclusive, representing the red, green, blue and alpha -# channels. The alpha value is currently ignored. The crosshair -# color will have no effect if the "crosshair" setting in the HUD -# section is disabled. These colors are used only if the "show owned" -# setting is enabled in the Game section. +# Color for tool tips and crosshair when owned by an NPC (R G B A). color background owned = 0.15 0.0 0.0 1.0 color crosshair owned = 1.0 0.15 0.15 1.0 -# This boolean setting enables or disables the "red flash" overlay -# that provides a visual clue when the character has taken damage. +# Red flash visually showing player damage. hit fader = true -# This floating point setting controls the transparency of the GUI -# windows. The value should be between 0.0 (transparent) and 1.0 -# (opaque). The setting can be adjusted in game with the "Menu -# Transparency" slider in the Prefs panel of the Options menu. +# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). menu transparency = 0.84 -# This floating point setting scales the GUI interface windows. The -# value must be greater than 0.0. A value of 1.0 results in the -# default scale. Values much larger than 2.0 may result in user -# interface components being inaccessible. +# Scales GUI window and widget size. (<1 is smaller, >1 is larger). scaling factor = 1.0 -# Stretch or shrink the introductory movie, new game screen, and -# loading screens to fill the specified video resolution. The default -# assets have a 4:3 aspect ratio, but other assets may have other -# resolutions. If this setting is false, the assets will be centered -# in their correct aspect ratio. +# Stretch menus, load screens, etc. to the window aspect ratio. stretch menu background = false -# Enable or disable subtitles for NPC spoken dialog (and some sound -# effects). Subtitles will appear in a tool tip box in the lower -# center of the screen. The setting can be toggled in game with the -# "Subtitles" button in the Prefs panel of Options menu. +# Subtitles for NPC spoken dialog and some sound effects. subtitles = false -# Set the delay between when you begin hovering over an item and when -# it's tooltip appears. This setting is a floating point value -# between 0.0, which displays the tool tip instantly and 1.0 which -# results in the maximum delay (approximately 1.5 seconds). This -# setting does not affect the tooltip delay for object under the -# crosshair in the "look mode", only widgets in the GUI windows. This -# setting can be adjusted in game with the "Menu Help Delay" slider in -# the Prefs panel of the Options menu. +# Time until tool tip appears when hovering over an object (0.0 is +# instantly, 1.0 is the maximum delay of about 1.5 seconds). tooltip delay = 0.0 -# Enable or disable the werewolf overlay. Unable to evaluate fully -# due to issues with becoming a werewolf. +# Werewolf overlay border around screen or window. werewolf overlay = true [Game] -# If this boolean setting is true, the character will always use the -# most powerful attack when striking with a weapon (chop, slash or -# thrust). If this setting is false, the type of attack is determined -# by the direction that the character is moving at the time the attack -# begins. The setting can be toggled with the "Always Use Best -# Attack" button in the Prefs panel of the Options menu. +# Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false -# This integer setting adjusts the difficulty of the game and is -# intended to be in the range -100 to 100 inclusive. Given the -# default game setting for fDifficultyMult of 5.0, a value of -100 -# results in the player taking 80% of the usual damage, doing 6 times -# the normal damage. A value of 100 results in the player taking 6 -# times as much damage, but inflicting only 80% of the usual damage. -# Values less than -500 will result in the player receiving no damage, -# and values greater than 500 will result in the player inflicting no -# damage. The setting can be controlled in game with the Difficulty -# slider in the Prefs panel of the Options menu. +# Difficulty. Expressed as damage dealt and received. (-100 to 100). difficulty = 0 -# Show the remaining duration of magic effects and lights if this -# boolean setting is true. The remaining duration is displayed in the -# tooltip by hovering over the magical effect. +# Show duration of magic effect and lights in the spells window. show effect duration = false -# Enable visual clues for items owned by NPCs when the crosshair is on -# the object. If the setting is 0, no clues are provided which is the -# default Morrowind behavior. If the setting is 1, the background of -# the tool tip for the object is highlight in the color specified by -# the "color background owned" setting in the "GUI" section. If the -# setting is 2, the crosshair is the color of the "color crosshair -# owned" setting in the "GUI" section. If the setting is 3, both the -# tool tip background and the crosshair are colored. Settings 2 and 3 -# only color the crosshair if it's enabled in the "HUD" section. +# Color crosshair and tool tip when object is owned by an NPC. (O is +# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). show owned = 0 [General] -# Set the maximum anisotropic filtering on textures. Anisotropic -# filtering is a method of enhancing the image quality of textures on -# surfaces that are at oblique viewing angles with respect to the -# camera. Valid values range from 0 to 16. Modern video cards can -# often perform 8 or 16 anisotropic filtering with a minimal -# performance impact. This effect of this setting can be seen in the -# Video panel of the Options menu by finding a location with straight -# lines (striped rugs and Balmora cobblestones work well) radiating -# into the distance, and adjusting the anisotropy slider. This -# setting can be changed in game using the "Anisotropy" slider in the -# Detail tab of the Video panel of the Options menu. +# Anisotropy reduces distortion in textures at low angles (0 to 16). anisotropy = 4 -# Sets the camera field of view in degrees. Recommended values range -# from 30 degrees to 110 degrees. Small values provide a very narrow -# field of view that creates a "zoomed in" effect, while large values -# cause distortion at the edges of the screen. The "field of view" -# setting interacts with aspect ratio of your video resolution in that -# more square aspect ratios (e.g. 4:3) need a wider field of view to -# more resemble the same field of view on a widescreen (e.g. 16:9) -# monitor. This setting can be adjusted in game from the Video tab of -# the Video panel of the Options menu using the "Field of View" -# slider. +# Camera field of view in degrees (30.0 to 110.0). field of view = 55.0 -# Specify the format for screenshots taken by pressing F12. This -# setting should be the file extension commonly associated with the -# desired format. The formats supported will be determined at -# compilation, but "jpg", "png", and "tga" should be allowed. +# File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Set the isotropic texture filtering mode to bilinear or trilinear. -# Bilinear filtering is a texture filtering method used to smooth -# textures when displayed larger or smaller than they actually are. -# Bilinear filtering is reasonably accurate until the scaling of the -# texture gets below half or above double the original size of the -# texture. Trilinear filtering is an extension of the bilinear -# texture filtering method, which also performs linear interpolation -# between mipmaps. Both methods use mipmaps in OpenMW, and the -# corresponding OpenGL modes are LINEAR_MIPMAP_NEAREST and -# LINEAR_MIPMAP_LINEAR. Trilinear filtering produces better texturing -# at a minimal cost on modern video cards. This setting can be -# changed in game using the "Texture filtering" pull down in the -# Detail tab of the Video panel of the Options menu. +# Isotropic texture filtering. (bilinear or trilinear). texture filtering = trilinear [HUD] -# This boolean setting determines whether the crosshair or reticle is -# displayed. If this setting is disabled it will override "show -# owned" and "color crosshair owned". This setting can be toggled -# with the "Crosshair" button in the Prefs panel of the Options menu. +# Displays the crosshair or reticle when not in GUI mode. crosshair = true [Input] -# Allow zooming in and out using the middle mouse wheel in third -# person view. +# Zoom in and out from player in third person view with mouse wheel. allow third person zoom = false -# If this boolean setting is true, the character is running by -# default, otherwise the character is walking by default. The shift -# key will temporarily invert this setting, and the caps lock key will -# invert this setting while it's "locked". Confusingly, this setting -# is updated every time you exit the game, based on whether the caps -# lock key was on or off at the time you exited. +# Player is running by default. always run = false -# This floating point setting controls the camera/mouse sensitivity -# when in "look mode". The default sensitivity is 1.0, with smaller -# values requiring more mouse movement, and larger values requiring -# less. This setting is multiplicative in magnitude. This setting -# does not affect mouse speed in GUI mode. +# Camera sensitivity when not in GUI mode. (0.1 to 5.0). camera sensitivity = 1.0 -# This floating point setting controls the vertical camera/mouse -# sensitivity relative to the horizontal sensitivity (see "camera -# sensitivity") above. It is multiplicative with the previous -# setting, meaning that it should remain set at 1.0 unless the player -# desires to have different sensitivities in the two axes. +# Vertical camera sensitivity multiplier when not in GUI mode. +# Because it's a multiplier values should be near one (0.5 to 1.5). camera y multiplier = 1.0 -# OpenMW will capture control of the cursor if this boolean setting is -# true. In "look mode", OpenMW will capture the cursor regardless of -# the value of this setting (since the cursor/crosshair is always -# centered in the OpenMW window). However, in GUI mode, this setting -# determines the behavior when the cursor is moved outside the OpenMW -# window. If true, the cursor movement stops at the edge of the -# window preventing access to other applications. If false, the -# cursor is allowed to move freely on the desktop. -# -# This setting does not apply to the screen where escape has been -# pressed, where the cursor is never captured. Regardless of this -# setting "Alt-Tab" or some other operating system dependent key -# sequence can be used to allow the operating system to regain control -# of the mouse cursor. This setting interacts with the "minimize on -# focus loss" setting by affecting what counts as a focus loss. -# Specifically on a two-screen configuration it may be more convenient -# to access the second screen with setting disabled. +# Capture control of the cursor prevent movement outside the window. grab cursor = true -# Invert the vertical axis while in "look mode". If this setting is -# true, moving the mouse away from the player will look down, while -# moving it towards the player will look up. This setting does not -# affect cursor movement in GUI mode. +# Invert the vertical axis while not in GUI mode. invert y axis = false -# This boolean setting causes the behavior of the sneak key (Ctrl by -# default) to toggle sneaking on and off rather than requiring the key -# to be held while sneaking. Players that spend significant time -# sneaking may find the character easier to control with this option -# enabled. +# Key controlling sneak toggles setting instead of being held down. toggle sneak = false -# This setting continues to be loaded and saved, but has no known -# effect. Presumably it and a related but also removed option named -# "ui y sensitivity" used to control mouse sensitivity while in GUI -# mode. The default value is 1.0. -ui sensitivity = 1.0 - [Map] -# It is not currently possible to control how many adjacent cells are -# displayed in the map. It appears that this is hardcoded to one -# adjacent cell (3x3) in the code. These settings control the canvas -# and resolution sizes, and therefore the amount of panning required -# to see the entire map, and the level of detail visible. - -# This integer setting adjusts the scale of the world map in the GUI -# mode map display. The value is the width in pixels of each cell in -# the map, so larger values result in larger more detailed world maps, -# while smaller values result in smaller less detailed world maps. -# However, the native resolution of the map source material appears to -# be 9 pixels per unexplored cell and approximately 18 pixels per -# explored cell, so values larger than 36 don't produce much -# additional detail. Similarly, the size of place markers is -# currently fixed at 12 pixels, so values smaller than this result in -# overlapping place markers. Values from 12 to 36 are recommended. -# For reference, Vvardenfell is approximately 41x36 cells. +# Size of each exterior cell in pixels in the world map. (12 to 24). +# Warning: affects explored areas in save files, see documentation. global map cell size = 18 -# This integer setting controls the zoom level for the HUD map display -# (the map in the lower right corner while not in GUI mode). A value -# of 64 results in the HUD map displaying one exterior cell. Since -# the GUI mode map displays 3x3 cells, a value of approximately 21 -# displays the same area as the GUI mode map. Larger values increase -# the level of zoom, while smaller values are wasteful. -# -# Note that the actual size of the widget is always the same on the -# screen unless the "scaling factor" setting in the "GUI" section is -# changed. Increasing both the scaling factor of the GUI and this -# setting does result in a higher resolution HUD map, but -# unfortunately with a scaled direction pointer on top of it. +# Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 +# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). local map hud widget size = 256 -# This integer setting controls the resolution of the GUI mode local -# map widget. Larger values generally increase the visible detail in -# map. If this setting is half the "local map widget size" or -# smaller, the map will generally be be fairly blurry. Setting the -# both options to the same value results in a map with good detail. -# Values that exceed the "local map widget size" setting by more than -# a factor of two are unlikely to provide much of an improvement in -# detail since they're subsequently scaled back to the approximately -# the map widget size before display. The video resolution setting -# interacts with this setting in that regard. +# Resolution of local map in GUI window in pixels. See documentation +# for details which may affect cell load performance. (128 to 1024). local map resolution = 256 -# This integer setting controls the canvas size of the GUI mode local -# map widget. Larger values result in a larger physical map size on -# screen, and typically require more panning to see all available -# portions of the map. This larger size also enables an overall -# greater level of detail if the "local map resolution" setting is -# also increased. +# Size of local map in GUI window in pixels. See documentation for +# details which may affect cell load performance. (256 to 1024). local map widget size = 512 [Objects] -# This boolean setting currently has no known impact, but is -# presumably intended to enable shaders for objects other than water. -# Whenever the setting file is written by the game, this option is -# currently reset to false. +# Enable shaders for objects other than water. Unused. shaders = true [Saves] -# This string setting contains the default character name for loading -# saved games. This setting is automatically updated from the Load -# game menu option when a different character is selected. -character = - -# This boolean setting determines whether the game will be -# automatically saved when the character rests. This setting can be -# toggled in game with the "Auto-Save when Rest" button in the Prefs -# panel of the Options menu. +# Automatically save the game whenever the player rests. autosave = true -# This boolean setting determines whether the amount of the time the -# player has spent playing will displayed for each saved game in the -# menu for saving and loading games. This setting can not currently -# be adjusted in game. This setting is disabled by default for players -# who would prefer not to know how many hours they've spent -# playing. :-) +# Name of last character played, and default for loading save files. +character = + +# Display the time played on each save file in the load menu. timeplayed = false [Shadows] -# Shadows in general are dependent on the "shaders" setting be enabled -# in the Objects section. Additionally, the "enabled" setting in this -# section must be true for any other options in this section to have -# effect. Both that setting and the Shadows section options are -# temporarily disabled following the conversion to the OpenSceneGraph -# engine. None of these option can be adjusted in game at the present -# time. - -# This boolean setting enables actors to cast shadows. +# Actors cast shadows. Unused. actor shadows = true -# Enable debugging of shadows? +# Debugging of shadows. Unused. debug = false -# Are shadows enabled in general? +# Enable shadows. Other shadow settings disabled if false. Unused. enabled = false -# This floating point setting determines the fraction of the total -# shadow distance after which the shadow starts to fade out. +# Fraction of distance after which shadow starts to fade out. Unused. fade start = 0.8 -# Allows miscellaneous object to cast shadows. +# Miscellaneous object cast shadows. misc shadows = true -# This setting will only have effect if the "split" setting in the -# Shadows section is false. Increasing shadow distance will lower the -# shadow quality. +# Distance for shadows if not split. Smaller is poorer. Unused. shadow distance = 1300 -# Split the shadow maps, allowing for a larger shadow distance? +# Split shadow maps, allowing for a larger shadow distance. Unused. split = false -# This setting will only have effect if the "split" setting in the -# Shadows section is true. # This one shouldn't be too low, otherwise -# you'll see artifacts. Use at least 2x max viewing distance. +# Distance for shadows if split. Unused. split shadow distance = 14000 -# Allow static objects to cast shadows. +# Static objects cast shadows. Unused. statics shadows = true -# Allow terrain to cast shadows. +# Terrain cast shadows. Unused. terrain shadows = true -# Size of the shadow textures. Higher resolution texture produce more -# detailed shadows and a better visual effect. +# Size of the shadow textures in pixels. Unused. (256 to 2048). texture size = 1024 [Sound] -# This string setting determines which audio device to use. A blank or -# missing setting means to use the default device, which should -# usually be sufficient, but if you need to explicitly specify a -# device name try doing so here. +# Name of audio device file. Blank means use the default device. device = -# The settings in the Sound section are generally floating point -# settings in the range from 0.0 (silent) to 1.0 (maximum volume). -# All sound settings are multiplied by the "master volume" setting, and -# will thus have no effect if the master volume is set to 0.0. These -# settings can be adjusted in game from the Audio panel of the Options -# menu under the appropriately labeled slider. +# Volumes are 0.0 for silent and 1.0 for the maximum volume. -# The volume of footsteps from the character and other actors. +# Footsteps volume. footsteps volume = 0.2 -# The master volume is multiplied with all other volume settings to -# determine the final volume +# Master volume. Controls all other volumes. master volume = 1.0 -# The volume for music tracks. +# Music tracks volume. music volume = 0.5 -# The volume for special effect sounds such as combat noises, etc. +# Sound effects volume. sfx volume = 1.0 -# The volume for spoken dialog from NPCs. +# Voice dialog volume. voice volume = 0.8 [Terrain] -<<<<<<< HEAD -# Not currently used, presumably due to the OpenSceneGraph upgrade. +# Distant land is rendered? Unused. distant land = false -# Not currently used, presumably due to the OpenSceneGraph upgrade. +# Use shaders for terrain? Unused. shader = true -======= -camera y multiplier = 1.0 ->>>>>>> upstream/master [Video] -# This integer setting controls anti-aliasing. Anti-aliasing is -# technique designed to reduce distortions called aliasing caused by -# displaying high resolution textures at a lower resolution. -# Anti-aliasing can correct these distortions at the cost of a minor -# reduction in the frame rate. A value of 0 disables anti-aliasing. -# Other powers of two (e.g. 2, 4, 8, 16) are supported according to -# the capabilities of your graphics hardware. Higher values do a -# better job of correcting the distortion and have a greater impact on -# frame rate. This setting can be configured from a list of valid -# choices in the Graphics panel of the OpenMW Launcher. +# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). antialiasing = 0 -# This floating point setting controls the contrast correction for all -# video in the game. This setting does not currently work under -# Linux, and the in-game setting in the Options menu has been -# disabled. -contrast = 1.00 +# Game video contrast. (0.0 to 1.0). No effect in Linux. +contrast = 1.0 -# This floating point setting determines the maximum frame rate in -# frames per second. If this setting is 0.0, the frame rate is -# unlimited. There are several reasons to consider capping your frame -# rate, especially if you're already experiencing a relatively high -# frame rate (greater than 60 frames per second). Lower frame rates -# will consume less power and generate less heat and noise. Frame -# rates above 60 frames per second rarely produce perceptible -# improvements in visual quality. Capping the frame rate may in some -# situations reduce the perception of choppiness (highly variable -# frame rates during game play) by lowering the peak frame rates. -# This setting interacts with the "vsync" setting in the Video section -# in the sense that enabling vertical sync limits the frame rate to -# the refresh rate of your monitor (often 60 frames per second). +# Maximum frames per second. (1.0 to 200.0). framerate limit = 0.0 -# This boolean setting determines whether the entire screen is used -# for the specified resolution. This setting can be toggled in game -# using the "Fullscreen" button in the Video tab of the Video panel in -# the Options menu. It can also be toggled with the "Full Screen" -# check box in the Graphic tab of the OpenMW Launcher. +# OpenMW takes complete control of the screen. fullscreen = false -# Theses two setting determine the horizontal and vertical resolution -# of the OpenMW game window. Larger values produce more detailed -# images within the constraints of your graphics hardware but also -# significantly reduce the frame rate. The window resolution can be -# selected from a menu of common screen sizes in the Video tab of the -# Video Panel of the Options menu. The resolution can also be set to -# a custom value in the Graphics tab of the OpenMW Launcher. +# Resolution of the Open window or screen. (600 to 2560). resolution x = 800 resolution y = 600 -# This boolean setting determines whether there's an operating system -# border drawn around the OpenMW window. If this setting is true, the -# window can be moved and resized with the operating system window -# controls. If this setting is false, the window has no operating -# system border. This setting has no effect if the "fullscreen" -# setting in the Video section is true. This setting can be toggled -# in game using the "Window Border" button in the Video tab of the -# Video panel in the Options menu. It can also be toggled with the -# "Window Border" check box in the OpenMW Launcher. +# An operating system border is drawn around the OpenMW window. window border = true -# This integer setting determines which screen the game will open on -# in multi-monitor configurations. This setting is particularly -# important when "fullscreen" setting in the Video section is true, -# since this is the only way to control which screen is used, but it -# can also be used to control which screen a normal window or a -# borderless window opens on as well. This setting can be selected -# from a pull down menu in the Graphics tab of the OpenMW Launcher, -# but not adjusted during game play. +# Determines which screen OpenMW is on. (0 or 1). screen = 0 -# Minimize the OpenMW window if it loses cursor focus. This setting -# has no effect if the "fullscreen" setting is false. This setting is -# primarily useful for single screen configurations, so that the -# OpenMW screen in full screen mode can be minimized when the -# operating system regains control of the mouse and keyboard. On -# multiple screen configurations, disabling this option make make it -# easier to switch between screens while playing OpenMW. +# Minimize OpenMW if it loses cursor or keyboard focus. minimize on focus loss = true -# This boolean setting determines whether frame draws are synchronized -# with the vertical refresh rate of your monitor. Enabling this -# setting can reduce "tearing", a visual defect caused by updating the -# image buffer in the middle of a screen draw. Enabling this option -# typically implies limiting the framerate to 60 frames per second, -# but may also introduce additional delays caused by having to wait -# until the appropriate time (the vertical blanking interval) to draw -# a frame. - -# This setting can be adjusted in game using the "VSync" button in the -# Video tab of the Video panel in the Options menu. It can also be -# changed by toggling the "Vertical Sync" check box in the Graphics -# tab of the OpenMW Launcher. +# Enable vertical syncing to reduce tearing defects. vsync = false -# This floating point setting controls the gamma correction for all -# video in the game. This setting does not currently work under -# Linux, and the in-game setting in the Options menu has been -# disabled. -gamma = 1.00 +# Video gamma setting. (0.0 to 1.0). No effect in Linux. +gamma = 1.0 [Water] -# The water settings can be tested experimentally in the Water tab of -# the Video panel in the Options menu. Changes there will be saved to -# these settings. - -# This boolean setting enables the refraction rendering feature of the -# water shader. Refraction causes deep water to be more opaque and -# objects seen through the plane of the water to have a wavy -# appearance. Enabling this feature results in better visuals, and a -# marginally lower framerate depending on your graphics hardware. The -# "shader" setting in the Water section must be enabled for this -# setting to have any effect. +# Enable refraction which affects visibility through water plane. refraction = false -# Refracted texture size. In the Video panel of the options menu, the -# choices are Low (512), Medium (1024) and High (2048). This setting -# determines the resolution of the textures used for rendering objects -# on the other wide of the plane of water (which have a wavy -# appearance caused the by the refraction). Higher values produces -# better visuals and result in a marginally lower framerate depending -# on your graphics hardware. The "refraction" setting in the "Water" -# section must be enabled for this setting to have any effect. +# Reflection and refraction texture size in pixels. (512, 1024, 2048). rtt size = 512 -# This boolean setting enables or disables the water shader, which -# results in much more realistic looking water surfaces, including -# shadows of reflected objects. +# Enable water shader with reflections and optionally refraction. shader = false [Windows] -# Each window in the GUI mode remembers it's previous location. Each -# setting is a floating point number representing a fraction of the -# "resolution x" or "resolution y" setting in the Video section. The -# X and Y values locate the top left corner, while the W value -# determines the width of the window and the H value determines the -# height of the window. +# Location and sizes of windows as a fraction of the OpenMW window or +# screen size. (0.0 to 1.0). X & Y, Height & Width. -# The alchemy window, for crafting potions. Activated by dragging an -# alchemy tool on to the rag doll. Unlike most other windows, this -# window hides all other windows when opened. +# Alchemy window for crafting potions. alchemy h = 0.5 alchemy w = 0.5 alchemy x = 0.25 alchemy y = 0.25 -# The NPC bartering window, displaying goods owned by the shopkeeper -# while bartering. Activated by clicking on the "Barter" choice in -# the dialog window for an NPC. +# NPC inventory window when bartering with a shopkeeper. barter h = 0.375 barter w = 0.75 barter x = 0.25 -barter y = 0 +barter y = 0.0 -# Unused? +# NPC inventory window when trading with a companion. companion h = 0.375 companion w = 0.75 companion x = 0.25 -companion y = 0 +companion y = 0.0 -# The console command window. Activated by pressing the tilde (~) key. +# Console command window for debugging commands. console h = 0.5 -console w = 1 -console x = 0 -console y = 0 +console w = 1.0 +console x = 0.0 +console y = 0.0 -# The container window, showing the contents of the container. -# Activated by clicking on a container. The same window is used for -# searching dead bodies, and pickpocketing people. +# Container inventory when searching a container. container h = 0.375 container w = 0.75 container x = 0.25 -container y = 0 +container y = 0.0 -# The dialog window, for talking with NPCs. Activated by clicking on a -# NPC. +# Dialog window for talking with NPCs. dialogue h = 0.810 dialogue w = 0.810 dialogue x = 0.095 dialogue y = 0.095 -# The character inventory window while bartering. It displays goods -# owned by the character while bartering. Activated by clicking on the -# "Barter" choice in the dialog window for an NPC. +# Player inventory window when bartering with a shopkeeper. inventory barter h = 0.5725 inventory barter w = 0.6225 -inventory barter x = 0 +inventory barter x = 0.0 inventory barter y = 0.4275 -# Unused? +# Player inventory window when trading with a companion. inventory companion h = 0.5725 inventory companion w = 0.6225 -inventory companion x = 0 +inventory companion x = 0.0 inventory companion y = 0.4275 -# The character inventory window while searching a container, showing -# the contents of the character's inventory. Activated by clicking on -# a container. The same window is used for searching dead bodies, and -# pickpocketing people. +# Player inventory window when searching a container. inventory container h = 0.5725 inventory container w = 0.6225 -inventory container x = 0 +inventory container x = 0.0 inventory container y = 0.4275 -# The inventory window, displaying the paper doll and possessions. -# Activated by clicking on the inventory widget (second from left) in -# the bottom left corner of the HUD. +# Player inventory window when explicitly opened. inventory h = 0.5725 inventory w = 0.6225 -inventory x = 0 +inventory x = 0.0 inventory y = 0.4275 -# The local and world map window. Activated by clicking on the map -# widget in the bottom right corner of the HUD. +# Local and world map window. map h = 0.5725 map w = 0.375 map x = 0.625 -map y = 0 +map y = 0.0 -# The spells window, displaying powers, spells, and magical items. -# Activated by clicking on the spells widget (third from left) in the -# bottom left corner of the HUD. +# Spells window displaying powers, spells, and magical items. spells h = 0.4275 spells w = 0.375 spells x = 0.625 spells y = 0.5725 -# The stats window, displaying level, race, class, skills and stats. -# Activated by clicking on any of the three bars in the lower left -# corner of the HUD. +# Stats window displaying level, race, class, skills and stats. stats h = 0.4275 stats w = 0.375 -stats x = 0 -stats y = 0 +stats x = 0.0 +stats y = 0.0 From 89100088f35a66834e83ce88979226898f55c450 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 20:07:48 -0500 Subject: [PATCH 1423/1812] The latest version of the settings.cfg without any code changes. --- files/settings-default.cfg | 464 ++++++++++++++++++------------------- 1 file changed, 232 insertions(+), 232 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ad4ccff9c..3b91e7f0a0 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -8,7 +8,7 @@ # # The version of this file that actually controls the behavior of # OpenMW is user specific, and it's location can be found in the -# documentation above. This file is probably NOT that file. +# documentation above. This file is probably NOT that file... [Camera] @@ -28,92 +28,6 @@ viewing distance = 6666.0 # dramatically affect performance, see documentation for details. exterior cell load distance = 1 -[GUI] - -# Color for tool tips and crosshair when owned by an NPC (R G B A). -color background owned = 0.15 0.0 0.0 1.0 -color crosshair owned = 1.0 0.15 0.15 1.0 - -# Red flash visually showing player damage. -hit fader = true - -# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). -menu transparency = 0.84 - -# Scales GUI window and widget size. (<1 is smaller, >1 is larger). -scaling factor = 1.0 - -# Stretch menus, load screens, etc. to the window aspect ratio. -stretch menu background = false - -# Subtitles for NPC spoken dialog and some sound effects. -subtitles = false - -# Time until tool tip appears when hovering over an object (0.0 is -# instantly, 1.0 is the maximum delay of about 1.5 seconds). -tooltip delay = 0.0 - -# Werewolf overlay border around screen or window. -werewolf overlay = true - -[Game] - -# Always use the best mode of attack: e.g. chop, slash or thrust. -best attack = false - -# Difficulty. Expressed as damage dealt and received. (-100 to 100). -difficulty = 0 - -# Show duration of magic effect and lights in the spells window. -show effect duration = false - -# Color crosshair and tool tip when object is owned by an NPC. (O is -# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). -show owned = 0 - -[General] - -# Anisotropy reduces distortion in textures at low angles (0 to 16). -anisotropy = 4 - -# Camera field of view in degrees (30.0 to 110.0). -field of view = 55.0 - -# File format for screenshots. (jpg, png, tga, and possibly more). -screenshot format = png - -# Isotropic texture filtering. (bilinear or trilinear). -texture filtering = trilinear - -[HUD] - -# Displays the crosshair or reticle when not in GUI mode. -crosshair = true - -[Input] - -# Zoom in and out from player in third person view with mouse wheel. -allow third person zoom = false - -# Player is running by default. -always run = false - -# Camera sensitivity when not in GUI mode. (0.1 to 5.0). -camera sensitivity = 1.0 - -# Vertical camera sensitivity multiplier when not in GUI mode. -# Because it's a multiplier values should be near one (0.5 to 1.5). -camera y multiplier = 1.0 - -# Capture control of the cursor prevent movement outside the window. -grab cursor = true - -# Invert the vertical axis while not in GUI mode. -invert y axis = false - -# Key controlling sneak toggles setting instead of being held down. -toggle sneak = false - [Map] # Size of each exterior cell in pixels in the world map. (12 to 24). @@ -132,57 +46,103 @@ local map resolution = 256 # details which may affect cell load performance. (256 to 1024). local map widget size = 512 -[Objects] +[GUI] -# Enable shaders for objects other than water. Unused. -shaders = true +# Scales GUI window and widget size. (<1 is smaller, >1 is larger). +scaling factor = 1.0 + +# Transparency of GUI windows (0.0 to 1.0, transparent to opaque). +menu transparency = 0.84 + +# Time until tool tip appears when hovering over an object (0.0 is +# instantly, 1.0 is the maximum delay of about 1.5 seconds). +tooltip delay = 0.0 + +# Stretch menus, load screens, etc. to the window aspect ratio. +stretch menu background = false + +# Subtitles for NPC spoken dialog and some sound effects. +subtitles = false + +# Red flash visually showing player damage. +hit fader = true + +# Werewolf overlay border around screen or window. +werewolf overlay = true + +# Color for tool tips and crosshair when owned by an NPC (R G B A). +color background owned = 0.15 0.0 0.0 1.0 +color crosshair owned = 1.0 0.15 0.15 1.0 + +[HUD] + +# Displays the crosshair or reticle when not in GUI mode. +crosshair = true + +[Game] + +# Color crosshair and tool tip when object is owned by an NPC. (O is +# no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). +show owned = 0 + +# Always use the best mode of attack: e.g. chop, slash or thrust. +best attack = false + +# Difficulty. Expressed as damage dealt and received. (-100 to 100). +difficulty = 0 + +# Show duration of magic effect and lights in the spells window. +show effect duration = false + +[General] + +# Anisotropy reduces distortion in textures at low angles (0 to 16). +anisotropy = 4 + +# Camera field of view in degrees (30.0 to 110.0). +field of view = 55.0 + +# File format for screenshots. (jpg, png, tga, and possibly more). +screenshot format = png + +# Isotropic texture filtering. (bilinear or trilinear). +texture filtering = trilinear + +[Input] + +# Capture control of the cursor prevent movement outside the window. +grab cursor = true + +# Key controlling sneak toggles setting instead of being held down. +toggle sneak = false + +# Player is running by default. +always run = false + +# Zoom in and out from player in third person view with mouse wheel. +allow third person zoom = false + +# Camera sensitivity when not in GUI mode. (0.1 to 5.0). +camera sensitivity = 1.0 + +# Vertical camera sensitivity multiplier when not in GUI mode. +# Because it's a multiplier values should be near one (0.5 to 1.5). +camera y multiplier = 1.0 + +# Invert the vertical axis while not in GUI mode. +invert y axis = false [Saves] -# Automatically save the game whenever the player rests. -autosave = true - # Name of last character played, and default for loading save files. character = +# Automatically save the game whenever the player rests. +autosave = true + # Display the time played on each save file in the load menu. timeplayed = false -[Shadows] - -# Actors cast shadows. Unused. -actor shadows = true - -# Debugging of shadows. Unused. -debug = false - -# Enable shadows. Other shadow settings disabled if false. Unused. -enabled = false - -# Fraction of distance after which shadow starts to fade out. Unused. -fade start = 0.8 - -# Miscellaneous object cast shadows. -misc shadows = true - -# Distance for shadows if not split. Smaller is poorer. Unused. -shadow distance = 1300 - -# Split shadow maps, allowing for a larger shadow distance. Unused. -split = false - -# Distance for shadows if split. Unused. -split shadow distance = 14000 - -# Static objects cast shadows. Unused. -statics shadows = true - -# Terrain cast shadows. Unused. -terrain shadows = true - -# Size of the shadow textures in pixels. Unused. (256 to 2048). -texture size = 1024 - [Sound] # Name of audio device file. Blank means use the default device. @@ -190,12 +150,12 @@ device = # Volumes are 0.0 for silent and 1.0 for the maximum volume. -# Footsteps volume. -footsteps volume = 0.2 - # Master volume. Controls all other volumes. master volume = 1.0 +# Footsteps volume. +footsteps volume = 0.2 + # Music tracks volume. music volume = 0.5 @@ -205,34 +165,14 @@ sfx volume = 1.0 # Voice dialog volume. voice volume = 0.8 -[Terrain] - -# Distant land is rendered? Unused. -distant land = false - -# Use shaders for terrain? Unused. -shader = true - [Video] -# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). -antialiasing = 0 - -# Game video contrast. (0.0 to 1.0). No effect in Linux. -contrast = 1.0 - -# Maximum frames per second. (1.0 to 200.0). -framerate limit = 0.0 - -# OpenMW takes complete control of the screen. -fullscreen = false - # Resolution of the Open window or screen. (600 to 2560). resolution x = 800 resolution y = 600 -# An operating system border is drawn around the OpenMW window. -window border = true +# OpenMW takes complete control of the screen. +fullscreen = false # Determines which screen OpenMW is on. (0 or 1). screen = 0 @@ -240,102 +180,162 @@ screen = 0 # Minimize OpenMW if it loses cursor or keyboard focus. minimize on focus loss = true +# An operating system border is drawn around the OpenMW window. +window border = true + +# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). +antialiasing = 0 + # Enable vertical syncing to reduce tearing defects. vsync = false +# Maximum frames per second. (1.0 to 200.0). +framerate limit = 0.0 + +# Game video contrast. (0.0 to 1.0). No effect in Linux. +contrast = 1.0 + # Video gamma setting. (0.0 to 1.0). No effect in Linux. gamma = 1.0 [Water] -# Enable refraction which affects visibility through water plane. -refraction = false +# Enable water shader with reflections and optionally refraction. +shader = false # Reflection and refraction texture size in pixels. (512, 1024, 2048). rtt size = 512 -# Enable water shader with reflections and optionally refraction. -shader = false +# Enable refraction which affects visibility through water plane. +refraction = false + +[Objects] + +# Enable shaders for objects other than water. Unused. +shaders = true + +[Terrain] + +# Use shaders for terrain? Unused. +shader = true + +# Distant land is rendered? Unused. +distant land = false + +[Shadows] + +# Enable shadows. Other shadow settings disabled if false. Unused. +enabled = false + +# Size of the shadow textures in pixels. Unused. (256 to 2048). +texture size = 1024 + +# Actors cast shadows. Unused. +actor shadows = true + +# Static objects cast shadows. Unused. +statics shadows = true + +# Terrain cast shadows. Unused. +terrain shadows = true + +# Miscellaneous objects cast shadows. Unused. +misc shadows = true + +# Debugging of shadows. Unused. +debug = false + +# Fraction of distance after which shadow starts to fade out. Unused. +fade start = 0.8 + +# Split shadow maps, allowing for a larger shadow distance. Unused. +split = false + +# Distance for shadows if not split. Smaller is poorer. Unused. +shadow distance = 1300 + +# Distance for shadows if split. Unused. +split shadow distance = 14000 [Windows] # Location and sizes of windows as a fraction of the OpenMW window or -# screen size. (0.0 to 1.0). X & Y, Height & Width. - -# Alchemy window for crafting potions. -alchemy h = 0.5 -alchemy w = 0.5 -alchemy x = 0.25 -alchemy y = 0.25 - -# NPC inventory window when bartering with a shopkeeper. -barter h = 0.375 -barter w = 0.75 -barter x = 0.25 -barter y = 0.0 - -# NPC inventory window when trading with a companion. -companion h = 0.375 -companion w = 0.75 -companion x = 0.25 -companion y = 0.0 - -# Console command window for debugging commands. -console h = 0.5 -console w = 1.0 -console x = 0.0 -console y = 0.0 - -# Container inventory when searching a container. -container h = 0.375 -container w = 0.75 -container x = 0.25 -container y = 0.0 - -# Dialog window for talking with NPCs. -dialogue h = 0.810 -dialogue w = 0.810 -dialogue x = 0.095 -dialogue y = 0.095 - -# Player inventory window when bartering with a shopkeeper. -inventory barter h = 0.5725 -inventory barter w = 0.6225 -inventory barter x = 0.0 -inventory barter y = 0.4275 - -# Player inventory window when trading with a companion. -inventory companion h = 0.5725 -inventory companion w = 0.6225 -inventory companion x = 0.0 -inventory companion y = 0.4275 - -# Player inventory window when searching a container. -inventory container h = 0.5725 -inventory container w = 0.6225 -inventory container x = 0.0 -inventory container y = 0.4275 - -# Player inventory window when explicitly opened. -inventory h = 0.5725 -inventory w = 0.6225 -inventory x = 0.0 -inventory y = 0.4275 - -# Local and world map window. -map h = 0.5725 -map w = 0.375 -map x = 0.625 -map y = 0.0 - -# Spells window displaying powers, spells, and magical items. -spells h = 0.4275 -spells w = 0.375 -spells x = 0.625 -spells y = 0.5725 +# screen size. (0.0 to 1.0). X & Y, Width & Height. # Stats window displaying level, race, class, skills and stats. -stats h = 0.4275 -stats w = 0.375 stats x = 0.0 stats y = 0.0 +stats w = 0.375 +stats h = 0.4275 + +# Spells window displaying powers, spells, and magical items. +spells x = 0.625 +spells y = 0.5725 +spells w = 0.375 +spells h = 0.4275 + +# Local and world map window. +map x = 0.625 +map y = 0.0 +map w = 0.375 +map h = 0.5725 + +# Dialog window for talking with NPCs. +dialogue x = 0.095 +dialogue y = 0.095 +dialogue w = 0.810 +dialogue h = 0.810 + +# Alchemy window for crafting potions. +alchemy x = 0.25 +alchemy y = 0.25 +alchemy w = 0.5 +alchemy h = 0.5 + +# Console command window for debugging commands. +console x = 0.0 +console y = 0.0 +console w = 1.0 +console h = 0.5 + +# Player inventory window when explicitly opened. +inventory x = 0.0 +inventory y = 0.4275 +inventory w = 0.6225 +inventory h = 0.5725 + +# Player inventory window when searching a container. +inventory container x = 0.0 +inventory container y = 0.4275 +inventory container w = 0.6225 +inventory container h = 0.5725 + +# Player inventory window when bartering with a shopkeeper. +inventory barter x = 0.0 +inventory barter y = 0.4275 +inventory barter w = 0.6225 +inventory barter h = 0.5725 + +# Player inventory window when trading with a companion. +inventory companion x = 0.0 +inventory companion y = 0.4275 +inventory companion w = 0.6225 +inventory companion h = 0.5725 + +# Container inventory when searching a container. +container x = 0.25 +container y = 0.0 +container w = 0.75 +container h = 0.375 + +# NPC inventory window when bartering with a shopkeeper. +barter x = 0.25 +barter y = 0.0 +barter w = 0.75 +barter h = 0.375 + +# NPC inventory window when trading with a companion. +companion x = 0.25 +companion y = 0.0 +companion w = 0.75 +companion h = 0.375 From 9a975a2e684e030650d064c70e05dcdfcd956df9 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 18:10:33 -0500 Subject: [PATCH 1424/1812] Substantial rewrite of code to save settings.cfg file, allowing comments to persist, ordering of settings to be retained, additional reporting of changed settings, preservation of the settings.cfg timestamp when no changes are made, and foundational changes for possible future features. Due to poor interaction with the openmw-launcher settings code, the launcher will still discard all of these benefits. --- components/settings/settings.cpp | 241 +++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 12 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 90fd300ecf..7abfaff2cd 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -58,6 +59,7 @@ CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); +typedef std::map< CategorySetting, bool > CategorySettingStatusMap; class SettingsFileParser { @@ -69,6 +71,7 @@ public: mFile = file; boost::filesystem::ifstream stream; stream.open(boost::filesystem::path(file)); + std::cout << "Loading settings file: " << file << std::endl; std::string currentCategory; mLine = 0; while (!stream.eof() && !stream.fail()) @@ -117,6 +120,230 @@ public: } } + void saveSettingsFile (const std::string& file, CategorySettingValueMap& settings) + { + // No options have been written to the file yet. + CategorySettingStatusMap written; + for (CategorySettingValueMap::iterator it = settings.begin(); it != settings.end(); ++it) { + written[it->first] = false; + } + + // Have we substantively changed the settings file? + bool changed = false; + + // Was there anything in the existing file? This is intended to permit the deletion of + // the settings.cfg file and it's automatic recreation -- a feature not currently + // supported elsewhere in the code. + bool existing = false; + + // The category/section we're currently in. + std::string currentCategory; + + // Open the existing settings.cfg file to copy comments. This might not be the same file + // as the output file if we're copying the setting from the default settings.cfg for the + // first time. A minor change in API to pass the source file might be in order here. + boost::filesystem::ifstream istream; + boost::filesystem::path ipath(file); + istream.open(ipath); + //std::cout << "Reading previous settings file: " << ipath << std::endl; + + // Create a new string stream to write the current settings to. It's likely that the + // input file and the output file are the same, so this stream serves as a temporary file + // of sorts. The setting files aren't very large so there's no performance issue. + std::stringstream ostream; + + // For every line in the input file... + while (!istream.eof() && !istream.fail()) { + std::string line; + std::getline(istream, line); + + // The current character position in the line. + size_t i = 0; + + // Don't add additional newlines at the end of the file. + if (istream.eof()) continue; + + // Copy entirely blank lines. + if (!skipWhiteSpace(i, line)) { + ostream << line << std::endl; + continue; + } + + // There were at least some comments in the input file. + existing = true; + + // Copy comments. + if (line[i] == '#') { + ostream << line << std::endl; + continue; + } + + // Category heading. + if (line[i] == '[') { + size_t end = line.find(']', i); + // This should never happen unless the player edited the file while playing. + if (end == std::string::npos) { + ostream << "# unterminated category: " << line << std::endl; + changed = true; + continue; + } + + // Ensure that all options in the current category have been written. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + bool missed = false; + if (mit->second == false && mit->first.first == currentCategory) { + std::cout << "Added new setting: [" << currentCategory << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // With some further code changes, this comment could be more descriptive. + ostream << "# Automatically added setting." << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + mit->second = true; + missed = true; + changed = true; + } + // Ensure that there's a newline before the next section if we added settings. + if (missed) ostream << std::endl; + } + + // Update the current category. + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + + // Write the (new) current category to the file. + ostream << "[" << currentCategory << "]" << std::endl; + //std::cout << "Wrote category: " << currentCategory << std::endl; + + // A setting can apparently follow the category on an input line. That's rather + // inconvenient, since it makes it more likely to have duplicative sections, + // which our algorithm doesn't like. Do the best we can. + i = end+1; + } + + // Truncate trailing whitespace, since we're changing the file anayway. + if (!skipWhiteSpace(i, line)) + continue; + + // If we'cve found settings befor ethe first category, something's wrong. This + // should never happen unless the player edited the file while playing, since + // the loadSettingsFile() logic rejects it. + if (currentCategory.empty()) { + ostream << "# empty category name: " << line << std::endl; + changed = true; + continue; + } + + // Which setting was at this location in the input file? + size_t settingEnd = line.find('=', i); + // This should never happen unless the player edited the file while playing. + if (settingEnd == std::string::npos) { + ostream << "# unterminated setting name: " << line << std::endl; + changed = true; + continue; + } + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + // Get the existing value so we can see if we've changed it. + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + // Construct the setting map key to determine whether the setting has already been + // written to the file. + CategorySetting key = std::make_pair(currentCategory, setting); + CategorySettingStatusMap::iterator finder = written.find(key); + + // Settings not in the written map are definitely invalid. Currently, this can only + // happen if the player edited the file while playing, because loadSettingsFile() + // will accept anything and pass it along in the map, but in the future, we might + // want to handle invalid settings more gracefully here. + if (finder == written.end()) { + ostream << "# invalid setting: " << line << std::endl; + changed = true; + continue; + } + + // Write the current value of the setting to the file. The key must exist in the + // settings map because of how written was initialized and finder != end(). + ostream << setting << " = " << settings[key] << std::endl; + // Mark that setting as written. + finder->second = true; + // Did we really change it? + if (value != settings[key]) { + std::cout << "Changed setting: [" << currentCategory << "] " + << setting << " = " << settings[key] << std::endl; + changed = true; + } + // No need to write the current line, because we just emitted a replacement. + + // Curiously, it appears that comments at the ends of lines with settings are not + // allowed, and the comment becomes part of the value. Was that intended? + } + + // We're done with the input stream file. + istream.close(); + + // Ensure that all options in the current category have been written. We must complete + // the current category at the end of the file before moving on to any new categories. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + bool missed = false; + if (mit->second == false && mit->first.first == currentCategory) { + std::cout << "Added new setting: [" << mit->first.first << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // With some further code changes, this comment could be more descriptive. + ostream << std::endl << "# Automatically added setting." << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + mit->second = true; + missed = true; + changed = true; + } + // Ensure that there's a newline before the next section if we added settings. + if (missed) ostream << std::endl; + } + + // This logic triggers when the input file was effectively empty. It could be extended + // to doing something more intelligent instead, like make a copy of the default settings + // file (complete with comments) before continuing. Other code prevents OpenMW from + // executing to this point with a missing config file. + if (!existing) { + ostream << "# This file was automatically generated." << std::endl << std::endl; + } + + // We still have one more thing to do before we're completely done writing the file. + // It's possible that there are entirely new categories, or that the input file had + // disappeared completely, so we need ensure that all settings are written to the file + // regardless of those issues. + for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { + // If the setting hasn't been written yet. + if (mit->second == false) { + // If the catgory has changed, write a new category header. + if (mit->first.first != currentCategory) { + currentCategory = mit->first.first; + std::cout << "Created new setting section: " << mit->first.first << std::endl; + ostream << std::endl; + // Add new category comments only if we're amending an existing file. + if (existing) ostream << "# Automatically added category." << std::endl; + ostream << "[" << currentCategory << "]" << std::endl; + } + std::cout << "Added new setting: [" << mit->first.first << "] " + << mit->first.second << " = " << settings[mit->first] << std::endl; + // Then write the setting. No need to mark it as written because we're done. + ostream << std::endl; + ostream << mit->first.second << " = " << settings[mit->first] << std::endl; + changed = true; + } + } + + // Now install the newly written file in the requested place. + if (changed) { + std::cout << "Updating settings file: " << ipath << std::endl; + boost::filesystem::ofstream ofstream; + ofstream.open(ipath); + ofstream << ostream.rdbuf(); + ofstream.close(); + } + } + private: /// Increment i until it longer points to a whitespace character /// in the string or has reached the end of the string. @@ -155,18 +382,8 @@ void Manager::loadUser(const std::string &file) void Manager::saveUser(const std::string &file) { - boost::filesystem::ofstream stream; - stream.open(boost::filesystem::path(file)); - std::string currentCategory; - for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) - { - if (it->first.first != currentCategory) - { - currentCategory = it->first.first; - stream << "\n[" << currentCategory << "]\n"; - } - stream << it->first.second << " = " << it->second << "\n"; - } + SettingsFileParser parser; + parser.saveSettingsFile(file, mUserSettings); } std::string Manager::getString(const std::string &setting, const std::string &category) From 6882e6451ab027b565c03de5e8da233d72fd937a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 23 Nov 2015 18:55:48 -0500 Subject: [PATCH 1425/1812] Remove tabs. :-[ --- components/settings/settings.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 7abfaff2cd..c72e1ace42 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -194,7 +194,7 @@ public: if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << currentCategory << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. + // With some further code changes, this comment could be more descriptive. ostream << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; @@ -223,9 +223,9 @@ public: if (!skipWhiteSpace(i, line)) continue; - // If we'cve found settings befor ethe first category, something's wrong. This + // If we'cve found settings befor ethe first category, something's wrong. This // should never happen unless the player edited the file while playing, since - // the loadSettingsFile() logic rejects it. + // the loadSettingsFile() logic rejects it. if (currentCategory.empty()) { ostream << "# empty category name: " << line << std::endl; changed = true; @@ -276,7 +276,7 @@ public: } // No need to write the current line, because we just emitted a replacement. - // Curiously, it appears that comments at the ends of lines with settings are not + // Curiously, it appears that comments at the ends of lines with settings are not // allowed, and the comment becomes part of the value. Was that intended? } @@ -290,7 +290,7 @@ public: if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. + // With some further code changes, this comment could be more descriptive. ostream << std::endl << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; @@ -301,10 +301,10 @@ public: if (missed) ostream << std::endl; } - // This logic triggers when the input file was effectively empty. It could be extended - // to doing something more intelligent instead, like make a copy of the default settings - // file (complete with comments) before continuing. Other code prevents OpenMW from - // executing to this point with a missing config file. + // This logic triggers when the input file was effectively empty. It could be extended + // to doing something more intelligent instead, like make a copy of the default settings + // file (complete with comments) before continuing. Other code prevents OpenMW from + // executing to this point with a missing config file. if (!existing) { ostream << "# This file was automatically generated." << std::endl << std::endl; } From 1b77428c59d230883194820f35c1e26c2186658f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Nov 2015 03:42:35 +0100 Subject: [PATCH 1426/1812] Use const reference, thanks ace13 --- components/sceneutil/lightmanager.cpp | 2 +- components/sceneutil/lightmanager.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 43f11cf005..ba2f8c5105 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -164,7 +164,7 @@ namespace SceneUtil mStateSetCache.clear(); } - void LightManager::addLight(LightSource* lightSource, osg::Matrixf worldMat) + void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat) { LightSourceTransform l; l.mLightSource = lightSource; diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index ecee873e86..89ffc13058 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -77,7 +77,7 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, osg::Matrixf worldMat); + void addLight(LightSource* lightSource, const osg::Matrixf& worldMat); struct LightSourceTransform { From e0752ccdd058e3ef6daff73d661b6f24e99c5be8 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Tue, 24 Nov 2015 00:10:23 -0500 Subject: [PATCH 1427/1812] Prioritize warning about user settings. Make recommendations for screen number more generic. Remove resolution recommendation. --- files/settings-default.cfg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3b91e7f0a0..f16ef91248 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,3 +1,6 @@ +# WARNING: Editing this file might have no effect, as these settings +# are overwritten by your user settings file. +# # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the # significance of each setting, interaction with other settings, hard @@ -6,9 +9,6 @@ # # https://wiki.openmw.org/index.php?title=Settings # -# The version of this file that actually controls the behavior of -# OpenMW is user specific, and it's location can be found in the -# documentation above. This file is probably NOT that file... [Camera] @@ -167,14 +167,14 @@ voice volume = 0.8 [Video] -# Resolution of the Open window or screen. (600 to 2560). +# Resolution of the Open window or screen. resolution x = 800 resolution y = 600 # OpenMW takes complete control of the screen. fullscreen = false -# Determines which screen OpenMW is on. (0 or 1). +# Determines which screen OpenMW is on. (>=0). screen = 0 # Minimize OpenMW if it loses cursor or keyboard focus. From edfcb45ad7b9d535c984ccb22e3cc8879ce3a7a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Nov 2015 22:50:54 +0100 Subject: [PATCH 1428/1812] Fix crash when onPcEquip script removes the equipped item (Fixes #3016) --- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++++------- apps/openmw/mwworld/actionequip.cpp | 7 ++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c1e202bc02..e5bf1f4b41 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -471,16 +471,18 @@ namespace MWGui MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); } - if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0) + mSkippedToEquip = MWWorld::Ptr(); + if (ptr.getRefData().getCount()) // make sure the item is still there, the script might have removed it { - boost::shared_ptr action = ptr.getClass().use(ptr); + if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0) + { + boost::shared_ptr action = ptr.getClass().use(ptr); - action->execute (player); - - mSkippedToEquip = MWWorld::Ptr(); + action->execute (player); + } + else + mSkippedToEquip = ptr; } - else - mSkippedToEquip = ptr; if (isVisible()) { diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 147f229638..a6d6eef2b1 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -52,7 +52,12 @@ namespace MWWorld } } - assert(it != invStore.end()); + if (it == invStore.end()) + { + std::stringstream error; + error << "ActionEquip can't find item " << object.getCellRef().getRefId(); + throw std::runtime_error(error.str()); + } // equip the item in the first free slot std::vector::const_iterator slot=slots_.first.begin(); From e2beefd8b59a358544cfb0eede9524459a12f214 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Nov 2015 04:53:24 -0800 Subject: [PATCH 1429/1812] Store info calculated from the ESM::Sound record --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwsound/sound_buffer.hpp | 26 +++++++ apps/openmw/mwsound/soundmanagerimp.cpp | 94 ++++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 8 ++- 4 files changed, 86 insertions(+), 44 deletions(-) create mode 100644 apps/openmw/mwsound/sound_buffer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 59a523023f..48d10e2028 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp new file mode 100644 index 0000000000..fcef7963ab --- /dev/null +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_SOUND_SOUND_BUFFER_H +#define GAME_SOUND_SOUND_BUFFER_H + +#include + +#include "soundmanagerimp.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWSound +{ + class Sound_Buffer + { + public: + std::string mResourceName; + + float mVolume; + float mMinDist, mMaxDist; + + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist) + { } + }; +} + +#endif /* GAME_SOUND_SOUND_BUFFER_H */ diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6e309e28e3..0845240744 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/actorutil.hpp" #include "sound_output.hpp" +#include "sound_buffer.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -103,38 +104,48 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - // Convert a soundId to file name, and modify the volume - // according to the sounds local volume setting, minRange and - // maxRange. - std::string SoundManager::lookup(const std::string &soundId, - float &volume, float &min, float &max) + // Lookup a soundid for its sound data (resource name, local volume, + // minRange and maxRange. The returned pointer is only valid temporarily. + const Sound_Buffer *SoundManager::lookup(const std::string &soundId) { - MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Sound *snd = world->getStore().get().find(soundId); - - volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - - if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); + if(sfxiter == mSoundBuffers.end()) { - static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); - static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); - min = fAudioDefaultMinDistance; - max = fAudioDefaultMaxDistance; - } - else - { - min = snd->mData.mMinRange; - max = snd->mData.mMaxRange; - } + // TODO: We could process all available ESM::Sound records on init + // to pre-fill a non-resizing list, which would allow subsystems to + // reference sounds by index instead of string. + MWBase::World* world = MWBase::Environment::get().getWorld(); + const ESM::Sound *snd = world->getStore().get().find(soundId); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - min *= fAudioMinDistanceMult; - max *= fAudioMaxDistanceMult; - min = std::max(min, 1.0f); - max = std::max(min, max); + float volume, min, max; + volume = static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - return "Sound/"+snd->mSound; + if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + { + static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); + min = fAudioDefaultMinDistance; + max = fAudioDefaultMaxDistance; + } + else + { + min = snd->mData.mMinRange; + max = snd->mData.mMaxRange; + } + + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + min *= fAudioMinDistanceMult; + max *= fAudioMaxDistanceMult; + min = std::max(min, 1.0f); + max = std::max(min, max); + + sfxiter = mSoundBuffers.insert(std::make_pair( + soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) + )).first; + mVFS->normalizeFilename(sfxiter->second.mResourceName); + } + return &sfxiter->second; } // Gets the combined volume settings for the given sound type @@ -268,7 +279,7 @@ namespace MWSound try { float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "Sound/"+filename; + std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -371,11 +382,12 @@ namespace MWSound return sound; try { + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound(file, volume, basevol, pitch, mode|type, offset); + sound = mOutput->playSound(sfx->mResourceName, + volume * sfx->mVolume, basevol, pitch, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception&) @@ -394,18 +406,17 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - if ((mode & Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - { + if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - } - sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); else @@ -427,11 +438,12 @@ namespace MWSound try { // Look up the sound in the ESM data + const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - float min, max; - std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound3D(file, initialPos, volume, basevol, pitch, min, max, mode|type, offset); + sound = mOutput->playSound3D(sfx->mResourceName, + initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index f79bfce155..d9eb7ff3df 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -21,6 +21,7 @@ namespace MWSound class Sound_Output; struct Sound_Decoder; class Sound; + class Sound_Buffer; enum Environment { Env_Normal, @@ -43,6 +44,9 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + typedef std::map NameBufferMap; + NameBufferMap mSoundBuffers; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -59,8 +63,8 @@ namespace MWSound int mPausedSoundTypes; - std::string lookup(const std::string &soundId, - float &volume, float &min, float &max); + const Sound_Buffer *lookup(const std::string &soundId); + void streamMusicFull(const std::string& filename); bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); From 4571218827802651a8b9b6bd734558e1a2a3a463 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 01:01:20 -0800 Subject: [PATCH 1430/1812] Load the sound as needed and pass it directly to the play methods This breaks say sounds, loudness handling, and the cache limit. Fixes are forthcoming. --- apps/openmw/mwsound/openal_output.cpp | 155 ++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 27 +---- apps/openmw/mwsound/sound_buffer.hpp | 5 +- apps/openmw/mwsound/sound_output.hpp | 12 +- apps/openmw/mwsound/soundmanagerimp.cpp | 28 ++++- 5 files changed, 95 insertions(+), 132 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a984fffa97..b71fe4d809 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,6 +19,9 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif +#define MAKE_PTRID(id) ((void*)(uintptr_t)id) +#define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) + namespace { const int loudnessFPS = 20; // loudness values per second of audio @@ -545,7 +548,6 @@ OpenAL_Sound::~OpenAL_Sound() alSourcei(mSource, AL_BUFFER, 0); mOutput.mFreeSources.push_back(mSource); - mOutput.bufferFinished(mBuffer); mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), mOutput.mActiveSounds.end(), this)); @@ -737,14 +739,6 @@ void OpenAL_Output::deinit() alDeleteSources(1, &mFreeSources[i]); mFreeSources.clear(); - mBufferRefs.clear(); - mUnusedBuffers.clear(); - while(!mBufferCache.empty()) - { - alDeleteBuffers(1, &mBufferCache.begin()->second.mALBuffer); - mBufferCache.erase(mBufferCache.begin()); - } - alcMakeContextCurrent(0); if(mContext) alcDestroyContext(mContext); @@ -757,32 +751,10 @@ void OpenAL_Output::deinit() } -const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { - ALuint buf = 0; - - NameMap::iterator iditer = mBufferCache.find(fname); - if(iditer != mBufferCache.end()) - { - buf = iditer->second.mALBuffer; - if(mBufferRefs[buf]++ == 0) - { - IDDq::iterator iter = std::find(mUnusedBuffers.begin(), - mUnusedBuffers.end(), buf); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - - return iditer->second; - } throwALerror(); - std::vector data; - ChannelConfig chans; - SampleType type; - ALenum format; - int srate; - DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. std::string file = fname; @@ -794,87 +766,70 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) } decoder->open(file); + std::vector data; + ChannelConfig chans; + SampleType type; + ALenum format; + int srate; + decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); decoder->readAll(data); decoder->close(); - CachedSound cached; - analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); + //analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); - alGenBuffers(1, &buf); - throwALerror(); - - alBufferData(buf, format, &data[0], data.size(), srate); - mBufferRefs[buf] = 1; - cached.mALBuffer = buf; - mBufferCache[fname] = cached; - - ALint bufsize = 0; - alGetBufferi(buf, AL_SIZE, &bufsize); - mBufferCacheMemSize += bufsize; - - // NOTE: Max buffer cache: 15MB - while(mBufferCacheMemSize > 15*1024*1024) - { - if(mUnusedBuffers.empty()) - { - std::cout <<"No more unused buffers to clear!"<< std::endl; - break; - } - - ALuint oldbuf = mUnusedBuffers.front(); - mUnusedBuffers.pop_front(); - - NameMap::iterator nameiter = mBufferCache.begin(); - while(nameiter != mBufferCache.end()) - { - if(nameiter->second.mALBuffer == oldbuf) - mBufferCache.erase(nameiter++); - else - ++nameiter; - } - - bufsize = 0; - alGetBufferi(oldbuf, AL_SIZE, &bufsize); - alDeleteBuffers(1, &oldbuf); - mBufferCacheMemSize -= bufsize; + ALuint buf = 0; + try { + alGenBuffers(1, &buf); + alBufferData(buf, format, &data[0], data.size(), srate); + throwALerror(); } - - return mBufferCache[fname]; + catch(...) { + if(buf && alIsBuffer(buf)) + alDeleteBuffers(1, &buf); + throw; + } + return MAKE_PTRID(buf); } -void OpenAL_Output::bufferFinished(ALuint buf) +void OpenAL_Output::unloadSound(Sound_Handle data) { - if(mBufferRefs.at(buf)-- == 1) + ALuint buffer = GET_PTRID(data); + // Make sure no sources are playing this buffer before unloading it. + SoundVec::const_iterator iter = mActiveSounds.begin(); + for(;iter != mActiveSounds.end();++iter) { - mBufferRefs.erase(mBufferRefs.find(buf)); - mUnusedBuffers.push_back(buf); + OpenAL_Sound *sound = dynamic_cast(*iter); + if(sound && sound->mSource && sound->mBuffer == buffer) + { + alSourceStop(sound->mSource); + alSourcei(sound->mSource, AL_BUFFER, 0); + sound->mBuffer = 0; + } } + alDeleteBuffers(1, &buffer); } -MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags,float offset) + +MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { boost::shared_ptr sound; - ALuint src=0, buf=0; + ALuint src=0; if(mFreeSources.empty()) fail("No free sources"); src = mFreeSources.front(); mFreeSources.pop_front(); - try - { - buf = getBuffer(fname).mALBuffer; - sound.reset(new OpenAL_Sound(*this, src, buf, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + ALuint buffer = GET_PTRID(data); + try { + sound.reset(new OpenAL_Sound(*this, src, buffer, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { mFreeSources.push_back(src); - if(buf && alIsBuffer(buf)) - bufferFinished(buf); - alGetError(); throw; } @@ -884,7 +839,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f if(offset>1) offset=1; - alSourcei(src, AL_BUFFER, buf); + alSourcei(src, AL_BUFFER, buffer); alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -892,32 +847,24 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f return sound; } -MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float min, float max, int flags, float offset, bool extractLoudness) +MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, + float min, float max, int flags, float offset) { boost::shared_ptr sound; - ALuint src=0, buf=0; + ALuint src=0; if(mFreeSources.empty()) fail("No free sources"); src = mFreeSources.front(); mFreeSources.pop_front(); - try - { - const CachedSound& cached = getBuffer(fname); - buf = cached.mALBuffer; - - sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); - if (extractLoudness) - sound->setLoudnessVector(cached.mLoudnessVector, static_cast(loudnessFPS)); + ALuint buffer = GET_PTRID(data); + try { + sound.reset(new OpenAL_Sound3D(*this, src, buffer, pos, vol, basevol, pitch, min, max, flags)); } catch(std::exception&) { mFreeSources.push_back(src); - if(buf && alIsBuffer(buf)) - bufferFinished(buf); - alGetError(); throw; } @@ -928,7 +875,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const osg: if(offset>1) offset=1; - alSourcei(src, AL_BUFFER, buf); + alSourcei(src, AL_BUFFER, buffer); alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); @@ -1041,8 +988,8 @@ void OpenAL_Output::resumeSounds(int types) OpenAL_Output::OpenAL_Output(SoundManager &mgr) - : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), - mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) + : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), + mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 755a0e5b62..8af46a4780 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,12 +16,6 @@ namespace MWSound class SoundManager; class Sound; - struct CachedSound - { - ALuint mALBuffer; - std::vector mLoudnessVector; - }; - class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -29,33 +23,24 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - IDDq mUnusedBuffers; - - typedef std::map NameMap; - NameMap mBufferCache; - - typedef std::map IDRefMap; - IDRefMap mBufferRefs; - - uint64_t mBufferCacheMemSize; typedef std::vector SoundVec; SoundVec mActiveSounds; - const CachedSound& getBuffer(const std::string &fname); - void bufferFinished(ALuint buffer); - Environment mLastEnvironment; virtual std::vector enumerate(); virtual void init(const std::string &devname=""); virtual void deinit(); + virtual Sound_Handle loadSound(const std::string &fname); + virtual void unloadSound(Sound_Handle data); + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset); + virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false); + virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index fcef7963ab..37f49e5181 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -4,6 +4,7 @@ #include #include "soundmanagerimp.hpp" +#include "sound_output.hpp" #include "../mwworld/ptr.hpp" @@ -17,8 +18,10 @@ namespace MWSound float mVolume; float mMinDist, mMaxDist; + Sound_Handle mHandle; + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index a0c6fb17b9..cbda19d59d 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -14,6 +14,9 @@ namespace MWSound struct Sound_Decoder; class Sound; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + class Sound_Output { SoundManager &mManager; @@ -22,11 +25,14 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; + virtual void unloadSound(Sound_Handle data) = 0; + /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags, float offset) = 0; + virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playSound3D(const std::string &fname, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset, bool extractLoudness=false) = 0; + virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0845240744..820a9841d6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,6 +92,16 @@ namespace MWSound SoundManager::~SoundManager() { + if(mOutput->isInitialized()) + { + NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); + for(;sfxiter != mSoundBuffers.end();++sfxiter) + { + if(sfxiter->second.mHandle) + mOutput->unloadSound(sfxiter->second.mHandle); + sfxiter->second.mHandle = 0; + } + } mUnderwaterSound.reset(); mActiveSounds.clear(); mMusic.reset(); @@ -144,7 +154,11 @@ namespace MWSound soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); } + else if(!sfxiter->second.mHandle) + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + return &sfxiter->second; } @@ -278,6 +292,7 @@ namespace MWSound return; try { +#if 0 float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -297,6 +312,9 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice, 0, true); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); +#else + throw std::runtime_error("say disabled"); +#endif } catch(std::exception &e) { @@ -325,11 +343,15 @@ namespace MWSound return; try { +#if 0 float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); +#else + throw std::runtime_error("say disabled"); +#endif } catch(std::exception &e) { @@ -385,7 +407,7 @@ namespace MWSound const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound(sfx->mResourceName, + sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); @@ -414,7 +436,7 @@ namespace MWSound if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - sound = mOutput->playSound3D(sfx->mResourceName, + sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if((mode&Play_NoTrack)) @@ -441,7 +463,7 @@ namespace MWSound const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound3D(sfx->mResourceName, + sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); From f4c22ec49e14dd348446e8574c4f50be4db8692e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 01:33:59 -0800 Subject: [PATCH 1431/1812] Hold a separate list for voice sound buffers This fixes say. Ideally voices would be streamed, but the loudness/"lip" buffer extraction should be separated from the buffer loading code. --- apps/openmw/mwsound/openal_output.cpp | 4 +- apps/openmw/mwsound/soundmanagerimp.cpp | 70 ++++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b71fe4d809..381c5ba180 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -816,7 +816,7 @@ void OpenAL_Output::unloadSound(Sound_Handle data) MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { boost::shared_ptr sound; - ALuint src=0; + ALuint src; if(mFreeSources.empty()) fail("No free sources"); @@ -851,7 +851,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f float min, float max, int flags, float offset) { boost::shared_ptr sound; - ALuint src=0; + ALuint src; if(mFreeSources.empty()) fail("No free sources"); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 820a9841d6..6e95c1116e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -101,6 +101,13 @@ namespace MWSound mOutput->unloadSound(sfxiter->second.mHandle); sfxiter->second.mHandle = 0; } + sfxiter = mVoiceSoundBuffers.begin(); + for(;sfxiter != mVoiceSoundBuffers.end();++sfxiter) + { + if(sfxiter->second.mHandle) + mOutput->unloadSound(sfxiter->second.mHandle); + sfxiter->second.mHandle = 0; + } } mUnderwaterSound.reset(); mActiveSounds.clear(); @@ -162,6 +169,35 @@ namespace MWSound return &sfxiter->second; } + const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) + { + NameBufferMap::iterator sfxiter = mVoiceSoundBuffers.find(voicefile); + if(sfxiter == mVoiceSoundBuffers.end()) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + + float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; + float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; + minDistance = std::max(minDistance, 1.f); + maxDistance = std::max(minDistance, maxDistance); + + sfxiter = mVoiceSoundBuffers.insert(std::make_pair( + voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) + )).first; + mVFS->normalizeFilename(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + } + else if(!sfxiter->second.mHandle) + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + + return &sfxiter->second; + } + + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -286,35 +322,21 @@ namespace MWSound startRandomTitle(); } - void SoundManager::say(const MWWorld::Ptr &ptr, const std::string& filename) + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; try { -#if 0 + const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); - - float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; - float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; - minDistance = std::max(minDistance, 1.f); - maxDistance = std::max(minDistance, maxDistance); - - MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, - minDistance, maxDistance, Play_Normal|Play_TypeVoice, 0, true); + MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, + objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 + ); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); -#else - throw std::runtime_error("say disabled"); -#endif } catch(std::exception &e) { @@ -343,15 +365,13 @@ namespace MWSound return; try { -#if 0 + const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); float basevol = volumeFromType(Play_TypeVoice); - std::string filePath = "Sound/"+filename; - MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); + MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, + sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 + ); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); -#else - throw std::runtime_error("say disabled"); -#endif } catch(std::exception &e) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d9eb7ff3df..5d605a90fc 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -46,6 +46,9 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; + // Should stream voices, but that requires handling the "lip" data + // separately from buffer loading. + NameBufferMap mVoiceSoundBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -64,6 +67,7 @@ namespace MWSound int mPausedSoundTypes; const Sound_Buffer *lookup(const std::string &soundId); + const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; From 495e13890793d69452336313761eb77774bbd6de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 02:08:27 -0800 Subject: [PATCH 1432/1812] Load sound loudness and store it with the Sound_Buffer Still not used for say yet, though --- apps/openmw/mwsound/loudness.cpp | 86 ++++++++++++++----------- apps/openmw/mwsound/loudness.hpp | 44 +++++++++---- apps/openmw/mwsound/openal_output.cpp | 5 +- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound.cpp | 23 ------- apps/openmw/mwsound/sound.hpp | 9 --- apps/openmw/mwsound/sound_buffer.hpp | 2 + apps/openmw/mwsound/sound_output.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +- 9 files changed, 91 insertions(+), 89 deletions(-) delete mode 100644 apps/openmw/mwsound/sound.cpp diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 12fe8ae4d0..21f399ddc5 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -8,49 +8,61 @@ namespace MWSound { - void analyzeLoudness(const std::vector &data, int sampleRate, ChannelConfig chans, - SampleType type, std::vector &out, float valuesPerSecond) +void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sampleRate, ChannelConfig chans, SampleType type, float valuesPerSecond) +{ + int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); + int numSamples = bytesToFrames(data.size(), chans, type); + int advance = framesToBytes(1, chans, type); + + mSamplesPerSec = valuesPerSecond; + mSamples.clear(); + mSamples.reserve(numSamples/samplesPerSegment); + + int segment=0; + int sample=0; + while (segment < numSamples/samplesPerSegment) { - int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); - int numSamples = bytesToFrames(data.size(), chans, type); - int advance = framesToBytes(1, chans, type); - - out.reserve(numSamples/samplesPerSegment); - - int segment=0; - int sample=0; - while (segment < numSamples/samplesPerSegment) + float sum=0; + int samplesAdded = 0; + while (sample < numSamples && sample < (segment+1)*samplesPerSegment) { - float sum=0; - int samplesAdded = 0; - while (sample < numSamples && sample < (segment+1)*samplesPerSegment) + // get sample on a scale from -1 to 1 + float value = 0; + if (type == SampleType_UInt8) + value = ((char)(data[sample*advance]^0x80))/128.f; + else if (type == SampleType_Int16) { - // get sample on a scale from -1 to 1 - float value = 0; - if (type == SampleType_UInt8) - value = ((char)(data[sample*advance]^0x80))/128.f; - else if (type == SampleType_Int16) - { - value = *reinterpret_cast(&data[sample*advance]); - value /= float(std::numeric_limits::max()); - } - else if (type == SampleType_Float32) - { - value = *reinterpret_cast(&data[sample*advance]); - value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already. - } - - sum += value*value; - ++samplesAdded; - ++sample; + value = *reinterpret_cast(&data[sample*advance]); + value /= float(std::numeric_limits::max()); + } + else if (type == SampleType_Float32) + { + value = *reinterpret_cast(&data[sample*advance]); + value = std::max(-1.f, std::min(1.f, value)); // Float samples *should* be scaled to [-1,1] already. } - float rms = 0; // root mean square - if (samplesAdded > 0) - rms = std::sqrt(sum / samplesAdded); - out.push_back(rms); - ++segment; + sum += value*value; + ++samplesAdded; + ++sample; } + + float rms = 0; // root mean square + if (samplesAdded > 0) + rms = std::sqrt(sum / samplesAdded); + mSamples.push_back(rms); + ++segment; } +} + + +float Sound_Loudness::getLoudnessAtTime(float sec) const +{ + if(mSamplesPerSec <= 0.0f || mSamples.empty() || sec < 0.0f) + return 0.0f; + + size_t index = static_cast(sec * mSamplesPerSec); + index = std::max(0, std::min(index, mSamples.size()-1)); + return mSamples[index]; +} } diff --git a/apps/openmw/mwsound/loudness.hpp b/apps/openmw/mwsound/loudness.hpp index df727bd0b2..a0af2b5586 100644 --- a/apps/openmw/mwsound/loudness.hpp +++ b/apps/openmw/mwsound/loudness.hpp @@ -1,20 +1,38 @@ +#ifndef GAME_SOUND_LOUDNESS_H +#define GAME_SOUND_LOUDNESS_H + +#include + #include "sound_decoder.hpp" namespace MWSound { -/** - * Analyzes the energy (closely related to loudness) of a sound buffer. - * The buffer will be divided into segments according to \a valuesPerSecond, - * and for each segment a loudness value in the range of [0,1] will be computed. - * @param data the sound buffer to analyze, containing raw samples - * @param sampleRate the sample rate of the sound buffer - * @param chans channel layout of the buffer - * @param type sample type of the buffer - * @param out Will contain the output loudness values. - * @param valuesPerSecond How many loudness values per second of audio to compute. - */ -void analyzeLoudness (const std::vector& data, int sampleRate, ChannelConfig chans, SampleType type, - std::vector& out, float valuesPerSecond); +class Sound_Loudness { + // Loudness sample info + float mSamplesPerSec; + std::vector mSamples; + +public: + Sound_Loudness() : mSamplesPerSec(0.0f) { } + + /** + * Analyzes the energy (closely related to loudness) of a sound buffer. + * The buffer will be divided into segments according to \a valuesPerSecond, + * and for each segment a loudness value in the range of [0,1] will be computed. + * @param data the sound buffer to analyze, containing raw samples + * @param sampleRate the sample rate of the sound buffer + * @param chans channel layout of the buffer + * @param type sample type of the buffer + * @param valuesPerSecond How many loudness values per second of audio to compute. + */ + void analyzeLoudness(const std::vector& data, int sampleRate, + ChannelConfig chans, SampleType type, + float valuesPerSecond); + + float getLoudnessAtTime(float sec) const; +}; } + +#endif /* GAME_SOUND_LOUDNESS_H */ diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 381c5ba180..82d56ffa07 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -751,7 +751,7 @@ void OpenAL_Output::deinit() } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness *loudness) { throwALerror(); @@ -778,7 +778,8 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->readAll(data); decoder->close(); - //analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); + if(loudness != 0) + loudness->analyzeLoudness(data, srate, chans, type, static_cast(loudnessFPS)); ALuint buf = 0; try { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 8af46a4780..b4c788faaa 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -33,7 +33,7 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual Sound_Handle loadSound(const std::string &fname); + virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); virtual void unloadSound(Sound_Handle data); /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. diff --git a/apps/openmw/mwsound/sound.cpp b/apps/openmw/mwsound/sound.cpp deleted file mode 100644 index 8b6bfda822..0000000000 --- a/apps/openmw/mwsound/sound.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "sound.hpp" - -namespace MWSound -{ - - float Sound::getCurrentLoudness() - { - if (mLoudnessVector.empty()) - return 0.f; - int index = static_cast(getTimeOffset() * mLoudnessFPS); - - index = std::max(0, std::min(index, int(mLoudnessVector.size()-1))); - - return mLoudnessVector[index]; - } - - void Sound::setLoudnessVector(const std::vector &loudnessVector, float loudnessFPS) - { - mLoudnessVector = loudnessVector; - mLoudnessFPS = loudnessFPS; - } - -} diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 96f59cea00..53b258a6a3 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -22,9 +22,6 @@ namespace MWSound int mFlags; float mFadeOutTime; - std::vector mLoudnessVector; - float mLoudnessFPS; - public: virtual void stop() = 0; virtual bool isPlaying() = 0; @@ -32,11 +29,6 @@ namespace MWSound void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setFadeout(float duration) { mFadeOutTime=duration; } - void setLoudnessVector(const std::vector& loudnessVector, float loudnessFPS); - - /// Get loudness at the current time position on a [0,1] scale. - /// Requires that loudnessVector was filled in by the user. - float getCurrentLoudness(); MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } @@ -51,7 +43,6 @@ namespace MWSound , mMaxDistance(maxdist) , mFlags(flags) , mFadeOutTime(0) - , mLoudnessFPS(20) { } virtual ~Sound() { } diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 37f49e5181..8ee7ae342c 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -5,6 +5,7 @@ #include "soundmanagerimp.hpp" #include "sound_output.hpp" +#include "loudness.hpp" #include "../mwworld/ptr.hpp" @@ -19,6 +20,7 @@ namespace MWSound float mMinDist, mMaxDist; Sound_Handle mHandle; + Sound_Loudness mLoudness; Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index cbda19d59d..5c437a6996 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -13,6 +13,7 @@ namespace MWSound class SoundManager; struct Sound_Decoder; class Sound; + class Sound_Loudness; // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; @@ -25,7 +26,7 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual Sound_Handle loadSound(const std::string &fname) = 0; + virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; virtual void unloadSound(Sound_Handle data) = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6e95c1116e..d48c614ddd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -189,10 +189,10 @@ namespace MWSound voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); } else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); return &sfxiter->second; } @@ -356,7 +356,7 @@ namespace MWSound if (snditer == mActiveSounds.end()) return 0.f; - return snditer->first->getCurrentLoudness(); + return 0.0f; } void SoundManager::say(const std::string& filename) From 9d0018e1bc0ad40dec7b1ab0dca880642e4c7ae7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 03:07:04 -0800 Subject: [PATCH 1433/1812] Reorder active sound data to make lookup by Ptr better --- apps/openmw/mwsound/soundmanagerimp.cpp | 223 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 5 +- 2 files changed, 135 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d48c614ddd..4eecf9a148 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -226,12 +226,15 @@ namespace MWSound bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const { - SoundMap::const_iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == id && snditer->first->isPlaying()) - return true; - ++snditer; + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == id && sndname->first->isPlaying()) + return true; + } } return false; } @@ -336,7 +339,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); + mActiveSounds[ptr].push_back(std::make_pair(sound, std::string("_say_sound"))); } catch(std::exception &e) { @@ -346,15 +349,16 @@ namespace MWSound float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const { - SoundMap::const_iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == "_say_sound") - break; - ++snditer; + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == "_say_sound") + return 0.0f; + } } - if (snditer == mActiveSounds.end()) - return 0.f; return 0.0f; } @@ -371,7 +375,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, std::string("_say_sound"))); } catch(std::exception &e) { @@ -386,16 +390,21 @@ namespace MWSound void SoundManager::stopSay(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == "_say_sound") + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != "_say_sound") + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } @@ -430,7 +439,7 @@ namespace MWSound sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); } catch(std::exception&) { @@ -460,9 +469,9 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if((mode&Play_NoTrack)) - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); else - mActiveSounds[sound] = std::make_pair(ptr, soundId); + mActiveSounds[ptr].push_back(std::make_pair(sound, soundId)); } catch(std::exception&) { @@ -486,7 +495,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); } catch(std::exception &) { @@ -500,43 +509,50 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->first == sound) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->first != sound) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != soundId) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr) - { - snditer->first->stop(); - mActiveSounds.erase(snditer++); - } - else - ++snditer; + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); + mActiveSounds.erase(snditer); } } @@ -545,11 +561,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first != MWMechanics::getPlayer() && - snditer->second.first.getCell() == cell) + if(snditer->first != MWWorld::Ptr() && + snditer->first != MWMechanics::getPlayer() && + snditer->first.getCell() == cell) { - snditer->first->stop(); + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); mActiveSounds.erase(snditer++); } else @@ -559,31 +577,36 @@ namespace MWSound void SoundManager::stopSound(const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == MWWorld::Ptr() && - snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->stop(); - mActiveSounds.erase(snditer++); + if(sndname->second != soundId) + continue; + + sndname->first->stop(); + snditer->second.erase(sndname); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); + return; } - else - ++snditer; } } void SoundManager::fadeOutSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, float duration) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) { - if(snditer->second.first == ptr && snditer->second.second == soundId) + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) { - snditer->first->setFadeout(duration); + if(sndname->second == soundId) + sndname->first->setFadeout(duration); } - ++snditer; } } @@ -714,37 +737,47 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(!snditer->first->isPlaying()) - mActiveSounds.erase(snditer++); - else + SoundNamePairList::iterator sndname = snditer->second.begin(); + while(sndname != snditer->second.end()) { - const MWWorld::Ptr &ptr = snditer->second.first; + if(!sndname->first->isPlaying()) + { + sndname = snditer->second.erase(sndname); + continue; + } + + const MWWorld::Ptr &ptr = snditer->first; if(!ptr.isEmpty()) { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - snditer->first->setPosition(objpos); + sndname->first->setPosition(objpos); - if ((snditer->first->mFlags & Play_RemoveAtDistance) + if ((sndname->first->mFlags & Play_RemoveAtDistance) && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { - mActiveSounds.erase(snditer++); + sndname = snditer->second.erase(sndname); continue; } } + //update fade out - if(snditer->first->mFadeOutTime>0) + if(sndname->first->mFadeOutTime > 0.0f) { - float soundDuration=duration; - if(soundDuration>snditer->first->mFadeOutTime) - soundDuration=snditer->first->mFadeOutTime; - snditer->first->setVolume(snditer->first->mVolume - - soundDuration / snditer->first->mFadeOutTime * snditer->first->mVolume); - snditer->first->mFadeOutTime -= soundDuration; + float soundDuration = duration; + if(soundDuration > sndname->first->mFadeOutTime) + soundDuration = sndname->first->mFadeOutTime; + sndname->first->setVolume(sndname->first->mVolume + - soundDuration / sndname->first->mFadeOutTime * sndname->first->mVolume); + sndname->first->mFadeOutTime -= soundDuration; } - snditer->first->update(); - ++snditer; + sndname->first->update(); + ++sndname; } + if(snditer->second.empty()) + mActiveSounds.erase(snditer++); + else + ++snditer; } } @@ -771,11 +804,14 @@ namespace MWSound mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + for(;snditer != mActiveSounds.end();++snditer) { - snditer->first->mBaseVolume = volumeFromType(snditer->first->getPlayType()); - snditer->first->update(); - ++snditer; + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + sndname->first->mBaseVolume = volumeFromType(sndname->first->getPlayType()); + sndname->first->update(); + } } if(mMusic) { @@ -790,8 +826,7 @@ namespace MWSound mListenerDir = dir; mListenerUp = up; - MWWorld::Ptr player = - MWMechanics::getPlayer(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::CellStore *cell = player.getCell(); mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); @@ -799,10 +834,12 @@ namespace MWSound void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { - for (SoundMap::iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + SoundMap::iterator snditer = mActiveSounds.find(old); + if(snditer != mActiveSounds.end()) { - if (snditer->second.first == old) - snditer->second.first = updated; + SoundNamePairList sndlist = snditer->second; + mActiveSounds.erase(snditer); + mActiveSounds[updated] = sndlist; } } @@ -873,9 +910,13 @@ namespace MWSound void SoundManager::clear() { - for (SoundMap::iterator iter (mActiveSounds.begin()); iter!=mActiveSounds.end(); ++iter) - iter->first->stop(); - + SoundMap::iterator snditer = mActiveSounds.begin(); + for(;snditer != mActiveSounds.end();++snditer) + { + SoundNamePairList::iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + sndname->first->stop(); + } mActiveSounds.clear(); stopMusic(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d605a90fc..999a49f8c8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -53,8 +53,9 @@ namespace MWSound boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair PtrIDPair; - typedef std::map SoundMap; + typedef std::pair SoundNamePair; + typedef std::vector SoundNamePairList; + typedef std::map SoundMap; SoundMap mActiveSounds; MWBase::SoundPtr mUnderwaterSound; From 3fdc3c4ea948dd5e108eabbaaa986e6ab2560d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:00:10 -0800 Subject: [PATCH 1434/1812] Use a separate map for say sounds Also restores lip movement --- apps/openmw/mwsound/soundmanagerimp.cpp | 171 ++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 3 + 2 files changed, 121 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4eecf9a148..262bc06446 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,6 +92,10 @@ namespace MWSound SoundManager::~SoundManager() { + mUnderwaterSound.reset(); + mActiveSounds.clear(); + mActiveSaySounds.clear(); + mMusic.reset(); if(mOutput->isInitialized()) { NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); @@ -109,9 +113,6 @@ namespace MWSound sfxiter->second.mHandle = 0; } } - mUnderwaterSound.reset(); - mActiveSounds.clear(); - mMusic.reset(); mOutput.reset(); } @@ -224,21 +225,6 @@ namespace MWSound return volume; } - bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const - { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) - { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second == id && sndname->first->isPlaying()) - return true; - } - } - return false; - } - void SoundManager::stopMusic() { @@ -325,13 +311,15 @@ namespace MWSound startRandomTitle(); } + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; try { - const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); + std::string voicefile = Misc::StringUtils::lowerCase(filename); + const Sound_Buffer *sfx = lookupVoice(voicefile); float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -339,7 +327,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[ptr].push_back(std::make_pair(sound, std::string("_say_sound"))); + mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); } catch(std::exception &e) { @@ -349,14 +337,15 @@ namespace MWSound float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) + SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + NameBufferMap::const_iterator sfxiter = mVoiceSoundBuffers.find(snditer->second.second); + if(sfxiter != mVoiceSoundBuffers.end()) { - if(sndname->second == "_say_sound") - return 0.0f; + float sec = snditer->second.first->getTimeOffset(); + if(snditer->second.first->isPlaying()) + return sfxiter->second.mLoudness.getLoudnessAtTime(sec); } } @@ -369,13 +358,14 @@ namespace MWSound return; try { - const Sound_Buffer *sfx = lookupVoice(Misc::StringUtils::lowerCase(filename)); + std::string voicefile = Misc::StringUtils::lowerCase(filename); + const Sound_Buffer *sfx = lookupVoice(voicefile); float basevol = volumeFromType(Play_TypeVoice); MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, std::string("_say_sound"))); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); } catch(std::exception &e) { @@ -385,26 +375,22 @@ namespace MWSound bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const { - return !isPlaying(ptr, "_say_sound"); + SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) + { + if(snditer->second.first->isPlaying()) + return false; + } + return true; } void SoundManager::stopSay(const MWWorld::Ptr &ptr) { - SoundMap::iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) + SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); + if(snditer != mActiveSaySounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second != "_say_sound") - continue; - - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); - return; - } + snditer->second.first->stop(); + mActiveSaySounds.erase(snditer); } } @@ -426,6 +412,21 @@ namespace MWSound } + bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const + { + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) + { + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == id && sndname->first->isPlaying()) + return true; + } + } + return false; + } + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -573,6 +574,19 @@ namespace MWSound else ++snditer; } + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + while(sayiter != mActiveSaySounds.end()) + { + if(sayiter->first != MWWorld::Ptr() && + sayiter->first != MWMechanics::getPlayer() && + sayiter->first.getCell() == cell) + { + sayiter->second.first->stop(); + mActiveSaySounds.erase(sayiter++); + } + else + ++sayiter; + } } void SoundManager::stopSound(const std::string& soundId) @@ -740,7 +754,8 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); while(sndname != snditer->second.end()) { - if(!sndname->first->isPlaying()) + MWBase::SoundPtr sound = sndname->first; + if(!sound->isPlaying()) { sndname = snditer->second.erase(sndname); continue; @@ -751,9 +766,9 @@ namespace MWSound { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - sndname->first->setPosition(objpos); + sound->setPosition(objpos); - if ((sndname->first->mFlags & Play_RemoveAtDistance) + if ((sound->mFlags & Play_RemoveAtDistance) && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) { sndname = snditer->second.erase(sndname); @@ -762,16 +777,16 @@ namespace MWSound } //update fade out - if(sndname->first->mFadeOutTime > 0.0f) + if(sound->mFadeOutTime > 0.0f) { float soundDuration = duration; - if(soundDuration > sndname->first->mFadeOutTime) - soundDuration = sndname->first->mFadeOutTime; - sndname->first->setVolume(sndname->first->mVolume - - soundDuration / sndname->first->mFadeOutTime * sndname->first->mVolume); - sndname->first->mFadeOutTime -= soundDuration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; } - sndname->first->update(); + sound->update(); + ++sndname; } if(snditer->second.empty()) @@ -779,6 +794,45 @@ namespace MWSound else ++snditer; } + + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + while(sayiter != mActiveSaySounds.end()) + { + MWBase::SoundPtr sound = sayiter->second.first; + if(!sound->isPlaying()) + { + mActiveSaySounds.erase(sayiter++); + continue; + } + + const MWWorld::Ptr &ptr = sayiter->first; + if(!ptr.isEmpty()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if ((sound->mFlags & Play_RemoveAtDistance) + && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) + { + mActiveSaySounds.erase(sayiter++); + continue; + } + } + + //update fade out + if(sound->mFadeOutTime > 0.0f) + { + float soundDuration = duration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; + } + sound->update(); + + ++sayiter; + } } void SoundManager::update(float duration) @@ -841,6 +895,13 @@ namespace MWSound mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } + SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); + if(sayiter != mActiveSaySounds.end()) + { + SoundNamePair sndlist = sayiter->second; + mActiveSaySounds.erase(sayiter); + mActiveSaySounds[updated] = sndlist; + } } // Default readAll implementation, for decoders that can't do anything @@ -918,6 +979,10 @@ namespace MWSound sndname->first->stop(); } mActiveSounds.clear(); + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + for(;sayiter != mActiveSaySounds.end();++sayiter) + sayiter->second.first->stop(); + mActiveSaySounds.clear(); stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 999a49f8c8..acd04fc078 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -58,6 +58,9 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; + typedef std::map SaySoundMap; + SaySoundMap mActiveSaySounds; + MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; From febc7b510a0718620c12f7d6695c45b818654c0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:10:56 -0800 Subject: [PATCH 1435/1812] Remove an unneeded method --- apps/openmw/mwsound/soundmanagerimp.cpp | 27 ++++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 262bc06446..73c9060bd2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -412,21 +412,6 @@ namespace MWSound } - bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const - { - SoundMap::const_iterator snditer = mActiveSounds.find(ptr); - if(snditer != mActiveSounds.end()) - { - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->second == id && sndname->first->isPlaying()) - return true; - } - } - return false; - } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -626,7 +611,17 @@ namespace MWSound bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const { - return isPlaying(ptr, soundId); + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer != mActiveSounds.end()) + { + SoundNamePairList::const_iterator sndname = snditer->second.begin(); + for(;sndname != snditer->second.end();++sndname) + { + if(sndname->second == soundId && sndname->first->isPlaying()) + return true; + } + } + return false; } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index acd04fc078..896cf48a7a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -74,7 +74,6 @@ namespace MWSound const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); - bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); void updateRegionSound(float duration); From e36289681776bdbe4556a98816029fe71596e511 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:31:15 -0800 Subject: [PATCH 1436/1812] Combine some duplicate code --- apps/openmw/mwsound/soundmanagerimp.cpp | 118 +++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 47 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 73c9060bd2..e00e5eecd1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -722,12 +722,7 @@ namespace MWSound Environment env = Env_Normal; if (mListenerUnderwater) - { env = Env_Underwater; - //play underwater sound - if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); - } else if(mUnderwaterSound) { mUnderwaterSound->stop(); @@ -741,48 +736,24 @@ namespace MWSound env ); + if(mListenerUnderwater) + { + // Play underwater sound (after updating listener) + if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + } + // Check if any sounds are finished playing, and trash them - // Lower volume on fading out sounds SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { SoundNamePairList::iterator sndname = snditer->second.begin(); while(sndname != snditer->second.end()) { - MWBase::SoundPtr sound = sndname->first; - if(!sound->isPlaying()) - { + if(!updateSound(sndname->first, snditer->first, duration)) sndname = snditer->second.erase(sndname); - continue; - } - - const MWWorld::Ptr &ptr = snditer->first; - if(!ptr.isEmpty()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); - - if ((sound->mFlags & Play_RemoveAtDistance) - && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) - { - sndname = snditer->second.erase(sndname); - continue; - } - } - - //update fade out - if(sound->mFadeOutTime > 0.0f) - { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; - } - sound->update(); - - ++sndname; + else + ++sndname; } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -793,43 +764,46 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - MWBase::SoundPtr sound = sayiter->second.first; - if(!sound->isPlaying()) - { + if(!updateSound(sayiter->second.first, sayiter->first, duration)) mActiveSaySounds.erase(sayiter++); - continue; - } - - const MWWorld::Ptr &ptr = sayiter->first; - if(!ptr.isEmpty()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); - - if ((sound->mFlags & Play_RemoveAtDistance) - && (mListenerPos - ptr.getRefData().getPosition().asVec3()).length2() > 2000*2000) - { - mActiveSaySounds.erase(sayiter++); - continue; - } - } - - //update fade out - if(sound->mFadeOutTime > 0.0f) - { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; - } - sound->update(); - - ++sayiter; + else + ++sayiter; } } + bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) + { + if(!ptr.isEmpty()) + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if((sound->mFlags&Play_RemoveAtDistance)) + { + osg::Vec3f diff = mListenerPos - ptr.getRefData().getPosition().asVec3(); + if(diff.length2() > 2000*2000) + sound->stop(); + } + } + + if(!sound->isPlaying()) + return false; + + // Update fade out + if(sound->mFadeOutTime > 0.0f) + { + float soundDuration = duration; + if(soundDuration > sound->mFadeOutTime) + soundDuration = sound->mFadeOutTime; + sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); + sound->mFadeOutTime -= soundDuration; + } + sound->update(); + return true; + } + + void SoundManager::update(float duration) { if(!mOutput->isInitialized()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 896cf48a7a..db60df044b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWSound const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); + bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); void updateRegionSound(float duration); From 407349507071f674fbb59e6566a0851c08b0f46b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 04:48:18 -0800 Subject: [PATCH 1437/1812] Add some missing sound handling --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index e00e5eecd1..f984bd96fd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -95,6 +95,7 @@ namespace MWSound mUnderwaterSound.reset(); mActiveSounds.clear(); mActiveSaySounds.clear(); + mUnderwaterSound.reset(); mMusic.reset(); if(mOutput->isInitialized()) { @@ -832,10 +833,18 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - sndname->first->mBaseVolume = volumeFromType(sndname->first->getPlayType()); - sndname->first->update(); + MWBase::SoundPtr sound = sndname->first; + sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->update(); } } + SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); + for(;sayiter != mActiveSaySounds.end();++sayiter) + { + MWBase::SoundPtr sound = sayiter->second.first; + sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->update(); + } if(mMusic) { mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); @@ -952,6 +961,7 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) sayiter->second.first->stop(); mActiveSaySounds.clear(); + mUnderwaterSound.reset(); stopMusic(); } } From 0b2747098c0293fbf09b54b6f785d51bb2566a95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 06:35:01 -0800 Subject: [PATCH 1438/1812] Keep track of unused sound buffers --- apps/openmw/mwsound/sound_output.hpp | 3 - apps/openmw/mwsound/soundmanagerimp.cpp | 94 ++++++++++++------------- apps/openmw/mwsound/soundmanagerimp.hpp | 8 +++ 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 5c437a6996..4c1691ed18 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -15,9 +15,6 @@ namespace MWSound class Sound; class Sound_Loudness; - // An opaque handle for the implementation's sound buffers. - typedef void *Sound_Handle; - class Sound_Output { SoundManager &mManager; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f984bd96fd..7f0a118171 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -92,11 +92,7 @@ namespace MWSound SoundManager::~SoundManager() { - mUnderwaterSound.reset(); - mActiveSounds.clear(); - mActiveSaySounds.clear(); - mUnderwaterSound.reset(); - mMusic.reset(); + clear(); if(mOutput->isInitialized()) { NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); @@ -128,6 +124,9 @@ namespace MWSound const Sound_Buffer *SoundManager::lookup(const std::string &soundId) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); + if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) + return &sfxiter->second; + if(sfxiter == mSoundBuffers.end()) { // TODO: We could process all available ESM::Sound records on init @@ -163,10 +162,10 @@ namespace MWSound soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) )).first; mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); } - else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + + sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + mUnusedBuffers.insert(sfxiter->second.mHandle); return &sfxiter->second; } @@ -420,13 +419,16 @@ namespace MWSound return sound; try { - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) { @@ -444,7 +446,8 @@ namespace MWSound try { // Look up the sound in the ESM data - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -455,10 +458,12 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); else - mActiveSounds[ptr].push_back(std::make_pair(sound, soundId)); + mActiveSounds[ptr].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) { @@ -476,13 +481,16 @@ namespace MWSound try { // Look up the sound in the ESM data - const Sound_Buffer *sfx = lookup(Misc::StringUtils::lowerCase(soundId)); + std::string soundid = Misc::StringUtils::lowerCase(soundId); + const Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundId)); + if(mBufferRefs[sfx->mHandle]++ == 0) + mUnusedBuffers.erase(sfx->mHandle); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception &) { @@ -493,22 +501,7 @@ namespace MWSound void SoundManager::stopSound (MWBase::SoundPtr sound) { - SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) - { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - { - if(sndname->first != sound) - continue; - - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); - return; - } - } + sound->stop(); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) @@ -516,16 +509,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second != soundId) + if(sndname->second != soundid) continue; - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); return; } } @@ -539,7 +529,6 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) sndname->first->stop(); - mActiveSounds.erase(snditer); } } @@ -555,10 +544,8 @@ namespace MWSound SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) sndname->first->stop(); - mActiveSounds.erase(snditer++); } - else - ++snditer; + ++snditer; } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) @@ -568,10 +555,8 @@ namespace MWSound sayiter->first.getCell() == cell) { sayiter->second.first->stop(); - mActiveSaySounds.erase(sayiter++); } - else - ++sayiter; + ++sayiter; } } @@ -580,16 +565,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second != soundId) + if(sndname->second != soundid) continue; - sndname->first->stop(); - snditer->second.erase(sndname); - if(snditer->second.empty()) - mActiveSounds.erase(snditer); return; } } @@ -601,10 +583,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second == soundId) + if(sndname->second == soundid) sndname->first->setFadeout(duration); } } @@ -615,10 +598,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { + std::string soundid = Misc::StringUtils::lowerCase(soundId); SoundNamePairList::const_iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) { - if(sndname->second == soundId && sndname->first->isPlaying()) + if(sndname->second == soundid && sndname->first->isPlaying()) return true; } } @@ -752,7 +736,12 @@ namespace MWSound while(sndname != snditer->second.end()) { if(!updateSound(sndname->first, snditer->first, duration)) + { + NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); + if(mBufferRefs[sfxiter->second.mHandle]-- == 1) + mUnusedBuffers.insert(sfxiter->second.mHandle); sndname = snditer->second.erase(sndname); + } else ++sndname; } @@ -954,7 +943,12 @@ namespace MWSound { SoundNamePairList::iterator sndname = snditer->second.begin(); for(;sndname != snditer->second.end();++sndname) + { sndname->first->stop(); + NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); + if(mBufferRefs[sfxiter->second.mHandle]-- <= 1) + mUnusedBuffers.insert(sfxiter->second.mHandle); + } } mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db60df044b..cb6c930448 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -23,6 +23,9 @@ namespace MWSound class Sound; class Sound_Buffer; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + enum Environment { Env_Normal, Env_Underwater @@ -50,6 +53,11 @@ namespace MWSound // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; + typedef std::map SoundRefMap; + SoundRefMap mBufferRefs; + typedef std::set SoundSet; + SoundSet mUnusedBuffers; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; From 22a681142599f266986b6f89e8f5d0e743fec0f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 06:52:37 -0800 Subject: [PATCH 1439/1812] Limit the sound buffer cache to 15MB --- apps/openmw/mwsound/openal_output.cpp | 11 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 1 + apps/openmw/mwsound/sound_output.hpp | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 5 files changed, 28 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 82d56ffa07..47acb414ec 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -813,6 +813,17 @@ void OpenAL_Output::unloadSound(Sound_Handle data) alDeleteBuffers(1, &buffer); } +size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const +{ + ALuint buffer = GET_PTRID(data); + ALint size = 0; + + alGetBufferi(buffer, AL_SIZE, &size); + throwALerror(); + + return (ALuint)size; +} + MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index b4c788faaa..3186706a30 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -35,6 +35,7 @@ namespace MWSound virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); virtual void unloadSound(Sound_Handle data); + virtual size_t getSoundDataSize(Sound_Handle data) const; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 4c1691ed18..f0b3fc4651 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -25,6 +25,7 @@ namespace MWSound virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; virtual void unloadSound(Sound_Handle data) = 0; + virtual size_t getSoundDataSize(Sound_Handle data) const = 0; /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7f0a118171..b758ef7d6a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -40,6 +40,7 @@ namespace MWSound , mMusicVolume(1.0f) , mVoiceVolume(1.0f) , mFootstepsVolume(1.0f) + , mBufferCacheSize(0) , mListenerUnderwater(false) , mListenerPos(0,0,0) , mListenerDir(1,0,0) @@ -165,6 +166,19 @@ namespace MWSound } sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfxiter->second.mHandle); + // NOTE: Max sound buffer cache size is 15MB. Make configurable? + while(mBufferCacheSize > 15*1024*1024) + { + if(mUnusedBuffers.empty()) + { + std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(*iter); + mUnusedBuffers.erase(iter); + } mUnusedBuffers.insert(sfxiter->second.mHandle); return &sfxiter->second; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index cb6c930448..ff0ff28b41 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,6 +49,7 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; + size_t mBufferCacheSize; // Should stream voices, but that requires handling the "lip" data // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; From 0f33f41d8d4d6a111cc9f646112690bb4f13f722 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 07:50:46 -0800 Subject: [PATCH 1440/1812] Actually unload sounds when running over --- apps/openmw/mwsound/sound_buffer.hpp | 4 ++- apps/openmw/mwsound/sound_output.hpp | 3 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 42 ++++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 9 ++---- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 8ee7ae342c..8818ac23cd 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -22,8 +22,10 @@ namespace MWSound Sound_Handle mHandle; Sound_Loudness mLoudness; + size_t mReferences; + Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mReferences(0) { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index f0b3fc4651..6e1f201104 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -15,6 +15,9 @@ namespace MWSound class Sound; class Sound_Loudness; + // An opaque handle for the implementation's sound buffers. + typedef void *Sound_Handle; + class Sound_Output { SoundManager &mManager; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b758ef7d6a..b63e203955 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -122,7 +122,7 @@ namespace MWSound // Lookup a soundid for its sound data (resource name, local volume, // minRange and maxRange. The returned pointer is only valid temporarily. - const Sound_Buffer *SoundManager::lookup(const std::string &soundId) + Sound_Buffer *SoundManager::lookup(const std::string &soundId) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) @@ -165,8 +165,10 @@ namespace MWSound mVFS->normalizeFilename(sfxiter->second.mResourceName); } - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfxiter->second.mHandle); + Sound_Buffer *sfx = &sfxiter->second; + sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + // NOTE: Max sound buffer cache size is 15MB. Make configurable? while(mBufferCacheSize > 15*1024*1024) { @@ -176,12 +178,14 @@ namespace MWSound break; } SoundSet::iterator iter = mUnusedBuffers.begin(); - mBufferCacheSize -= mOutput->getSoundDataSize(*iter); + sfxiter = mSoundBuffers.find(*iter); + mBufferCacheSize -= mOutput->getSoundDataSize(sfxiter->second.mHandle); + mOutput->unloadSound(sfxiter->second.mHandle); mUnusedBuffers.erase(iter); } - mUnusedBuffers.insert(sfxiter->second.mHandle); + mUnusedBuffers.insert(soundId); - return &sfxiter->second; + return sfx; } const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) @@ -434,14 +438,14 @@ namespace MWSound try { std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception&) @@ -461,7 +465,7 @@ namespace MWSound { // Look up the sound in the ESM data std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -472,8 +476,8 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); if((mode&Play_NoTrack)) mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); else @@ -496,14 +500,14 @@ namespace MWSound { // Look up the sound in the ESM data std::string soundid = Misc::StringUtils::lowerCase(soundId); - const Sound_Buffer *sfx = lookup(soundid); + Sound_Buffer *sfx = lookup(soundid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(mBufferRefs[sfx->mHandle]++ == 0) - mUnusedBuffers.erase(sfx->mHandle); + if(sfx->mReferences++ == 0) + mUnusedBuffers.erase(soundid); mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); } catch(std::exception &) @@ -752,8 +756,8 @@ namespace MWSound if(!updateSound(sndname->first, snditer->first, duration)) { NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(mBufferRefs[sfxiter->second.mHandle]-- == 1) - mUnusedBuffers.insert(sfxiter->second.mHandle); + if(sfxiter->second.mReferences-- == 1) + mUnusedBuffers.insert(sndname->second); sndname = snditer->second.erase(sndname); } else @@ -960,8 +964,8 @@ namespace MWSound { sndname->first->stop(); NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(mBufferRefs[sfxiter->second.mHandle]-- <= 1) - mUnusedBuffers.insert(sfxiter->second.mHandle); + if(sfxiter->second.mReferences-- == 1) + mUnusedBuffers.insert(sndname->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index ff0ff28b41..db5ced5c30 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -23,9 +23,6 @@ namespace MWSound class Sound; class Sound_Buffer; - // An opaque handle for the implementation's sound buffers. - typedef void *Sound_Handle; - enum Environment { Env_Normal, Env_Underwater @@ -54,9 +51,7 @@ namespace MWSound // separately from buffer loading. NameBufferMap mVoiceSoundBuffers; - typedef std::map SoundRefMap; - SoundRefMap mBufferRefs; - typedef std::set SoundSet; + typedef std::set SoundSet; SoundSet mUnusedBuffers; boost::shared_ptr mMusic; @@ -79,7 +74,7 @@ namespace MWSound int mPausedSoundTypes; - const Sound_Buffer *lookup(const std::string &soundId); + Sound_Buffer *lookup(const std::string &soundId); const Sound_Buffer *lookupVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); From 16f72886e93c9b5233d4d9ae025a5ce15265c376 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 07:51:52 -0800 Subject: [PATCH 1441/1812] Use separate lists for openal sounds and streams --- apps/openmw/mwsound/openal_output.cpp | 65 +++++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 7 ++- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 47acb414ec..0d8a994aef 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -296,7 +296,7 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mBufferSize = static_cast(sBufferLength*srate); mBufferSize = framesToBytes(mBufferSize, chans, type); - mOutput.mActiveSounds.push_back(this); + mOutput.mActiveStreams.push_back(this); } catch(std::exception&) { @@ -318,8 +318,8 @@ OpenAL_SoundStream::~OpenAL_SoundStream() mDecoder->close(); - mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), - mOutput.mActiveSounds.end(), this)); + mOutput.mActiveStreams.erase(std::find(mOutput.mActiveStreams.begin(), + mOutput.mActiveStreams.end(), this)); } void OpenAL_SoundStream::play() @@ -802,12 +802,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && sound->mBuffer == buffer) + if((*iter)->mSource && (*iter)->mBuffer == buffer) { - alSourceStop(sound->mSource); - alSourcei(sound->mSource, AL_BUFFER, 0); - sound->mBuffer = 0; + alSourceStop((*iter)->mSource); + alSourcei((*iter)->mSource, AL_BUFFER, 0); + (*iter)->mBuffer = 0; } } alDeleteBuffers(1, &buffer); @@ -947,22 +946,17 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - SoundVec::const_iterator iter = mActiveSounds.begin(); - while(iter != mActiveSounds.end()) + SoundVec::const_iterator sound = mActiveSounds.begin(); + for(;sound != mActiveSounds.end();++sound) { - const OpenAL_SoundStream *stream = dynamic_cast(*iter); - if(stream) - { - if(stream->mSource && (stream->getPlayType()&types)) - sources.push_back(stream->mSource); - } - else - { - const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && (sound->getPlayType()&types)) - sources.push_back(sound->mSource); - } - ++iter; + if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) + sources.push_back((*sound)->mSource); + } + StreamVec::const_iterator stream = mActiveStreams.begin(); + for(;stream != mActiveStreams.end();++stream) + { + if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) + sources.push_back((*stream)->mSource); } if(!sources.empty()) { @@ -974,22 +968,17 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - SoundVec::const_iterator iter = mActiveSounds.begin(); - while(iter != mActiveSounds.end()) + SoundVec::const_iterator sound = mActiveSounds.begin(); + for(;sound != mActiveSounds.end();++sound) { - const OpenAL_SoundStream *stream = dynamic_cast(*iter); - if(stream) - { - if(stream->mSource && (stream->getPlayType()&types)) - sources.push_back(stream->mSource); - } - else - { - const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource && (sound->getPlayType()&types)) - sources.push_back(sound->mSource); - } - ++iter; + if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) + sources.push_back((*sound)->mSource); + } + StreamVec::const_iterator stream = mActiveStreams.begin(); + for(;stream != mActiveStreams.end();++stream) + { + if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) + sources.push_back((*stream)->mSource); } if(!sources.empty()) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 3186706a30..9a9d188d90 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,6 +16,9 @@ namespace MWSound class SoundManager; class Sound; + class OpenAL_Sound; + class OpenAL_SoundStream; + class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -24,8 +27,10 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; + typedef std::vector StreamVec; + StreamVec mActiveStreams; Environment mLastEnvironment; From 83721092f2c6c11243587a54833ee35cd97dc235 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:10:49 -0800 Subject: [PATCH 1442/1812] Refactor the audio streaming code to be a bit saner --- apps/openmw/mwsound/openal_output.cpp | 164 ++++++++++++-------------- 1 file changed, 78 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0d8a994aef..bee58bbe81 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -150,18 +150,6 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } -static ALint getBufferSampleCount(ALuint buf) -{ - ALint size, bits, channels; - - alGetBufferi(buf, AL_SIZE, &size); - alGetBufferi(buf, AL_BITS, &bits); - alGetBufferi(buf, AL_CHANNELS, &channels); - throwALerror(); - - return size / channels * 8 / bits; -} - // // A streaming OpenAL sound. // @@ -174,17 +162,17 @@ class OpenAL_SoundStream : public Sound ALuint mSource; ALuint mBuffers[sNumBuffers]; + ALint mCurrentBufIdx; ALenum mFormat; ALsizei mSampleRate; ALuint mBufferSize; - - ALuint mSamplesQueued; + ALuint mFrameSize; + ALint mSilence; DecoderPtr mDecoder; volatile bool mIsFinished; - volatile bool mIsInitialBatchEnqueued; void updateAll(bool local); @@ -204,6 +192,7 @@ public: void play(); bool process(); + ALint refillQueue(); }; const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; @@ -277,7 +266,8 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) - , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) + , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) + , mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -293,8 +283,16 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mFormat = getALFormat(chans, type); mSampleRate = srate; + switch(type) + { + case SampleType_UInt8: mSilence = 0x80; + case SampleType_Int16: mSilence = 0x00; + case SampleType_Float32: mSilence = 0x00; + } + + mFrameSize = framesToBytes(1, chans, type); mBufferSize = static_cast(sBufferLength*srate); - mBufferSize = framesToBytes(mBufferSize, chans, type); + mBufferSize *= mFrameSize; mOutput.mActiveStreams.push_back(this); } @@ -327,9 +325,8 @@ void OpenAL_SoundStream::play() alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); - mSamplesQueued = 0; + mIsFinished = false; - mIsInitialBatchEnqueued = false; mOutput.mStreamThread->add(this); } @@ -337,12 +334,10 @@ void OpenAL_SoundStream::stop() { mOutput.mStreamThread->remove(this); mIsFinished = true; - mIsInitialBatchEnqueued = false; alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); - mSamplesQueued = 0; mDecoder->rewind(); } @@ -351,6 +346,7 @@ bool OpenAL_SoundStream::isPlaying() { ALint state; + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -362,17 +358,26 @@ bool OpenAL_SoundStream::isPlaying() double OpenAL_SoundStream::getTimeOffset() { ALint state = AL_STOPPED; - ALfloat offset = 0.0f; + ALint offset; double t; - mOutput.mStreamThread->mMutex.lock(); - alGetSourcef(mSource, AL_SEC_OFFSET, &offset); + boost::unique_lock lock(mOutput.mStreamThread->mMutex); + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) - t = (double)(mDecoder->getSampleOffset() - mSamplesQueued)/(double)mSampleRate + offset; + { + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + ALint inqueue = mBufferSize/mFrameSize*queued + offset; + t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; + } else + { + /* Underrun, or not started yet. The decoder offset is where we'll play + * next. */ t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; - mOutput.mStreamThread->mMutex.unlock(); + } + lock.unlock(); throwALerror(); return t; @@ -418,78 +423,65 @@ void OpenAL_SoundStream::update() bool OpenAL_SoundStream::process() { try { - bool finished = mIsFinished; - ALint processed, state; - - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); - throwALerror(); - - if(processed > 0) + if(refillQueue() > 0) { - std::vector data(mBufferSize); - do { - ALuint bufid = 0; - size_t got; - - alSourceUnqueueBuffers(mSource, 1, &bufid); - mSamplesQueued -= getBufferSampleCount(bufid); - processed--; - - if(finished) - continue; - - got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - mSamplesQueued += getBufferSampleCount(bufid); - } - } while(processed > 0); - throwALerror(); - } - else if (!mIsInitialBatchEnqueued) { // nothing enqueued yet - std::vector data(mBufferSize); - - for(ALuint i = 0;i < sNumBuffers && !finished;i++) + ALint state; + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state != AL_PLAYING && state != AL_PAUSED) { - size_t got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - ALuint bufid = mBuffers[i]; - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - throwALerror(); - mSamplesQueued += getBufferSampleCount(bufid); - } + if(refillQueue() > 0) + alSourcePlay(mSource); + throwALerror(); } - mIsInitialBatchEnqueued = true; } - - if(state != AL_PLAYING && state != AL_PAUSED) - { - ALint queued = 0; - - alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - if(queued > 0) - alSourcePlay(mSource); - throwALerror(); - } - - mIsFinished = finished; } catch(std::exception&) { std::cout<< "Error updating stream \""<getName()<<"\"" < 0) + { + ALuint buf; + alSourceUnqueueBuffers(mSource, 1, &buf); + --processed; + } + throwALerror(); + + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + if(!mIsFinished && (ALuint)queued < sNumBuffers) + { + std::vector data(mBufferSize); + for(;!mIsFinished && (ALuint)queued < sNumBuffers;++queued) + { + size_t got = mDecoder->read(&data[0], data.size()); + if(got < data.size()) + { + mIsFinished = true; + memset(&data[got], mSilence, data.size()-got); + } + if(got > 0) + { + ALuint bufid = mBuffers[mCurrentBufIdx]; + alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + throwALerror(); + mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; + } + } + } + + return queued; +} + + // // A regular 2D OpenAL sound // From f1a1dc8408f4bbf6538c7965637cd800754110c3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:27:35 -0800 Subject: [PATCH 1443/1812] Pass relevant sound parameters to the OpenAL_SoundStream constructor --- apps/openmw/mwsound/openal_output.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bee58bbe81..1a33d1cb05 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -182,7 +182,7 @@ class OpenAL_SoundStream : public Sound friend class OpenAL_Output; public: - OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags); + OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_SoundStream(); virtual void stop(); @@ -264,8 +264,8 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) - : Sound(osg::Vec3f(0.f, 0.f, 0.f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) +OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) , mDecoder(decoder), mIsFinished(true) { @@ -888,7 +888,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } -MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { boost::shared_ptr sound; ALuint src; @@ -902,7 +902,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new OpenAL_SoundStream(*this, src, decoder, volume, pitch, flags)); + sound.reset(new OpenAL_SoundStream(*this, src, decoder, osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { From eee6a19e312b6cb50b765358212d7dfcb80f4a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 19:41:57 -0800 Subject: [PATCH 1444/1812] Add a method to stream sounds in 3D --- apps/openmw/mwsound/openal_output.cpp | 67 ++++++++++++++++++++++++++- apps/openmw/mwsound/openal_output.hpp | 5 +- apps/openmw/mwsound/sound_output.hpp | 4 +- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1a33d1cb05..0c0f634755 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -158,9 +158,12 @@ class OpenAL_SoundStream : public Sound static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; +protected: OpenAL_Output &mOutput; ALuint mSource; + +private: ALuint mBuffers[sNumBuffers]; ALint mCurrentBufIdx; @@ -194,9 +197,22 @@ public: bool process(); ALint refillQueue(); }; - const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; +class OpenAL_SoundStream3D : public OpenAL_SoundStream +{ + OpenAL_SoundStream3D(const OpenAL_SoundStream3D &rhs); + OpenAL_SoundStream3D& operator=(const OpenAL_SoundStream3D &rhs); + +public: + OpenAL_SoundStream3D(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) + { } + + virtual void update(); +}; + + // // A background streaming thread (keeps active streams processed) // @@ -481,6 +497,26 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } +void OpenAL_SoundStream3D::update() +{ + ALfloat gain = mVolume*mBaseVolume; + ALfloat pitch = mPitch; + if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) + gain = 0.0f; + else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(mSource, AL_GAIN, gain); + alSourcef(mSource, AL_PITCH, pitch); + alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); + alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); +} + // // A regular 2D OpenAL sound @@ -917,6 +953,35 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f } +MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags) +{ + boost::shared_ptr sound; + ALuint src; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.front(); + mFreeSources.pop_front(); + + if((flags&MWBase::SoundManager::Play_Loop)) + std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; + try + { + sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags)); + } + catch(std::exception&) + { + mFreeSources.push_back(src); + throw; + } + + sound->updateAll(true); + + sound->play(); + return sound; +} + + void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 9a9d188d90..e6f438ad83 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -47,7 +47,9 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); + virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags); virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); @@ -66,6 +68,7 @@ namespace MWSound friend class OpenAL_Sound; friend class OpenAL_Sound3D; friend class OpenAL_SoundStream; + friend class OpenAL_SoundStream3D; friend class SoundManager; }; #ifndef DEFAULT_OUTPUT diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 6e1f201104..2326c64ba4 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -35,7 +35,9 @@ namespace MWSound /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; + virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags) = 0; virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; From fbfcc4050f059e21cc737b008bef2702137afe3d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 20:13:24 -0800 Subject: [PATCH 1445/1812] Stream voice clips Voices tend to be a bit long, and not individually replayed often. So it's better to stream them instead of loading theminto a sound buffer. The loudness data is very small, though, so that can be kept buffered indefinitely. --- apps/openmw/mwsound/openal_output.cpp | 13 +-- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound_buffer.hpp | 1 - apps/openmw/mwsound/sound_output.hpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 102 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 10 ++- 6 files changed, 71 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0c0f634755..ccdbff3afb 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,14 +19,10 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif + #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace -{ - const int loudnessFPS = 20; // loudness values per second of audio -} - namespace MWSound { @@ -779,7 +775,7 @@ void OpenAL_Output::deinit() } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness *loudness) +Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { throwALerror(); @@ -806,9 +802,6 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname, Sound_Loudness * decoder->readAll(data); decoder->close(); - if(loudness != 0) - loudness->analyzeLoudness(data, srate, chans, type, static_cast(loudnessFPS)); - ALuint buf = 0; try { alGenBuffers(1, &buf); @@ -975,7 +968,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec throw; } - sound->updateAll(true); + sound->updateAll(false); sound->play(); return sound; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index e6f438ad83..912bebb569 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -38,7 +38,7 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness); + virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index 8818ac23cd..eb67908a2b 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -20,7 +20,6 @@ namespace MWSound float mMinDist, mMaxDist; Sound_Handle mHandle; - Sound_Loudness mLoudness; size_t mReferences; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2326c64ba4..86be94d335 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -26,7 +26,7 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual Sound_Handle loadSound(const std::string &fname, Sound_Loudness *loudness=0) = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b63e203955..bafd3aa1ed 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -30,6 +30,11 @@ #endif +namespace +{ + const int sLoudnessFPS = 20; // loudness values per second of audio +} + namespace MWSound { SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) @@ -103,13 +108,6 @@ namespace MWSound mOutput->unloadSound(sfxiter->second.mHandle); sfxiter->second.mHandle = 0; } - sfxiter = mVoiceSoundBuffers.begin(); - for(;sfxiter != mVoiceSoundBuffers.end();++sfxiter) - { - if(sfxiter->second.mHandle) - mOutput->unloadSound(sfxiter->second.mHandle); - sfxiter->second.mHandle = 0; - } } mOutput.reset(); } @@ -188,32 +186,37 @@ namespace MWSound return sfx; } - const Sound_Buffer *SoundManager::lookupVoice(const std::string &voicefile) + void SoundManager::loadVoice(const std::string &voicefile) { - NameBufferMap::iterator sfxiter = mVoiceSoundBuffers.find(voicefile); - if(sfxiter == mVoiceSoundBuffers.end()) + NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); + if(lipiter != mVoiceLipBuffers.end()) return; + + DecoderPtr decoder = getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(voicefile)) + decoder->open(voicefile); + else { - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); - - float minDistance = fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult; - float maxDistance = fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult; - minDistance = std::max(minDistance, 1.f); - maxDistance = std::max(minDistance, maxDistance); - - sfxiter = mVoiceSoundBuffers.insert(std::make_pair( - voicefile, Sound_Buffer("sound/"+voicefile, 1.0f, minDistance, maxDistance) - )).first; - mVFS->normalizeFilename(sfxiter->second.mResourceName); - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); + std::string file = voicefile; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); } - else if(!sfxiter->second.mHandle) - sfxiter->second.mHandle = mOutput->loadSound(sfxiter->second.mResourceName, &sfxiter->second.mLoudness); - return &sfxiter->second; + ChannelConfig chans; + SampleType type; + int srate; + decoder->getInfo(&srate, &chans, &type); + + std::vector data; + decoder->readAll(data); + decoder->close(); + + Sound_Loudness loudness; + loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); + + mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); } @@ -336,14 +339,25 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); + static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundPtr sound = mOutput->playSound3D(sfx->mHandle, - objpos, sfx->mVolume, basevol, 1.0f, sfx->mMinDist, sfx->mMaxDist, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice ); mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); } @@ -358,12 +372,13 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - NameBufferMap::const_iterator sfxiter = mVoiceSoundBuffers.find(snditer->second.second); - if(sfxiter != mVoiceSoundBuffers.end()) + MWBase::SoundPtr sound = snditer->second.first; + NameLoudnessMap::const_iterator lipiter = mVoiceLipBuffers.find(snditer->second.second); + if(lipiter != mVoiceLipBuffers.end()) { - float sec = snditer->second.first->getTimeOffset(); - if(snditer->second.first->isPlaying()) - return sfxiter->second.mLoudness.getLoudnessAtTime(sec); + float sec = sound->getTimeOffset(); + if(sound->isPlaying()) + return lipiter->second.getLoudnessAtTime(sec); } } @@ -376,12 +391,15 @@ namespace MWSound return; try { - std::string voicefile = Misc::StringUtils::lowerCase(filename); - const Sound_Buffer *sfx = lookupVoice(voicefile); + std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); - MWBase::SoundPtr sound = mOutput->playSound(sfx->mHandle, - sfx->mVolume, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0 + loadVoice(voicefile); + DecoderPtr decoder = getDecoder(); + decoder->open(voicefile); + + MWBase::SoundPtr sound = mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice ); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db5ced5c30..00c0af7b2b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -9,6 +9,7 @@ #include +#include "loudness.hpp" #include "../mwbase/soundmanager.hpp" namespace VFS @@ -47,9 +48,9 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mSoundBuffers; size_t mBufferCacheSize; - // Should stream voices, but that requires handling the "lip" data - // separately from buffer loading. - NameBufferMap mVoiceSoundBuffers; + + typedef std::map NameLoudnessMap; + NameLoudnessMap mVoiceLipBuffers; typedef std::set SoundSet; SoundSet mUnusedBuffers; @@ -75,7 +76,8 @@ namespace MWSound int mPausedSoundTypes; Sound_Buffer *lookup(const std::string &soundId); - const Sound_Buffer *lookupVoice(const std::string &voicefile); + // Ensure the loudness/"lip" data is loaded + void loadVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 6c3953766e97a5d8be561d76cb119c05b668a791 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 00:03:54 -0800 Subject: [PATCH 1446/1812] Use separate lists for the sound name and its buffer This should make sound lookup a bit more efficient, especially when an integer ID can be used. --- apps/openmw/mwsound/soundmanagerimp.cpp | 90 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 9 ++- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bafd3aa1ed..d74b0bc6d3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -101,12 +101,12 @@ namespace MWSound clear(); if(mOutput->isInitialized()) { - NameBufferMap::iterator sfxiter = mSoundBuffers.begin(); + SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if(sfxiter->second.mHandle) - mOutput->unloadSound(sfxiter->second.mHandle); - sfxiter->second.mHandle = 0; + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } } mOutput.reset(); @@ -122,11 +122,11 @@ namespace MWSound // minRange and maxRange. The returned pointer is only valid temporarily. Sound_Buffer *SoundManager::lookup(const std::string &soundId) { - NameBufferMap::iterator sfxiter = mSoundBuffers.find(soundId); - if(sfxiter != mSoundBuffers.end() && sfxiter->second.mHandle) - return &sfxiter->second; - - if(sfxiter == mSoundBuffers.end()) + Sound_Buffer *sfx; + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + else { // TODO: We could process all available ESM::Sound records on init // to pre-fill a non-resizing list, which would allow subsystems to @@ -157,31 +157,45 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - sfxiter = mSoundBuffers.insert(std::make_pair( - soundId, Sound_Buffer("Sound/"+snd->mSound, volume, min, max) - )).first; - mVFS->normalizeFilename(sfxiter->second.mResourceName); - } - - Sound_Buffer *sfx = &sfxiter->second; - sfx->mHandle = mOutput->loadSound(sfx->mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); - - // NOTE: Max sound buffer cache size is 15MB. Make configurable? - while(mBufferCacheSize > 15*1024*1024) - { - if(mUnusedBuffers.empty()) - { - std::cerr<< "No unused sound buffers to free, using "<mSound, volume, min, max) + ); + sfx = &mSoundBuffers[id]; } - SoundSet::iterator iter = mUnusedBuffers.begin(); - sfxiter = mSoundBuffers.find(*iter); - mBufferCacheSize -= mOutput->getSoundDataSize(sfxiter->second.mHandle); - mOutput->unloadSound(sfxiter->second.mHandle); - mUnusedBuffers.erase(iter); + catch(...) { + mBufferKeys.erase(bufkey); + throw; + } + + mVFS->normalizeFilename(sfx->mResourceName); + } + + if(!sfx->mHandle) + { + sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + + // NOTE: Max sound buffer cache size is 15MB. Make configurable? + while(mBufferCacheSize > 15*1024*1024) + { + if(mUnusedBuffers.empty()) + { + std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); + mOutput->unloadSound(unused->mHandle); + mUnusedBuffers.erase(iter); + } + mUnusedBuffers.insert(soundId); } - mUnusedBuffers.insert(soundId); return sfx; } @@ -773,8 +787,10 @@ namespace MWSound { if(!updateSound(sndname->first, snditer->first, duration)) { - NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(sfxiter->second.mReferences-- == 1) + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), + sndname->second); + Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(sfx->mReferences-- == 1) mUnusedBuffers.insert(sndname->second); sndname = snditer->second.erase(sndname); } @@ -981,8 +997,10 @@ namespace MWSound for(;sndname != snditer->second.end();++sndname) { sndname->first->stop(); - NameBufferMap::iterator sfxiter = mSoundBuffers.find(sndname->second); - if(sfxiter->second.mReferences-- == 1) + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), + sndname->second); + Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(sfx->mReferences-- == 1) mUnusedBuffers.insert(sndname->second); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 00c0af7b2b..082e046780 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -45,8 +45,13 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::map NameBufferMap; - NameBufferMap mSoundBuffers; + typedef std::vector BufferKeyList; + typedef std::vector SoundBufferList; + // Each mBufferKeys index has a corresponding entry in mSoundBuffers. + // That is, if string "foo" is at index 10 in mBufferKeys, index 10 in + // mSoundBuffers contains the Sound_Buffer for "foo". + BufferKeyList mBufferKeys; + SoundBufferList mSoundBuffers; size_t mBufferCacheSize; typedef std::map NameLoudnessMap; From f9e18cd966bf7431b186a80e4d558350cd31a7f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 01:40:14 -0800 Subject: [PATCH 1447/1812] Prepare all Sound_Buffer objects when one is needed This simply sets up the Sound record data to be used by the sound output. The actual audio buffers, stored in the Sound_Handle, are still loaded on-demand. --- apps/openmw/mwsound/soundmanagerimp.cpp | 112 ++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 7 ++ 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d74b0bc6d3..2c33cb2b75 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -118,62 +118,84 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } + void SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) + { + BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + { + std::cerr<< "Duplicate sound record \""<getStore().get().find("fAudioDefaultMinDistance")->getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + float volume, min, max; + + volume = static_cast(pow(10.0, (sound->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); + if(sound->mData.mMinRange == 0 && sound->mData.mMaxRange == 0) + { + min = fAudioDefaultMinDistance; + max = fAudioDefaultMaxDistance; + } + else + { + min = sound->mData.mMinRange; + max = sound->mData.mMaxRange; + } + + min *= fAudioMinDistanceMult; + max *= fAudioMaxDistanceMult; + min = std::max(min, 1.0f); + max = std::max(min, max); + + Sound_Buffer *sfx; + bufkey = mBufferKeys.insert(bufkey, soundId); + try { + BufferKeyList::difference_type id; + id = std::distance(mBufferKeys.begin(), bufkey); + mSoundBuffers.insert(mSoundBuffers.begin()+id, + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + ); + sfx = &mSoundBuffers[id]; + } + catch(...) { + mBufferKeys.erase(bufkey); + throw; + } + + mVFS->normalizeFilename(sfx->mResourceName); + } + // Lookup a soundid for its sound data (resource name, local volume, - // minRange and maxRange. The returned pointer is only valid temporarily. + // minRange and maxRange). Sound_Buffer *SoundManager::lookup(const std::string &soundId) { Sound_Buffer *sfx; BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; - else + if(bufkey == mBufferKeys.end() || *bufkey != soundId) { - // TODO: We could process all available ESM::Sound records on init - // to pre-fill a non-resizing list, which would allow subsystems to - // reference sounds by index instead of string. - MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Sound *snd = world->getStore().get().find(soundId); - - float volume, min, max; - volume = static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); - - if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) + if(mBufferKeys.empty()) { - static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); - static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); - min = fAudioDefaultMinDistance; - max = fAudioDefaultMaxDistance; - } - else - { - min = snd->mData.mMinRange; - max = snd->mData.mMaxRange; - } + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Store::iterator iter = world->getStore().get().begin(); + MWWorld::Store::iterator end = world->getStore().get().end(); + size_t storesize = world->getStore().get().getSize(); + mBufferKeys.reserve(storesize); + mSoundBuffers.reserve(storesize); + for(;iter != end;++iter) + insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - min *= fAudioMinDistanceMult; - max *= fAudioMaxDistanceMult; - min = std::max(min, 1.0f); - max = std::max(min, max); - - bufkey = mBufferKeys.insert(bufkey, soundId); - try { - BufferKeyList::difference_type id; - id = std::distance(mBufferKeys.begin(), bufkey); - mSoundBuffers.insert(mSoundBuffers.begin()+id, - Sound_Buffer("Sound/"+snd->mSound, volume, min, max) - ); - sfx = &mSoundBuffers[id]; + bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); } - catch(...) { - mBufferKeys.erase(bufkey); - throw; - } - - mVFS->normalizeFilename(sfx->mResourceName); + if(bufkey == mBufferKeys.end() || *bufkey != soundId) + throw std::runtime_error("Sound "+soundId+" not found"); } + sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + if(!sfx->mHandle) { sfx->mHandle = mOutput->loadSound(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 082e046780..5e8d0d8f89 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -17,6 +17,11 @@ namespace VFS class Manager; } +namespace ESM +{ + struct Sound; +} + namespace MWSound { class Sound_Output; @@ -80,6 +85,8 @@ namespace MWSound int mPausedSoundTypes; + void insertSound(const std::string &soundId, const ESM::Sound *sound); + Sound_Buffer *lookup(const std::string &soundId); // Ensure the loudness/"lip" data is loaded void loadVoice(const std::string &voicefile); From f7218f5a2586efcfc8a1bc3b7dff89a6bb881d90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 02:57:43 -0800 Subject: [PATCH 1448/1812] Use proper mutex mechanisms and don't check al errors in the stream thread --- apps/openmw/mwsound/openal_output.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index ccdbff3afb..e3d3ca8dab 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -232,7 +232,7 @@ struct OpenAL_Output::StreamThread { { while(1) { - mMutex.lock(); + boost::unique_lock lock(mMutex); StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) { @@ -241,33 +241,29 @@ struct OpenAL_Output::StreamThread { else ++iter; } - mMutex.unlock(); + lock.unlock(); boost::this_thread::sleep(boost::posix_time::milliseconds(50)); } } void add(OpenAL_SoundStream *stream) { - mMutex.lock(); + boost::lock_guard lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) mStreams.push_back(stream); - mMutex.unlock(); } void remove(OpenAL_SoundStream *stream) { - mMutex.lock(); + boost::lock_guard lock(mMutex); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); - if(iter != mStreams.end()) - mStreams.erase(iter); - mMutex.unlock(); + if(iter != mStreams.end()) mStreams.erase(iter); } void removeAll() { - mMutex.lock(); + boost::lock_guard lock(mMutex); mStreams.clear(); - mMutex.unlock(); } private: @@ -373,7 +369,7 @@ double OpenAL_SoundStream::getTimeOffset() ALint offset; double t; - boost::unique_lock lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) @@ -389,7 +385,6 @@ double OpenAL_SoundStream::getTimeOffset() * next. */ t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - lock.unlock(); throwALerror(); return t; @@ -443,7 +438,6 @@ bool OpenAL_SoundStream::process() { if(refillQueue() > 0) alSourcePlay(mSource); - throwALerror(); } } } @@ -464,7 +458,6 @@ ALint OpenAL_SoundStream::refillQueue() alSourceUnqueueBuffers(mSource, 1, &buf); --processed; } - throwALerror(); ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); @@ -484,7 +477,6 @@ ALint OpenAL_SoundStream::refillQueue() ALuint bufid = mBuffers[mCurrentBufIdx]; alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); - throwALerror(); mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; } } From 24f8c78fcaf4b470f6e9c6ca158f765a3938cb88 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 03:18:23 -0800 Subject: [PATCH 1449/1812] Store sound buffer references by index instead of string --- apps/openmw/mwsound/soundmanagerimp.cpp | 181 +++++++++++++----------- apps/openmw/mwsound/soundmanagerimp.hpp | 13 +- 2 files changed, 106 insertions(+), 88 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2c33cb2b75..bb767cf418 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -169,32 +169,45 @@ namespace MWSound mVFS->normalizeFilename(sfx->mResourceName); } - // Lookup a soundid for its sound data (resource name, local volume, - // minRange and maxRange). - Sound_Buffer *SoundManager::lookup(const std::string &soundId) + size_t SoundManager::lookupId(const std::string &soundId) { - Sound_Buffer *sfx; BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey == mBufferKeys.end() || *bufkey != soundId) - { - if(mBufferKeys.empty()) - { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Store::iterator iter = world->getStore().get().begin(); - MWWorld::Store::iterator end = world->getStore().get().end(); - size_t storesize = world->getStore().get().getSize(); - mBufferKeys.reserve(storesize); - mSoundBuffers.reserve(storesize); - for(;iter != end;++iter) - insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - } - if(bufkey == mBufferKeys.end() || *bufkey != soundId) - throw std::runtime_error("Sound "+soundId+" not found"); + if(mBufferKeys.empty()) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Store::iterator iter = world->getStore().get().begin(); + MWWorld::Store::iterator end = world->getStore().get().end(); + size_t storesize = world->getStore().get().getSize(); + mBufferKeys.reserve(storesize); + mSoundBuffers.reserve(storesize); + for(;iter != end;++iter) + insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); + + bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); } - sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + throw std::runtime_error("Sound "+soundId+" not found"); + } + + size_t SoundManager::lookupId(const std::string& soundId) const + { + BufferKeyList::const_iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); + if(bufkey != mBufferKeys.end() && *bufkey == soundId) + return std::distance(mBufferKeys.begin(), bufkey); + + throw std::runtime_error("Sound "+soundId+" not found"); + } + + // Lookup a sfxid for its sound data (resource name, local volume, + // minRange, and maxRange). + Sound_Buffer *SoundManager::lookup(size_t sfxid) + { + Sound_Buffer *sfx = &mSoundBuffers[sfxid]; if(!sfx->mHandle) { @@ -210,18 +223,24 @@ namespace MWSound break; } SoundSet::iterator iter = mUnusedBuffers.begin(); - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), *iter); - Sound_Buffer *unused = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + Sound_Buffer *unused = &mSoundBuffers[*iter]; mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); mUnusedBuffers.erase(iter); } - mUnusedBuffers.insert(soundId); + mUnusedBuffers.insert(sfxid); } return sfx; } + // Lookup a soundid for its sound data (resource name, local volume, + // minRange, and maxRange). + Sound_Buffer *SoundManager::lookup(const std::string &soundId) + { + return lookup(lookupId(soundId)); + } + void SoundManager::loadVoice(const std::string &voicefile) { NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); @@ -491,16 +510,16 @@ namespace MWSound return sound; try { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mUnusedBuffers.erase(sfxid); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -518,8 +537,8 @@ namespace MWSound try { // Look up the sound in the ESM data - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -531,11 +550,11 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); + mUnusedBuffers.erase(sfxid); if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); else - mActiveSounds[ptr].push_back(std::make_pair(sound, soundid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -553,16 +572,16 @@ namespace MWSound try { // Look up the sound in the ESM data - std::string soundid = Misc::StringUtils::lowerCase(soundId); - Sound_Buffer *sfx = lookup(soundid); + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + Sound_Buffer *sfx = lookup(sfxid); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(soundid); - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, soundid)); + mUnusedBuffers.erase(sfxid); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception &) { @@ -581,13 +600,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second != soundid) + if(sndidx->second != sfxid) continue; - sndname->first->stop(); + sndidx->first->stop(); return; } } @@ -598,9 +617,9 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - sndname->first->stop(); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) + sndidx->first->stop(); } } @@ -613,9 +632,9 @@ namespace MWSound snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) - sndname->first->stop(); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) + sndidx->first->stop(); } ++snditer; } @@ -637,14 +656,12 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second != soundid) - continue; - sndname->first->stop(); - return; + if(sndidx->second == sfxid) + sndidx->first->stop(); } } } @@ -655,12 +672,12 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second == soundid) - sndname->first->setFadeout(duration); + if(sndidx->second == sfxid) + sndidx->first->setFadeout(duration); } } } @@ -670,11 +687,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - std::string soundid = Misc::StringUtils::lowerCase(soundId); - SoundNamePairList::const_iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); + SoundIndexPairList::const_iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - if(sndname->second == soundid && sndname->first->isPlaying()) + if(sndidx->second == sfxid && sndidx->first->isPlaying()) return true; } } @@ -804,20 +821,18 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - while(sndname != snditer->second.end()) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + while(sndidx != snditer->second.end()) { - if(!updateSound(sndname->first, snditer->first, duration)) + if(!updateSound(sndidx->first, snditer->first, duration)) { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), - sndname->second); - Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndname->second); - sndname = snditer->second.erase(sndname); + mUnusedBuffers.insert(sndidx->second); + sndidx = snditer->second.erase(sndidx); } else - ++sndname; + ++sndidx; } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -893,10 +908,10 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - MWBase::SoundPtr sound = sndname->first; + MWBase::SoundPtr sound = sndidx->first; sound->mBaseVolume = volumeFromType(sound->getPlayType()); sound->update(); } @@ -932,7 +947,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundNamePairList sndlist = snditer->second; + SoundIndexPairList sndlist = snditer->second; mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } @@ -1015,15 +1030,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundNamePairList::iterator sndname = snditer->second.begin(); - for(;sndname != snditer->second.end();++sndname) + SoundIndexPairList::iterator sndidx = snditer->second.begin(); + for(;sndidx != snditer->second.end();++sndidx) { - sndname->first->stop(); - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), - sndname->second); - Sound_Buffer *sfx = &mSoundBuffers[std::distance(mBufferKeys.begin(), bufkey)]; + sndidx->first->stop(); + Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndname->second); + mUnusedBuffers.insert(sndidx->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5e8d0d8f89..25ba9ce05d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -62,17 +62,18 @@ namespace MWSound typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; - typedef std::set SoundSet; + typedef std::set SoundSet; SoundSet mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair SoundNamePair; - typedef std::vector SoundNamePairList; - typedef std::map SoundMap; + typedef std::pair SoundIndexPair; + typedef std::vector SoundIndexPairList; + typedef std::map SoundMap; SoundMap mActiveSounds; + typedef std::pair SoundNamePair; typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; @@ -87,7 +88,11 @@ namespace MWSound void insertSound(const std::string &soundId, const ESM::Sound *sound); + size_t lookupId(const std::string &soundId); + size_t lookupId(const std::string &soundId) const; + Sound_Buffer *lookup(size_t sfxid); Sound_Buffer *lookup(const std::string &soundId); + // Ensure the loudness/"lip" data is loaded void loadVoice(const std::string &voicefile); From 3ce6aee98babc135b95c77b749f509549855e81f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:00:17 -0800 Subject: [PATCH 1450/1812] Return a decoder from the loadVoice function --- apps/openmw/mwsound/soundmanagerimp.cpp | 31 ++++++++++++++++++------- apps/openmw/mwsound/soundmanagerimp.hpp | 5 ++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bb767cf418..fca879e8f1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -241,10 +241,25 @@ namespace MWSound return lookup(lookupId(soundId)); } - void SoundManager::loadVoice(const std::string &voicefile) + DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) return; + if(lipiter != mVoiceLipBuffers.end()) + { + DecoderPtr decoder = getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(voicefile)) + decoder->open(voicefile); + else + { + std::string file = voicefile; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); + } + return decoder; + } DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -266,12 +281,14 @@ namespace MWSound std::vector data; decoder->readAll(data); - decoder->close(); Sound_Loudness loudness; loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); + + decoder->rewind(); + return decoder; } @@ -407,9 +424,7 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - loadVoice(voicefile); - DecoderPtr decoder = getDecoder(); - decoder->open(voicefile); + DecoderPtr decoder = loadVoice(voicefile); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice @@ -449,9 +464,7 @@ namespace MWSound std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); float basevol = volumeFromType(Play_TypeVoice); - loadVoice(voicefile); - DecoderPtr decoder = getDecoder(); - decoder->open(voicefile); + DecoderPtr decoder = loadVoice(voicefile); MWBase::SoundPtr sound = mOutput->streamSound(decoder, basevol, 1.0f, Play_Normal|Play_TypeVoice diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 25ba9ce05d..9fc9084ee7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -93,8 +93,9 @@ namespace MWSound Sound_Buffer *lookup(size_t sfxid); Sound_Buffer *lookup(const std::string &soundId); - // Ensure the loudness/"lip" data is loaded - void loadVoice(const std::string &voicefile); + // Ensures the loudness/"lip" data is loaded, and returns a decoder to + // start streaming + DecoderPtr loadVoice(const std::string &voicefile); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 5ad772c3b3b84012346e8baa18f171e0c610a8cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:54:14 -0800 Subject: [PATCH 1451/1812] Fix streaming sound time --- apps/openmw/mwsound/openal_output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index e3d3ca8dab..b851b931d1 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -376,7 +376,7 @@ double OpenAL_SoundStream::getTimeOffset() { ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - ALint inqueue = mBufferSize/mFrameSize*queued + offset; + ALint inqueue = mBufferSize/mFrameSize*queued - offset; t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; } else From 574c1923fe7ad463c8c556f93086dd08575c81d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 04:54:54 -0800 Subject: [PATCH 1452/1812] Clear unused buffers after unloading them all --- apps/openmw/mwsound/soundmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index fca879e8f1..d7199c0fe9 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -108,6 +108,7 @@ namespace MWSound mOutput->unloadSound(sfxiter->mHandle); sfxiter->mHandle = 0; } + mUnusedBuffers.clear(); } mOutput.reset(); } From 45628316f869ee85f54f0f9f33f4315655bffa9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 05:03:08 -0800 Subject: [PATCH 1453/1812] Remove an unnecessary check --- apps/openmw/mwsound/openal_output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b851b931d1..867a290449 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -436,8 +436,8 @@ bool OpenAL_SoundStream::process() alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state != AL_PLAYING && state != AL_PAUSED) { - if(refillQueue() > 0) - alSourcePlay(mSource); + refillQueue(); + alSourcePlay(mSource); } } } From 8a69f676ec182af006674bfe229d9e3d71ff9f79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 05:56:05 -0800 Subject: [PATCH 1454/1812] Remove some duplicate code --- apps/openmw/mwsound/soundmanagerimp.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d7199c0fe9..d027761361 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -244,24 +244,6 @@ namespace MWSound DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { - NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) - { - DecoderPtr decoder = getDecoder(); - // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - if(decoder->mResourceMgr->exists(voicefile)) - decoder->open(voicefile); - else - { - std::string file = voicefile; - std::string::size_type pos = file.rfind('.'); - if(pos != std::string::npos) - file = file.substr(0, pos)+".mp3"; - decoder->open(file); - } - return decoder; - } - DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. if(decoder->mResourceMgr->exists(voicefile)) @@ -275,6 +257,9 @@ namespace MWSound decoder->open(file); } + NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); + if(lipiter != mVoiceLipBuffers.end()) return decoder; + ChannelConfig chans; SampleType type; int srate; From 4801661b34e1e50be065f02b8221c122161a3603 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 08:08:38 -0800 Subject: [PATCH 1455/1812] Stop all sounds of the given id --- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d027761361..1b88bb3f22 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -603,10 +603,8 @@ namespace MWSound SoundIndexPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second != sfxid) - continue; - sndidx->first->stop(); - return; + if(sndidx->second == sfxid) + sndidx->first->stop(); } } } From fd7d58fe7e130a885bcbd74faa1665266164f0f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 18:48:25 -0800 Subject: [PATCH 1456/1812] Reset the sound handle back to null after unloading --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b88bb3f22..ebc3aab7ef 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -225,8 +225,11 @@ namespace MWSound } SoundSet::iterator iter = mUnusedBuffers.begin(); Sound_Buffer *unused = &mSoundBuffers[*iter]; + mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); + unused->mHandle = 0; + mUnusedBuffers.erase(iter); } mUnusedBuffers.insert(sfxid); From ea70b0baee524387b05c0ff7595c67662d2e8aa7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 20:03:15 -0800 Subject: [PATCH 1457/1812] Don't store the buffer in the sound struct --- apps/openmw/mwsound/openal_output.cpp | 73 ++++++++++++++------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 867a290449..61a5cc3a33 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -146,6 +146,19 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } +static double getBufferLength(ALuint buffer) +{ + ALint bufferSize, frequency, channels, bitsPerSample; + alGetBufferi(buffer, AL_SIZE, &bufferSize); + alGetBufferi(buffer, AL_FREQUENCY, &frequency); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_BITS, &bitsPerSample); + throwALerror(); + + return (8.0*bufferSize)/(frequency*channels*bitsPerSample); +} + + // // A streaming OpenAL sound. // @@ -515,7 +528,6 @@ protected: OpenAL_Output &mOutput; ALuint mSource; - ALuint mBuffer; friend class OpenAL_Output; @@ -526,13 +538,12 @@ private: OpenAL_Sound& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); + OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_Sound(); virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual double getLength(); virtual void update(); }; @@ -545,16 +556,16 @@ class OpenAL_Sound3D : public OpenAL_Sound OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags) + OpenAL_Sound3D(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) { } virtual void update(); }; -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src), mBuffer(buf) + , mOutput(output), mSource(src) { mOutput.mActiveSounds.push_back(this); } @@ -595,17 +606,6 @@ double OpenAL_Sound::getTimeOffset() return t; } -double OpenAL_Sound::getLength() -{ - ALint bufferSize, frequency, channels, bitsPerSample; - alGetBufferi(mBuffer, AL_SIZE, &bufferSize); - alGetBufferi(mBuffer, AL_FREQUENCY, &frequency); - alGetBufferi(mBuffer, AL_CHANNELS, &channels); - alGetBufferi(mBuffer, AL_BITS, &bitsPerSample); - - return (8.0*bufferSize)/(frequency*channels*bitsPerSample); -} - void OpenAL_Sound::updateAll(bool local) { alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); @@ -815,11 +815,15 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - if((*iter)->mSource && (*iter)->mBuffer == buffer) + if(!(*iter)->mSource) + continue; + + ALint srcbuf; + alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf); + if((ALuint)srcbuf == buffer) { alSourceStop((*iter)->mSource); alSourcei((*iter)->mSource, AL_BUFFER, 0); - (*iter)->mBuffer = 0; } } alDeleteBuffers(1, &buffer); @@ -847,9 +851,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba src = mFreeSources.front(); mFreeSources.pop_front(); - ALuint buffer = GET_PTRID(data); try { - sound.reset(new OpenAL_Sound(*this, src, buffer, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception&) { @@ -858,13 +861,14 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba } sound->updateAll(true); - if(offset<0) - offset=0; - if(offset>1) - offset=1; + if(offset < 0.0f) + offset = 0.0f; + if(offset > 1.0f) + offset = 1.0f; + ALuint buffer = GET_PTRID(data); alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); + alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -882,9 +886,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f src = mFreeSources.front(); mFreeSources.pop_front(); - ALuint buffer = GET_PTRID(data); try { - sound.reset(new OpenAL_Sound3D(*this, src, buffer, pos, vol, basevol, pitch, min, max, flags)); + sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags)); } catch(std::exception&) { @@ -893,14 +896,14 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } sound->updateAll(false); + if(offset < 0.0f) + offset = 0.0f; + if(offset > 1.0f) + offset = 1.0f; - if(offset<0) - offset=0; - if(offset>1) - offset=1; - + ALuint buffer = GET_PTRID(data); alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); + alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); From 669b7a22953689a5b8593a0131b400f1ff812769 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 20:37:38 -0800 Subject: [PATCH 1458/1812] Batch update changes together, when possible Certain OpenAL implementations, including Rapture3D, Creative's hardware drivers, and more recent versions of OpenAL Soft, can batch together changes so that they all occur at once, avoiding potential discontinuities with one sound being changed before another, or the listeenr being changed before sounds are. On other implementaitons, this is a no-op and maintains existing behavior. --- apps/openmw/mwsound/openal_output.cpp | 11 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 3 +++ apps/openmw/mwsound/sound_output.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 61a5cc3a33..33202ba741 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -970,6 +970,17 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec } +void OpenAL_Output::startUpdate() +{ + alcSuspendContext(alcGetCurrentContext()); +} + +void OpenAL_Output::finishUpdate() +{ + alcProcessContext(alcGetCurrentContext()); +} + + void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { mPos = pos; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 912bebb569..0f54da9b5c 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -51,6 +51,9 @@ namespace MWSound virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags); + virtual void startUpdate(); + virtual void finishUpdate(); + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env); virtual void pauseSounds(int types); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 86be94d335..c91431f696 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -39,6 +39,9 @@ namespace MWSound virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void startUpdate() = 0; + virtual void finishUpdate() = 0; + virtual void updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) = 0; virtual void pauseSounds(int types) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ebc3aab7ef..3ccc1c715a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -803,6 +803,7 @@ namespace MWSound mUnderwaterSound.reset(); } + mOutput->startUpdate(); mOutput->updateListener( mListenerPos, mListenerDir, @@ -848,6 +849,7 @@ namespace MWSound else ++sayiter; } + mOutput->finishUpdate(); } bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) @@ -905,6 +907,9 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); + if(!mOutput->isInitialized()) + return; + mOutput->startUpdate(); SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { @@ -928,6 +933,7 @@ namespace MWSound mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); mMusic->update(); } + mOutput->finishUpdate(); } void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) From caae305dddde434ca79f89a20d40416da43b4462 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 21:40:15 -0800 Subject: [PATCH 1459/1812] Use a sorted list for unused buffers Helps ensure the buffers being unloaded due to cache limits are not likely to be needed anytime soon. --- apps/openmw/mwsound/soundmanagerimp.cpp | 29 +++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 6 +++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 3ccc1c715a..9183378f74 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -223,16 +223,15 @@ namespace MWSound std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); unused->mHandle = 0; - mUnusedBuffers.erase(iter); + mUnusedBuffers.pop_back(); } - mUnusedBuffers.insert(sfxid); + mUnusedBuffers.push_front(sfxid); } return sfx; @@ -520,7 +519,11 @@ namespace MWSound volume * sfx->mVolume, basevol, pitch, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) @@ -552,7 +555,11 @@ namespace MWSound objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } if((mode&Play_NoTrack)) mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); else @@ -582,7 +589,11 @@ namespace MWSound initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); if(sfx->mReferences++ == 0) - mUnusedBuffers.erase(sfxid); + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); } catch(std::exception &) @@ -829,7 +840,7 @@ namespace MWSound { Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndidx->second); + mUnusedBuffers.push_front(sndidx->second); sndidx = snditer->second.erase(sndidx); } else @@ -1042,7 +1053,7 @@ namespace MWSound sndidx->first->stop(); Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; if(sfx->mReferences-- == 1) - mUnusedBuffers.insert(sndidx->second); + mUnusedBuffers.push_front(sndidx->second); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9fc9084ee7..d5c9a881ea 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -62,8 +63,9 @@ namespace MWSound typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; - typedef std::set SoundSet; - SoundSet mUnusedBuffers; + // NOTE: unused buffers are stored in front-newest order. + typedef std::deque SoundList; + SoundList mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; From 73448c72f63583e6e881ee6a6f5c3c42c9d7945c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Nov 2015 23:24:42 -0800 Subject: [PATCH 1460/1812] Replace Play_NoTrack with playManualSound3D, and rename the latter --- apps/openmw/mwbase/soundmanager.hpp | 23 ++++++++++------------- apps/openmw/mwmechanics/actors.cpp | 5 +++-- apps/openmw/mwsound/soundmanagerimp.cpp | 9 +++------ apps/openmw/mwsound/soundmanagerimp.hpp | 6 +++--- apps/openmw/mwworld/action.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/projectilemanager.cpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 4fccec40bb..91bdef9678 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -29,13 +29,10 @@ namespace MWBase public: /* These must all fit together */ enum PlayMode { - Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ + Play_Normal = 0, /* non-looping, affected by 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. */ - Play_RemoveAtDistance = 1<<3, /* (3D only) If the listener gets further than 2000 units away + Play_RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away from the sound source, the sound is removed. This is weird stuff but apparently how vanilla works for sounds played by the PlayLoopSound family of script functions. Perhaps we @@ -45,11 +42,11 @@ namespace MWBase Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance }; enum PlayType { - Play_TypeSfx = 1<<4, /* Normal SFX sound */ - Play_TypeVoice = 1<<5, /* Voice sound */ - Play_TypeFoot = 1<<6, /* Footstep sound */ - Play_TypeMusic = 1<<7, /* Music track */ - Play_TypeMovie = 1<<8, /* Movie audio track */ + Play_TypeSfx = 1<<3, /* Normal SFX sound */ + Play_TypeVoice = 1<<4, /* Voice sound */ + Play_TypeFoot = 1<<5, /* Footstep sound */ + Play_TypeMusic = 1<<6, /* Music track */ + Play_TypeMovie = 1<<7, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie }; @@ -120,9 +117,9 @@ namespace MWBase ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0; - ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. + virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; + ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 284e237a0d..59f8ecbc0f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -212,8 +212,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, "", mCreature.getRefData().getPosition().asVec3()); - MWBase::Environment::get().getSoundManager()->playSound3D(mCreature, "conjuration hit", 1.f, 1.f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D( + mCreature.getRefData().getPosition().asVec3(), "conjuration hit", 1.f, 1.f + ); } }; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9183378f74..7819102838 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -560,10 +560,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - if((mode&Play_NoTrack)) - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); - else - mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); } catch(std::exception&) { @@ -572,8 +569,8 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset) + MWBase::SoundPtr SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d5c9a881ea..3b2ed873e8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -168,9 +168,9 @@ namespace MWSound ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. - virtual MWBase::SoundPtr playManualSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); - ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition. + virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< Play a sound from an object ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 6361b34048..c29377ecb3 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -19,19 +19,26 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty()) + if(!mSoundId.empty()) { - if (mKeepSound && actor == MWMechanics::getPlayer()) + if(mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal, mSoundOffset + ); else { bool local = mTarget.isEmpty() || !mTarget.isInCell(); // no usable target - - MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal, - mSoundOffset); + if(mKeepSound) + MWBase::Environment::get().getSoundManager()->playSound3D( + (local ? actor : mTarget).getRefData().getPosition().asVec3(), + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); + else + MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); } } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d5aca17a63..0aeaabf12b 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -107,7 +107,7 @@ namespace MWWorld createModel(state, ptr.getClass().getModel(ptr), pos, orient); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); mMagicBolts.push_back(state); } @@ -374,8 +374,8 @@ namespace MWWorld createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); state.mSoundId = esm.mSound; mMagicBolts.push_back(state); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6f63605c78..df2e577d16 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3153,9 +3153,9 @@ namespace MWWorld { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(!effect->mAreaSound.empty()) - sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playSound3D(origin, effect->mAreaSound, 1.0f, 1.0f); else - sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack); + sndMgr->playSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f); } // Get the actors in range of the effect std::vector objects; From aac903484c661e6bcecfb2c7d67b182822bd3735 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 00:09:40 -0800 Subject: [PATCH 1461/1812] Remove a really unnecessary method --- apps/openmw/mwbase/soundmanager.hpp | 3 --- apps/openmw/mwsound/soundmanagerimp.cpp | 5 ----- apps/openmw/mwsound/soundmanagerimp.hpp | 3 --- apps/openmw/mwworld/projectilemanager.cpp | 5 ++--- apps/openmw/mwworld/weather.cpp | 8 +++----- 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 91bdef9678..9366875e34 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -127,9 +127,6 @@ namespace MWBase virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; ///< Stop the given object from playing all sounds. - virtual void stopSound(MWBase::SoundPtr sound) = 0; - ///< Stop the given sound handle - virtual void stopSound(const MWWorld::CellStore *cell) = 0; ///< Stop all sounds for the given cell. diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7819102838..26ba1e2103 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -600,11 +600,6 @@ namespace MWSound return sound; } - void SoundManager::stopSound (MWBase::SoundPtr sound) - { - sound->stop(); - } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 3b2ed873e8..15fdd86cf2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -181,9 +181,6 @@ namespace MWSound virtual void stopSound3D(const MWWorld::Ptr &reference); ///< Stop the given object from playing all sounds. - virtual void stopSound(MWBase::SoundPtr sound); - ///< Stop the given sound handle - virtual void stopSound(const MWWorld::CellStore *cell); ///< Stop all sounds for the given cell. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 0aeaabf12b..4ec4d14325 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -190,8 +190,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); - + it->mSound->stop(); mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); @@ -265,7 +264,7 @@ namespace MWWorld for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { mParent->removeChild(it->mNode); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); + it->mSound->stop(); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 49d421a201..6d9a85ada4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -735,11 +735,9 @@ void WeatherManager::update(float duration, bool paused) void WeatherManager::stopSounds() { if (mAmbientSound.get()) - { - MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); - mAmbientSound.reset(); - mPlayingSoundID.clear(); - } + mAmbientSound->stop(); + mAmbientSound.reset(); + mPlayingSoundID.clear(); } float WeatherManager::getWindSpeed() const From a1bdb544dbaa6520f265be73a2710a5c5b82668d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 01:05:55 -0800 Subject: [PATCH 1462/1812] Avoid an unnecessary string copy --- apps/openmw/mwsound/openal_output.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 33202ba741..bafd272af6 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -773,14 +773,16 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - std::string file = fname; - if (!decoder->mResourceMgr->exists(file)) + if(decoder->mResourceMgr->exists(fname)) + decoder->open(fname); + else { + std::string file = fname; std::string::size_type pos = file.rfind('.'); if(pos != std::string::npos) file = file.substr(0, pos)+".mp3"; + decoder->open(file); } - decoder->open(file); std::vector data; ChannelConfig chans; From 0d4fea896c549edb109587d42f9630af1f7816f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 02:04:10 -0800 Subject: [PATCH 1463/1812] Avoid unsafe sizeof(x)/sizeof(x[0]) constructs for array counting --- apps/openmw/mwsound/openal_output.cpp | 98 ++++++++++++--------------- 1 file changed, 44 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bafd272af6..419bb76b74 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,13 +23,17 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace MWSound +namespace { -static void fail(const std::string &msg) +template +inline size_t countof(const T(&)[N]) +{ return N; } + +void fail(const std::string &msg) { throw std::runtime_error("OpenAL exception: " + msg); } -static void throwALCerror(ALCdevice *device) +void throwALCerror(ALCdevice *device) { ALCenum err = alcGetError(device); if(err != ALC_NO_ERROR) @@ -39,7 +43,7 @@ static void throwALCerror(ALCdevice *device) } } -static void throwALerror() +void throwALerror() { ALenum err = alGetError(); if(err != AL_NO_ERROR) @@ -50,21 +54,39 @@ static void throwALerror() } -static ALenum getALFormat(ChannelConfig chans, SampleType type) +ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) { static const struct { ALenum format; - ChannelConfig chans; - SampleType type; + MWSound::ChannelConfig chans; + MWSound::SampleType type; } fmtlist[] = { - { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, - { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, - { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, - { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, + { AL_FORMAT_MONO16, MWSound::ChannelConfig_Mono, MWSound::SampleType_Int16 }, + { AL_FORMAT_MONO8, MWSound::ChannelConfig_Mono, MWSound::SampleType_UInt8 }, + { AL_FORMAT_STEREO16, MWSound::ChannelConfig_Stereo, MWSound::SampleType_Int16 }, + { AL_FORMAT_STEREO8, MWSound::ChannelConfig_Stereo, MWSound::SampleType_UInt8 }, + }; + static const struct { + char name[32]; + MWSound::ChannelConfig chans; + MWSound::SampleType type; + } mcfmtlist[] = { + { "AL_FORMAT_QUAD16", MWSound::ChannelConfig_Quad, MWSound::SampleType_Int16 }, + { "AL_FORMAT_QUAD8", MWSound::ChannelConfig_Quad, MWSound::SampleType_UInt8 }, + { "AL_FORMAT_51CHN16", MWSound::ChannelConfig_5point1, MWSound::SampleType_Int16 }, + { "AL_FORMAT_51CHN8", MWSound::ChannelConfig_5point1, MWSound::SampleType_UInt8 }, + { "AL_FORMAT_71CHN16", MWSound::ChannelConfig_7point1, MWSound::SampleType_Int16 }, + { "AL_FORMAT_71CHN8", MWSound::ChannelConfig_7point1, MWSound::SampleType_UInt8 }, + }, fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", MWSound::ChannelConfig_Mono, MWSound::SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", MWSound::ChannelConfig_Stereo, MWSound::SampleType_Float32 }, + }, fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", MWSound::ChannelConfig_Quad, MWSound::SampleType_Float32 }, + { "AL_FORMAT_51CHN32", MWSound::ChannelConfig_5point1, MWSound::SampleType_Float32 }, + { "AL_FORMAT_71CHN32", MWSound::ChannelConfig_7point1, MWSound::SampleType_Float32 }, }; - static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); - for(size_t i = 0;i < fmtlistsize;i++) + for(size_t i = 0;i < countof(fmtlist);i++) { if(fmtlist[i].chans == chans && fmtlist[i].type == type) return fmtlist[i].format; @@ -72,21 +94,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } mcfmtlist[] = { - { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, - { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, - { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, - { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, - { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, - { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, - }; - static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); - - for(size_t i = 0;i < mcfmtlistsize;i++) + for(size_t i = 0;i < countof(mcfmtlist);i++) { if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) { @@ -98,17 +106,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltfmtlist[] = { - { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, - { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, - }; - static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); - - for(size_t i = 0;i < fltfmtlistsize;i++) + for(size_t i = 0;i < countof(fltfmtlist);i++) { if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) { @@ -119,18 +117,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltmcfmtlist[] = { - { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, - { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, - { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, - }; - static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); - - for(size_t i = 0;i < fltmcfmtlistsize;i++) + for(size_t i = 0;i < countof(fltmcfmtlist);i++) { if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) { @@ -142,11 +129,10 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } - fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); - return AL_NONE; + throw std::runtime_error(std::string("Unsupported sound format (")+MWSound::getChannelConfigName(chans)+", "+MWSound::getSampleTypeName(type)+")"); } -static double getBufferLength(ALuint buffer) +double getBufferLength(ALuint buffer) { ALint bufferSize, frequency, channels, bitsPerSample; alGetBufferi(buffer, AL_SIZE, &bufferSize); @@ -158,6 +144,10 @@ static double getBufferLength(ALuint buffer) return (8.0*bufferSize)/(frequency*channels*bitsPerSample); } +} + +namespace MWSound +{ // // A streaming OpenAL sound. From 04f885d8cc72a36deccbdd5f7c3fe9fa12942a58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 03:34:44 -0800 Subject: [PATCH 1464/1812] Rename mReferences to mUses --- apps/openmw/mwsound/sound_buffer.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index eb67908a2b..8f8e43da4b 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -21,10 +21,10 @@ namespace MWSound Sound_Handle mHandle; - size_t mReferences; + size_t mUses; Sound_Buffer(std::string resname, float volume, float mindist, float maxdist) - : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mReferences(0) + : mResourceName(resname), mVolume(volume), mMinDist(mindist), mMaxDist(maxdist), mHandle(0), mUses(0) { } }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 26ba1e2103..c7e5047701 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -518,7 +518,7 @@ namespace MWSound sound = mOutput->playSound(sfx->mHandle, volume * sfx->mVolume, basevol, pitch, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -554,7 +554,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -585,7 +585,7 @@ namespace MWSound sound = mOutput->playSound3D(sfx->mHandle, initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset ); - if(sfx->mReferences++ == 0) + if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); if(iter != mUnusedBuffers.end()) @@ -831,7 +831,7 @@ namespace MWSound if(!updateSound(sndidx->first, snditer->first, duration)) { Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; - if(sfx->mReferences-- == 1) + if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sndidx->second); sndidx = snditer->second.erase(sndidx); } @@ -1044,7 +1044,7 @@ namespace MWSound { sndidx->first->stop(); Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; - if(sfx->mReferences-- == 1) + if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sndidx->second); } } From 8f08ca9cbafcce05879e8a254e6888edf3eead12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2015 06:06:27 -0800 Subject: [PATCH 1465/1812] Revert "Avoid unsafe sizeof(x)/sizeof(x[0]) constructs for array counting" This reverts commit 0d4fea896c549edb109587d42f9630af1f7816f9. --- apps/openmw/mwsound/openal_output.cpp | 98 +++++++++++++++------------ 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 419bb76b74..bafd272af6 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,17 +23,13 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) -namespace +namespace MWSound { -template -inline size_t countof(const T(&)[N]) -{ return N; } - -void fail(const std::string &msg) +static void fail(const std::string &msg) { throw std::runtime_error("OpenAL exception: " + msg); } -void throwALCerror(ALCdevice *device) +static void throwALCerror(ALCdevice *device) { ALCenum err = alcGetError(device); if(err != ALC_NO_ERROR) @@ -43,7 +39,7 @@ void throwALCerror(ALCdevice *device) } } -void throwALerror() +static void throwALerror() { ALenum err = alGetError(); if(err != AL_NO_ERROR) @@ -54,39 +50,21 @@ void throwALerror() } -ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) +static ALenum getALFormat(ChannelConfig chans, SampleType type) { static const struct { ALenum format; - MWSound::ChannelConfig chans; - MWSound::SampleType type; + ChannelConfig chans; + SampleType type; } fmtlist[] = { - { AL_FORMAT_MONO16, MWSound::ChannelConfig_Mono, MWSound::SampleType_Int16 }, - { AL_FORMAT_MONO8, MWSound::ChannelConfig_Mono, MWSound::SampleType_UInt8 }, - { AL_FORMAT_STEREO16, MWSound::ChannelConfig_Stereo, MWSound::SampleType_Int16 }, - { AL_FORMAT_STEREO8, MWSound::ChannelConfig_Stereo, MWSound::SampleType_UInt8 }, - }; - static const struct { - char name[32]; - MWSound::ChannelConfig chans; - MWSound::SampleType type; - } mcfmtlist[] = { - { "AL_FORMAT_QUAD16", MWSound::ChannelConfig_Quad, MWSound::SampleType_Int16 }, - { "AL_FORMAT_QUAD8", MWSound::ChannelConfig_Quad, MWSound::SampleType_UInt8 }, - { "AL_FORMAT_51CHN16", MWSound::ChannelConfig_5point1, MWSound::SampleType_Int16 }, - { "AL_FORMAT_51CHN8", MWSound::ChannelConfig_5point1, MWSound::SampleType_UInt8 }, - { "AL_FORMAT_71CHN16", MWSound::ChannelConfig_7point1, MWSound::SampleType_Int16 }, - { "AL_FORMAT_71CHN8", MWSound::ChannelConfig_7point1, MWSound::SampleType_UInt8 }, - }, fltfmtlist[] = { - { "AL_FORMAT_MONO_FLOAT32", MWSound::ChannelConfig_Mono, MWSound::SampleType_Float32 }, - { "AL_FORMAT_STEREO_FLOAT32", MWSound::ChannelConfig_Stereo, MWSound::SampleType_Float32 }, - }, fltmcfmtlist[] = { - { "AL_FORMAT_QUAD32", MWSound::ChannelConfig_Quad, MWSound::SampleType_Float32 }, - { "AL_FORMAT_51CHN32", MWSound::ChannelConfig_5point1, MWSound::SampleType_Float32 }, - { "AL_FORMAT_71CHN32", MWSound::ChannelConfig_7point1, MWSound::SampleType_Float32 }, + { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, + { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, + { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, + { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, }; + static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); - for(size_t i = 0;i < countof(fmtlist);i++) + for(size_t i = 0;i < fmtlistsize;i++) { if(fmtlist[i].chans == chans && fmtlist[i].type == type) return fmtlist[i].format; @@ -94,7 +72,21 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - for(size_t i = 0;i < countof(mcfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } mcfmtlist[] = { + { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, + { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, + { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, + { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, + { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, + { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, + }; + static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); + + for(size_t i = 0;i < mcfmtlistsize;i++) { if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) { @@ -106,7 +98,17 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - for(size_t i = 0;i < countof(fltfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, + }; + static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + + for(size_t i = 0;i < fltfmtlistsize;i++) { if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) { @@ -117,7 +119,18 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - for(size_t i = 0;i < countof(fltmcfmtlist);i++) + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, + { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, + { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, + }; + static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + + for(size_t i = 0;i < fltmcfmtlistsize;i++) { if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) { @@ -129,10 +142,11 @@ ALenum getALFormat(MWSound::ChannelConfig chans, MWSound::SampleType type) } } - throw std::runtime_error(std::string("Unsupported sound format (")+MWSound::getChannelConfigName(chans)+", "+MWSound::getSampleTypeName(type)+")"); + fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); + return AL_NONE; } -double getBufferLength(ALuint buffer) +static double getBufferLength(ALuint buffer) { ALint bufferSize, frequency, channels, bitsPerSample; alGetBufferi(buffer, AL_SIZE, &bufferSize); @@ -144,10 +158,6 @@ double getBufferLength(ALuint buffer) return (8.0*bufferSize)/(frequency*channels*bitsPerSample); } -} - -namespace MWSound -{ // // A streaming OpenAL sound. From ac2eedcb7d944240bb8f35ef179ade8811f3b544 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 09:24:38 -0500 Subject: [PATCH 1466/1812] Change wording in warning to be clearer. Correct ranges on contrast and gamma. --- files/settings-default.cfg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f16ef91248..5ed2d688d5 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,5 +1,6 @@ -# WARNING: Editing this file might have no effect, as these settings -# are overwritten by your user settings file. +# WARNING: If this file is named settings-default.cfg, then editing +# this file might have no effect, as these settings may be overwritten +# by your user settings.cfg file (see docmentation for its location). # # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the @@ -192,10 +193,10 @@ vsync = false # Maximum frames per second. (1.0 to 200.0). framerate limit = 0.0 -# Game video contrast. (0.0 to 1.0). No effect in Linux. +# Game video contrast. (>0.0). No effect in Linux. contrast = 1.0 -# Video gamma setting. (0.0 to 1.0). No effect in Linux. +# Video gamma setting. (>0.0). No effect in Linux. gamma = 1.0 [Water] From 18da95e4f8dd82fb7058b0cb5e17c06259e0961f Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 13:08:53 -0500 Subject: [PATCH 1467/1812] Make openmw-launcher pass comments through settings.cfg, and reuse the Settings::Manager code to do most of the work. Stop loading both the global settings-default.cfg and the one in the current directory, while continuing to prefer the latter one. Cleanup paths slightly and remove what appears to have been debugging in the launcher settings. --- apps/launcher/settings/graphicssettings.cpp | 44 --------------------- apps/launcher/settings/graphicssettings.hpp | 18 --------- 2 files changed, 62 deletions(-) delete mode 100644 apps/launcher/settings/graphicssettings.cpp delete mode 100644 apps/launcher/settings/graphicssettings.hpp diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp deleted file mode 100644 index 9dad3dee6b..0000000000 --- a/apps/launcher/settings/graphicssettings.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "graphicssettings.hpp" - -#include -#include -#include -#include - -Launcher::GraphicsSettings::GraphicsSettings() -{ -} - -Launcher::GraphicsSettings::~GraphicsSettings() -{ -} - -bool Launcher::GraphicsSettings::writeFile(QTextStream &stream) -{ - QString sectionPrefix; - QRegExp sectionRe("([^/]+)/(.+)$"); - QMap settings = SettingsBase::getSettings(); - - QMapIterator i(settings); - while (i.hasNext()) { - i.next(); - - QString prefix; - QString key; - - if (sectionRe.exactMatch(i.key())) { - prefix = sectionRe.cap(1); - key = sectionRe.cap(2); - } - - if (sectionPrefix != prefix) { - sectionPrefix = prefix; - stream << "\n[" << prefix << "]\n"; - } - - stream << key << " = " << i.value() << "\n"; - } - - return true; - -} diff --git a/apps/launcher/settings/graphicssettings.hpp b/apps/launcher/settings/graphicssettings.hpp deleted file mode 100644 index a52e0aa84c..0000000000 --- a/apps/launcher/settings/graphicssettings.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GRAPHICSSETTINGS_HPP -#define GRAPHICSSETTINGS_HPP - -#include - -namespace Launcher -{ - class GraphicsSettings : public Config::SettingsBase > - { - public: - GraphicsSettings(); - ~GraphicsSettings(); - - bool writeFile(QTextStream &stream); - - }; -} -#endif // GRAPHICSSETTINGS_HPP From 67c4b17581850ced0439b2f107dd7b0e0971203a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 13:17:03 -0500 Subject: [PATCH 1468/1812] Commit files that I thought wre in the previous commit. :-[ I'm accustomed to the hg behavior of commiting all modified files by default. --- apps/launcher/CMakeLists.txt | 4 - apps/launcher/datafilespage.cpp | 2 +- apps/launcher/graphicspage.cpp | 62 ++++++------- apps/launcher/graphicspage.hpp | 6 +- apps/launcher/maindialog.cpp | 121 ++++++++++++------------- apps/launcher/maindialog.hpp | 4 +- apps/openmw/engine.cpp | 6 +- components/config/launchersettings.cpp | 2 - 8 files changed, 100 insertions(+), 107 deletions(-) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 274239fb0c..75f76a5327 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -7,8 +7,6 @@ set(LAUNCHER textslotmsgbox.cpp settingspage.cpp - settings/graphicssettings.cpp - utils/profilescombobox.cpp utils/textinputdialog.cpp utils/lineedit.cpp @@ -24,8 +22,6 @@ set(LAUNCHER_HEADER textslotmsgbox.hpp settingspage.hpp - settings/graphicssettings.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp utils/lineedit.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ec2e1246ef..0b0f8c75e2 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -75,7 +75,7 @@ bool Launcher::DataFilesPage::loadSettings() QStringList profiles = mLauncherSettings.getContentLists(); QString currentProfile = mLauncherSettings.getCurrentContentListName(); - qDebug() << "current profile is: " << currentProfile; + qDebug() << "The current profile is: " << currentProfile; foreach (const QString &item, profiles) addProfile (item, false); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2128c08f74..a3bfbe5db0 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -18,7 +18,7 @@ #include -#include "settings/graphicssettings.hpp" +#include QString getAspect(int x, int y) { @@ -32,10 +32,10 @@ QString getAspect(int x, int y) return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); } -Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) +Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) - , mGraphicsSettings(graphicsSetting) + , mEngineSettings(engineSettings) { setObjectName ("GraphicsPage"); setupUi(this); @@ -80,25 +80,26 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; - if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) + if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + if (mEngineSettings.getBool("fullscreen", "Video")) fullScreenCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/window border")) == QLatin1String("true")) + if (mEngineSettings.getBool("window border", "Video")) windowBorderCheckBox->setCheckState(Qt::Checked); - int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + // aaValue is the actual value (0, 1, 2, 4, 8, 16) + int aaValue = mEngineSettings.getInt("antialiasing", "Video"); + // aaIndex is the index into the allowed values in the pull down. + int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue)); if (aaIndex != -1) antiAliasingComboBox->setCurrentIndex(aaIndex); - QString width = mGraphicsSettings.value(QString("Video/resolution x")); - QString height = mGraphicsSettings.value(QString("Video/resolution y")); - QString resolution = width + QString(" x ") + height; - QString screen = mGraphicsSettings.value(QString("Video/screen")); - - screenComboBox->setCurrentIndex(screen.toInt()); + int width = mEngineSettings.getInt("resolution x", "Video"); + int height = mEngineSettings.getInt("resolution y", "Video"); + QString resolution = QString::number(width) + QString(" x ") + QString::number(height); + screenComboBox->setCurrentIndex(mEngineSettings.getInt("screen", "Video")); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -107,9 +108,8 @@ bool Launcher::GraphicsPage::loadSettings() resolutionComboBox->setCurrentIndex(resIndex); } else { customRadioButton->toggle(); - customWidthSpinBox->setValue(width.toInt()); - customHeightSpinBox->setValue(height.toInt()); - + customWidthSpinBox->setValue(width); + customHeightSpinBox->setValue(height); } return true; @@ -117,31 +117,29 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - - fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - - windowBorderCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/window border"), QString("true")) - : mGraphicsSettings.setValue(QString("Video/window border"), QString("false")); - - mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); + mEngineSettings.setBool("vsync", "Video", vSyncCheckBox->checkState()); + mEngineSettings.setBool("fullscreen", "Video", fullScreenCheckBox->checkState()); + mEngineSettings.setBool("window border", "Video", windowBorderCheckBox->checkState()); + // The atoi() call is safe because the pull down constrains the string values. + int aaValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + mEngineSettings.setInt("antialiasing", "Video", aaValue); if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + // The atoi() call is safe because the pull down constrains the string values. + int width = atoi(resolutionRe.cap(1).toLatin1().data()); + int height = atoi(resolutionRe.cap(2).toLatin1().data()); + mEngineSettings.setInt("resolution x", "Video", width); + mEngineSettings.setInt("resolution y", "Video", height); } } else { - mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); - mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); + mEngineSettings.setInt("resolution x", "Video", customWidthSpinBox->value()); + mEngineSettings.setInt("resolution y", "Video", customHeightSpinBox->value()); } - mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); + mEngineSettings.setInt("screen", "Video", screenComboBox->currentIndex()); } QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index fb96c39d78..e6eb53a3b7 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -5,6 +5,8 @@ #include "ui_graphicspage.h" +#include + namespace Files { struct ConfigurationManager; } namespace Launcher @@ -16,7 +18,7 @@ namespace Launcher Q_OBJECT public: - GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); + GraphicsPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent = 0); void saveSettings(); bool loadSettings(); @@ -30,7 +32,7 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; - GraphicsSettings &mGraphicsSettings; + Settings::Manager &mEngineSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9a6f91a0f5..1c56a9efd8 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -105,7 +105,7 @@ void Launcher::MainDialog::createPages() { mPlayPage = new PlayPage(this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); - mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); + mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this); mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage @@ -381,55 +381,64 @@ bool Launcher::MainDialog::setupGameSettings() return true; } +void cfgError(const QString& title, const QString& msg) { + QMessageBox msgBox; + msgBox.setWindowTitle(title); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(msg); + msgBox.exec(); +} + bool Launcher::MainDialog::setupGraphicsSettings() { - mGraphicsSettings.setMultiValueEnabled(false); + // This method is almost a copy of OMW::Engine::loadSettings(). They should definitely + // remain consistent, and possibly be merged into a shared component. At the very least + // the filenames should be in the CfgMgr component. - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); - QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); + // 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"; + std::string defaultPath; - QFile localDefault(QString("settings-default.cfg")); - QFile globalDefault(globalPath + QString("settings-default.cfg")); - - if (!localDefault.exists() && !globalDefault.exists()) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error reading OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not find settings-default.cfg

    \ - The problem may be due to an incomplete installation of OpenMW.
    \ - Reinstalling OpenMW may resolve the problem.")); - msgBox.exec(); + // Prefer the settings-default.cfg in the current directory. + if (boost::filesystem::exists(localDefault)) + defaultPath = localDefault; + else if (boost::filesystem::exists(globalDefault)) + defaultPath = globalDefault; + // Something's very wrong if we can't find the file at all. + else { + cfgError(tr("Error reading OpenMW configuration file"), + tr("
    Could not find settings-default.cfg

    \ + The problem may be due to an incomplete installation of OpenMW.
    \ + Reinstalling OpenMW may resolve the problem.")); return false; } + // Load the default settings, report any parsing errors. + try { + mEngineSettings.loadDefault(defaultPath); + } + catch (std::exception& e) { + std::string msg = "
    Error reading settings-default.cfg

    " + + defaultPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; + } - QStringList paths; - paths.append(globalPath + QString("settings-default.cfg")); - paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); + // Load user settings if they exist + const std::string userPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + // User settings are not required to exist, so if they don't we're done. + if (!boost::filesystem::exists(userPath)) return true; - foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - mGraphicsSettings.readFile(stream); - } - file.close(); + try { + mEngineSettings.loadUser(userPath); + } + catch (std::exception& e) { + std::string msg = "
    Error reading settings-default.cfg

    " + + defaultPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; } return true; @@ -511,27 +520,16 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Graphics settings - file.setFileName(userPath + QString("settings.cfg")); - - if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + const std::string settingsPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + try { + mEngineSettings.saveUser(settingsPath); + } + catch (std::exception& e) { + std::string msg = "
    Error writing settings.cfg

    " + + settingsPath + "

    " + e.what(); + cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + return false; } - - QTextStream stream(&file); - stream.setDevice(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - mGraphicsSettings.writeFile(stream); - file.close(); // Launcher settings file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -549,6 +547,7 @@ bool Launcher::MainDialog::writeSettings() return false; } + QTextStream stream(&file); stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 298682d207..0dfea48659 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -13,7 +13,7 @@ #include #include -#include "settings/graphicssettings.hpp" +#include #include "ui_mainwindow.h" @@ -93,7 +93,7 @@ namespace Launcher Files::ConfigurationManager mCfgMgr; Config::GameSettings mGameSettings; - GraphicsSettings mGraphicsSettings; + Settings::Manager mEngineSettings; Config::LauncherSettings mLauncherSettings; }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 031eac8001..a4f5f94407 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -298,8 +298,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // 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"; + 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)) @@ -310,7 +310,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) 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 - const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; + const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 1d4b428c91..8f34988262 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -25,8 +25,6 @@ QStringList Config::LauncherSettings::subKeys(const QString &key) QMap settings = SettingsBase::getSettings(); QStringList keys = settings.uniqueKeys(); - qDebug() << keys; - QRegExp keyRe("(.+)/"); QStringList result; From 8a3ec14bc616e897f3bbf22c2e6992ae752c6460 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Nov 2015 19:22:48 +0100 Subject: [PATCH 1469/1812] Revert "Merge remote-tracking branch 'sandstranger/opengles'" This reverts commit cc9cab6fd1531a8df6e44ea34c5843c7e9070ad5, reversing changes made to da856eed9512aa202f93b955552f6f7d8ca7ecd2. --- CMakeLists.txt | 44 ++-- apps/openmw/CMakeLists.txt | 34 +-- apps/openmw/android_main.c | 1 + apps/openmw/main.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 5 - apps/openmw/mwrender/sky.cpp | 5 - apps/openmw/mwrender/water.cpp | 11 +- cmake/FindOpenGLES.cmake | 94 -------- cmake/FindOpenGLES2.cmake | 170 -------------- components/CMakeLists.txt | 103 ++++----- .../myguiplatform/myguirendermanager.cpp | 4 - components/sdlutil/sdlcursormanager.cpp | 3 - files/shaders/CMakeLists.txt | 20 +- files/shaders/watergles_fragment.glsl | 209 ------------------ files/shaders/watergles_vertex.glsl | 24 -- 15 files changed, 70 insertions(+), 659 deletions(-) delete mode 100644 cmake/FindOpenGLES.cmake delete mode 100644 cmake/FindOpenGLES2.cmake delete mode 100644 files/shaders/watergles_fragment.glsl delete mode 100644 files/shaders/watergles_vertex.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index ec14d59163..d038936d3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,20 +47,8 @@ include(OpenMWMacros) if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) - add_definitions (-DOSG_PLUGINS_DIR) - set(OPENGLES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) -option(OPENGLES "enable opengl es support" FALSE ) - -if (OPENGLES) - INCLUDE(cmake/FindOpenGLES.cmake) - INCLUDE(cmake/FindOpenGLES2.cmake) - add_definitions (-DOPENGLES) - INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) -endif (OPENGLES) - # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -157,21 +145,21 @@ if (WIN32) endif() # Dependencies -if (NOT ANDROID) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - message(STATUS "Using Qt${DESIRED_QT_VERSION}") - if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) - else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) - endif() +set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") +message(STATUS "Using Qt${DESIRED_QT_VERSION}") + +if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) +else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) + # Instruct CMake to run moc automatically when needed. + #set(CMAKE_AUTOMOC ON) endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) @@ -201,11 +189,7 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -if (NOT ANDROID) - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) -else() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) -endif() +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1f0fe71ab9..59a523023f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -134,50 +134,18 @@ target_link_libraries(openmw ) if (ANDROID) - set (OSG_PLUGINS - -Wl,--whole-archive - ${OSG_PLUGINS_DIR}/libosgdb_dds.a - ${OSG_PLUGINS_DIR}/libosgdb_bmp.a - ${OSG_PLUGINS_DIR}/libosgdb_tga.a - ${OSG_PLUGINS_DIR}/libosgdb_gif.a - ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a - ${OSG_PLUGINS_DIR}/libosgdb_png.a - -Wl,--no-whole-archive - ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic + cpufeatures BulletCollision LinearMath - z - osg - osgDB - osgAnimation - osgText - osgUtil - osgShadow - ${OPENSCENEGRAPH_LIBRARIES} - ${OSG_PLUGINS} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - jpeg - gif - png ) endif (ANDROID) -if (OPENGLES) - target_link_libraries(openmw - ${OPENGLES_gl_LIBRARY} - ${OPENGLES2_gl_LIBRARY} - ) -endif (OPENGLES) - if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 8cd69e8f01..47b77a8b38 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,3 +1,4 @@ +#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c3f0f8688e..17ef46246a 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 077d215127..14ec770e84 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -24,11 +24,6 @@ #include "vismask.hpp" -#ifdef OPENGLES - #include -#endif - - namespace { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7572d7e92f..66253f70d5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -45,11 +45,6 @@ #include "vismask.hpp" #include "renderbin.hpp" -#ifdef OPENGLES - #include -#endif - - namespace { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 5a9bc664a9..ca099991ea 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -40,10 +40,6 @@ #include "ripplesimulation.hpp" #include "renderbin.hpp" -#ifdef OPENGLES -#include -#endif - namespace { @@ -579,13 +575,10 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R // use a define map to conditionally compile the shader std::map defineMap; defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); -#ifdef OPENGLES - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/watergles_vertex.glsl", defineMap)); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/watergles_fragment.glsl", defineMap)); -#else + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); -#endif + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake deleted file mode 100644 index 7ee2c07f18..0000000000 --- a/cmake/FindOpenGLES.cmake +++ /dev/null @@ -1,94 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OpenGLES -# Once done this will define -# -# OPENGLES_FOUND - system has OpenGLES -# OPENGLES_INCLUDE_DIR - the GL include directory -# OPENGLES_LIBRARIES - Link these to use OpenGLES - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") - ELSE(BORLAND) - #MS compiler - todo - fix the following line: - SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - #create_search_paths(/Developer/Platforms) - #findpkg_framework(OpenGLES) - #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") - - ELSE(APPLE) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h - /opt/vc/include - /opt/graphics/OpenGL/include - /usr/openwin/share/include - /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY - NAMES GLES_CM GLESv1_CM - PATHS /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - - #IF (OPENGLES_gl_LIBRARY) - # IF(NOT X11_FOUND) - # INCLUDE(FindX11) - # ENDIF(NOT X11_FOUND) - # IF (X11_FOUND) - # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) - # ENDIF (X11_FOUND) - #ENDIF (OPENGLES_gl_LIBRARY) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGLES_FOUND "NO" ) -IF(OPENGLES_gl_LIBRARY) - - SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) - - SET( OPENGLES_FOUND "YES" ) - -ENDIF(OPENGLES_gl_LIBRARY) - -MARK_AS_ADVANCED( - OPENGLES_INCLUDE_DIR - OPENGLES_gl_LIBRARY -) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/cmake/FindOpenGLES2.cmake b/cmake/FindOpenGLES2.cmake deleted file mode 100644 index 136e7618be..0000000000 --- a/cmake/FindOpenGLES2.cmake +++ /dev/null @@ -1,170 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OpenGLES and EGL -# If using ARM Mali emulation you can specify the parent directory that contains the bin and include directories by -# setting the MALI_SDK_ROOT variable in the environment. -# -# For AMD emulation use the AMD_SDK_ROOT variable -# -# Once done this will define -# -# OPENGLES2_FOUND - system has OpenGLES -# OPENGLES2_INCLUDE_DIR - the GL include directory -# OPENGLES2_LIBRARIES - Link these to use OpenGLES -# -# EGL_FOUND - system has EGL -# EGL_INCLUDE_DIR - the EGL include directory -# EGL_LIBRARIES - Link these to use EGL - -#include(FindPkgMacros) - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32") - ELSE(BORLAND) - #getenv_path(AMD_SDK_ROOT) - #getenv_path(MALI_SDK_ROOT) - - SET(POWERVR_SDK_PATH "C:/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds") - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - ${POWERVR_SDK_PATH}/Include - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" - ) - - FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - ${POWERVR_SDK_PATH}/Include - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/Include" - ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY - NAMES libGLESv2 - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - ${POWERVR_SDK_PATH}/Windows/x86_32/Lib - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" - ) - - FIND_LIBRARY(EGL_egl_LIBRARY - NAMES libEGL - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - ${POWERVR_SDK_PATH}/Windows/x86_32/Lib - "C:/Imagination Technologies/PowerVR Insider SDK/OGLES2_WINDOWS_X86EMULATION_2.10/Builds/OGLES2/WindowsX86/Lib" - ) - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - #create_search_paths(/Developer/Platforms) - #findpkg_framework(OpenGLES2) - #set(OPENGLES2_gl_LIBRARY "-framework OpenGLES") - - ELSE(APPLE) - #getenv_path(AMD_SDK_ROOT) - #getenv_path(MALI_SDK_ROOT) - - FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include - /opt/vc/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(OPENGLES2_gl_LIBRARY - NAMES GLESv2 - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib - /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h - ${ENV_AMD_SDK_ROOT}/include - ${ENV_MALI_SDK_ROOT}/include - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Include - /opt/vc/include - /usr/openwin/share/include - /opt/graphics/OpenGL/include /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(EGL_egl_LIBRARY - NAMES EGL - PATHS ${ENV_AMD_SDK_ROOT}/x86 - ${ENV_MALI_SDK_ROOT}/bin - /opt/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Builds/Linux/x86_32/Lib - /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - # It's not true on OSX. - - #IF (OPENGLES2_gl_LIBRARY) - # IF(NOT X11_FOUND) - # INCLUDE(FindX11) - # ENDIF(NOT X11_FOUND) - # IF (X11_FOUND) - # IF (NOT APPLE) - # SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES}) - # ENDIF (NOT APPLE) - # ENDIF (X11_FOUND) - #ENDIF (OPENGLES2_gl_LIBRARY) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGLES2_FOUND "YES" ) -IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) - - SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES}) - SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES}) - SET( OPENGLES2_FOUND "YES" ) - -ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY) - -MARK_AS_ADVANCED( - OPENGLES2_INCLUDE_DIR - OPENGLES2_gl_LIBRARY - EGL_INCLUDE_DIR - EGL_egl_LIBRARY -) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES2 REQUIRED_VARS OPENGLES2_LIBRARIES OPENGLES2_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7bfbf6d935..c80e27e4d8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,9 +20,8 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -if (NOT ANDROID) - find_package(OpenGL REQUIRED) -endif() +find_package(OpenGL REQUIRED) + # source files add_component_dir (settings @@ -138,31 +137,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -if (NOT ANDROID) - add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) - add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) +add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) +add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) - add_component_qt_dir (process - processinvoker - ) - if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) - else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) - endif() +add_component_qt_dir (process + processinvoker +) + +if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) endif() + if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) @@ -173,46 +172,32 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -if (NOT ANDROID) - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} - ) -else() - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - ${MYGUI_LIBRARIES} - ) -endif() +target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} +) if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (NOT ANDROID) - if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) - else() - qt5_use_modules(components Widgets Core) - endif() +if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) +else() + qt5_use_modules(components Widgets Core) endif() + if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5fb3054a61..5bd56dc8f4 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -17,10 +17,6 @@ #include #include "myguitexture.hpp" - -#ifdef OPENGLES - #include -#endif #define MYGUI_PLATFORM_LOG_SECTION "Platform" #define MYGUI_PLATFORM_LOG(level, text) MYGUI_LOGGING(MYGUI_PLATFORM_LOG_SECTION, level, text) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 23f01f3a7b..e1a67aff81 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,9 +217,6 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - #ifdef ANDROID - return; - #endif if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index da25502755..fc4706c1f6 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -1,17 +1,11 @@ # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) -if (OPENGLES) - set(SHADER_FILES - watergles_vertex.glsl - watergles_fragment.glsl - water_nm.png - ) -else() - set(SHADER_FILES - water_vertex.glsl - water_fragment.glsl - water_nm.png - ) -endif() + +set(SHADER_FILES + water_vertex.glsl + water_fragment.glsl + water_nm.png +) + copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") diff --git a/files/shaders/watergles_fragment.glsl b/files/shaders/watergles_fragment.glsl deleted file mode 100644 index e3f756087b..0000000000 --- a/files/shaders/watergles_fragment.glsl +++ /dev/null @@ -1,209 +0,0 @@ -#version 100 -precision mediump float; -precision mediump int; - -struct osg_LightSourceParameters { - mediump vec4 ambient; - mediump vec4 diffuse; - mediump vec4 specular; - mediump vec4 position; - mediump vec4 halfVector; - mediump vec3 spotDirection; - mediump float spotExponent; - mediump float spotCutoff; - mediump float spotCosCutoff; - mediump float constantAttenuation; - mediump float linearAttenuation; - mediump float quadraticAttenuation; - }; -uniform osg_LightSourceParameters osg_LightSource[1]; - -#define REFRACTION @refraction_enabled - -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - -// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - -const float VISIBILITY = 1200.0; // how far you can look through water - -const float BIG_WAVES_X = 0.1; // strength of big waves -const float BIG_WAVES_Y = 0.1; - -const float MID_WAVES_X = 0.1; // strength of middle sized waves -const float MID_WAVES_Y = 0.1; - -const float SMALL_WAVES_X = 0.1; // strength of small waves -const float SMALL_WAVES_Y = 0.1; - -const float WAVE_CHOPPYNESS = 0.05; // wave choppyness -const float WAVE_SCALE = 75.0; // overall wave scale - -const float BUMP = 0.5; // overall water surface bumpiness -const float REFL_BUMP = 0.10; // reflection distortion amount -const float REFR_BUMP = 0.07; // refraction distortion amount - -const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering -const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering - -const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction - -const float SPEC_HARDNESS = 256.0; // specular highlights hardness - -const vec2 WIND_DIR = vec2(0.5, -0.8); -const float WIND_SPEED = 0.2; - -const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); - -// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) -{ - 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; - - return result; -} - -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; - -uniform sampler2D normalMap; - -uniform sampler2D reflectionMap; -#if REFRACTION -uniform sampler2D refractionMap; -uniform sampler2D refractionDepthMap; -#endif - -uniform float osg_SimulationTime; - -uniform float near; -uniform float far; -uniform vec3 nodePosition; - -void main(void) -{ - vec3 worldPos = position.xyz + nodePosition.xyz; - vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; - UV.y *= -1.0; - - float shadow = 1.0; - - vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; - screenCoords.y = (1.0-screenCoords.y); - - vec2 nCoord = vec2(0.0,0.0); - - #define waterTimer osg_SimulationTime - - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; - vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; - vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; - vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+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; - vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-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; - vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - - - vec3 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); - - normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); - - normal = vec3(-normal.x, -normal.y, normal.z); - - // normal for sunlight scattering - vec3 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).xyz; - lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); - lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); - - - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(osg_LightSource[0].position.xyz, 0.0)).xyz); - - vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0)).xyz; - vec3 vVec = normalize(position.xyz - cameraPos.xyz); - - float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - - // sunlight scattering - vec3 pNormal = vec3(0.0,0.0,1.0); - vec3 lR = reflect(lVec, lNormal); - vec3 llR = reflect(lVec, pNormal); - - float sunHeight = lVec.z; - float sunFade = length(gl_LightModel.ambient.xyz); - - float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); - float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); - - // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air - float fresnel = fresnel_dielectric(vVec, normal, ior); - - fresnel = clamp(fresnel, 0.0, 1.0); - - // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; - - // refraction -#if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; - - // brighten up the refraction underwater - refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; -#endif - - // specular - vec3 R = reflect(vVec, normal); - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; - - vec3 waterColor = WATER_COLOR; - waterColor = waterColor * length(gl_LightModel.ambient.xyz); -#if REFRACTION - float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - - float waterDepth = refractionDepth - depthPassthrough; - - if (cameraPos.z > 0.0) - refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); - - gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * osg_LightSource[0].specular.xyz; -#else - gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * osg_LightSource[0].specular.xyz; -#endif - - // fog - float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); - gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); - -#if REFRACTION - gl_FragData[0].w = 1.0; -#else - gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endif -} diff --git a/files/shaders/watergles_vertex.glsl b/files/shaders/watergles_vertex.glsl deleted file mode 100644 index 71cc9718b8..0000000000 --- a/files/shaders/watergles_vertex.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 100 -precision mediump float; -precision mediump int; - -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; - -void main(void) -{ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - - 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); - - vec4 texcoordProj = ((scalemat) * ( gl_Position)); - screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); - - position = gl_Vertex; - - depthPassthrough = gl_Position.z; -} From fa610c447c7325963b537be1cec7ce02d3c6fb47 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 17:42:10 -0500 Subject: [PATCH 1470/1812] Fix typos. Add "e.g." in places where ranges are only recommmendations. Add more factual limits where that's easy. --- files/settings-default.cfg | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5ed2d688d5..cab6e7c4a1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,6 +1,6 @@ # WARNING: If this file is named settings-default.cfg, then editing # this file might have no effect, as these settings may be overwritten -# by your user settings.cfg file (see docmentation for its location). +# by your user settings.cfg file (see documentation for its location). # # This file provides minimal documentation for each setting, and # ranges of recommended values. For detailed explanations of the @@ -13,13 +13,13 @@ [Camera] -# Near clipping plane (0.01 to 18.0). +# Near clipping plane (>0.0, e.g. 0.01 to 18.0). near clip = 5.0 # Cull objects smaller than one pixel. small feature culling = true -# Maximum visible distance (2000.0 to 6666.0+). Caution: this setting +# Maximum visible distance (e.g. 2000.0 to 6666.0). Caution: this setting # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 @@ -31,25 +31,24 @@ exterior cell load distance = 1 [Map] -# Size of each exterior cell in pixels in the world map. (12 to 24). +# Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). # Warning: affects explored areas in save files, see documentation. global map cell size = 18 # Zoom level in pixels for HUD map widget. 64 is one cell, 128 is 1/4 -# cell, 256 is 1/8 cell. See documentation for details. (64 to 256). +# cell, 256 is 1/8 cell. See documentation for details. (e.g. 64 to 256). local map hud widget size = 256 # Resolution of local map in GUI window in pixels. See documentation -# for details which may affect cell load performance. (128 to 1024). +# for details which may affect cell load performance. (e.g. 128 to 1024). local map resolution = 256 -# Size of local map in GUI window in pixels. See documentation for -# details which may affect cell load performance. (256 to 1024). +# Size of local map in GUI window in pixels. (e.g. 256 to 1024). local map widget size = 512 [GUI] -# Scales GUI window and widget size. (<1 is smaller, >1 is larger). +# Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger). scaling factor = 1.0 # Transparency of GUI windows (0.0 to 1.0, transparent to opaque). @@ -89,7 +88,7 @@ show owned = 0 # Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false -# Difficulty. Expressed as damage dealt and received. (-100 to 100). +# Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100). difficulty = 0 # Show duration of magic effect and lights in the spells window. @@ -97,10 +96,10 @@ show effect duration = false [General] -# Anisotropy reduces distortion in textures at low angles (0 to 16). +# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). anisotropy = 4 -# Camera field of view in degrees (30.0 to 110.0). +# Camera field of view in degrees (e.g. 30.0 to 110.0). field of view = 55.0 # File format for screenshots. (jpg, png, tga, and possibly more). @@ -123,11 +122,11 @@ always run = false # Zoom in and out from player in third person view with mouse wheel. allow third person zoom = false -# Camera sensitivity when not in GUI mode. (0.1 to 5.0). +# Camera sensitivity when not in GUI mode. (>0.0, e.g. 0.1 to 5.0). camera sensitivity = 1.0 # Vertical camera sensitivity multiplier when not in GUI mode. -# Because it's a multiplier values should be near one (0.5 to 1.5). +# (>0.0, Because it's a multiplier values should be near 1.0) camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. @@ -168,7 +167,7 @@ voice volume = 0.8 [Video] -# Resolution of the Open window or screen. +# Resolution of the OpenMW window or screen. resolution x = 800 resolution y = 600 @@ -190,13 +189,13 @@ antialiasing = 0 # Enable vertical syncing to reduce tearing defects. vsync = false -# Maximum frames per second. (1.0 to 200.0). +# Maximum frames per second. 0.0 is unlimited, or >0.0 to limit. framerate limit = 0.0 # Game video contrast. (>0.0). No effect in Linux. contrast = 1.0 -# Video gamma setting. (>0.0). No effect in Linux. +# Video gamma setting. (>0.0). No effect in Linux. gamma = 1.0 [Water] @@ -228,7 +227,7 @@ distant land = false # Enable shadows. Other shadow settings disabled if false. Unused. enabled = false -# Size of the shadow textures in pixels. Unused. (256 to 2048). +# Size of the shadow textures in pixels. Unused. (e.g. 256 to 2048). texture size = 1024 # Actors cast shadows. Unused. From ad5eaaa705dcb1fe6ffe29e7be5fcf71c16c5889 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Wed, 25 Nov 2015 21:30:04 -0500 Subject: [PATCH 1471/1812] Update the OpenMW Launcher so that it only writes changed values to the user settings.cfg file. Add a helpful header to the top of new settings.cfg files. Remove old code involve whitespace management that didn't work correctly anayway, and doesn't matter since we're not adding comments to the file. Remove "automatically generated" comments. --- apps/launcher/graphicspage.cpp | 50 ++++++++++++++++++++++++-------- apps/launcher/graphicspage.hpp | 1 + components/settings/settings.cpp | 35 +++++++--------------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index a3bfbe5db0..d7f045f80e 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -80,6 +80,8 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; + mInitialSettings = mEngineSettings; + if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -117,29 +119,53 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - mEngineSettings.setBool("vsync", "Video", vSyncCheckBox->checkState()); - mEngineSettings.setBool("fullscreen", "Video", fullScreenCheckBox->checkState()); - mEngineSettings.setBool("window border", "Video", windowBorderCheckBox->checkState()); + bool iVSync = mInitialSettings.getBool("vsync", "Video"); + bool cVSync = vSyncCheckBox->checkState(); + if (iVSync != cVSync) + mEngineSettings.setBool("vsync", "Video", cVSync); + bool iFullScreen = mInitialSettings.getBool("fullscreen", "Video"); + bool cFullScreen = fullScreenCheckBox->checkState(); + if (iFullScreen != cFullScreen) + mEngineSettings.setBool("fullscreen", "Video", cFullScreen); + + bool iWindowBorder = mInitialSettings.getBool("window border", "Video"); + bool cWindowBorder = windowBorderCheckBox->checkState(); + if (iWindowBorder != cWindowBorder) + mEngineSettings.setBool("window border", "Video", cWindowBorder); + + int iAAValue = mInitialSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. - int aaValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); - mEngineSettings.setInt("antialiasing", "Video", aaValue); + int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + if (iAAValue != cAAValue) + mEngineSettings.setInt("antialiasing", "Video", cAAValue); + int cWidth = 0; + int cHeight = 0; if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { // The atoi() call is safe because the pull down constrains the string values. - int width = atoi(resolutionRe.cap(1).toLatin1().data()); - int height = atoi(resolutionRe.cap(2).toLatin1().data()); - mEngineSettings.setInt("resolution x", "Video", width); - mEngineSettings.setInt("resolution y", "Video", height); + cWidth = atoi(resolutionRe.cap(1).toLatin1().data()); + cHeight = atoi(resolutionRe.cap(2).toLatin1().data()); } } else { - mEngineSettings.setInt("resolution x", "Video", customWidthSpinBox->value()); - mEngineSettings.setInt("resolution y", "Video", customHeightSpinBox->value()); + cWidth = customWidthSpinBox->value(); + cHeight = customHeightSpinBox->value(); } - mEngineSettings.setInt("screen", "Video", screenComboBox->currentIndex()); + int iWidth = mInitialSettings.getInt("resolution x", "Video"); + if (iWidth != cWidth) + mEngineSettings.setInt("resolution x", "Video", cWidth); + + int iHeight = mInitialSettings.getInt("resolution y", "Video"); + if (iHeight != cHeight) + mEngineSettings.setInt("resolution y", "Video", cHeight); + + int iScreen = mInitialSettings.getInt("screen", "Video"); + int cScreen = screenComboBox->currentIndex(); + if (iScreen != cScreen) + mEngineSettings.setInt("screen", "Video", cScreen); } QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index e6eb53a3b7..0958f07dae 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -33,6 +33,7 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; Settings::Manager &mEngineSettings; + Settings::Manager mInitialSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index c72e1ace42..acad1a98e8 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -131,9 +131,7 @@ public: // Have we substantively changed the settings file? bool changed = false; - // Was there anything in the existing file? This is intended to permit the deletion of - // the settings.cfg file and it's automatic recreation -- a feature not currently - // supported elsewhere in the code. + // Were there any lines at all in the file? bool existing = false; // The category/section we're currently in. @@ -145,7 +143,6 @@ public: boost::filesystem::ifstream istream; boost::filesystem::path ipath(file); istream.open(ipath); - //std::cout << "Reading previous settings file: " << ipath << std::endl; // Create a new string stream to write the current settings to. It's likely that the // input file and the output file are the same, so this stream serves as a temporary file @@ -190,19 +187,13 @@ public: // Ensure that all options in the current category have been written. for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { - bool missed = false; if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << currentCategory << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. - ostream << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; - missed = true; changed = true; } - // Ensure that there's a newline before the next section if we added settings. - if (missed) ostream << std::endl; } // Update the current category. @@ -223,7 +214,7 @@ public: if (!skipWhiteSpace(i, line)) continue; - // If we'cve found settings befor ethe first category, something's wrong. This + // If we've found settings before the first category, something's wrong. This // should never happen unless the player edited the file while playing, since // the loadSettingsFile() logic rejects it. if (currentCategory.empty()) { @@ -286,27 +277,24 @@ public: // Ensure that all options in the current category have been written. We must complete // the current category at the end of the file before moving on to any new categories. for (CategorySettingStatusMap::iterator mit = written.begin(); mit != written.end(); ++mit) { - bool missed = false; if (mit->second == false && mit->first.first == currentCategory) { std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; - // With some further code changes, this comment could be more descriptive. - ostream << std::endl << "# Automatically added setting." << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; mit->second = true; - missed = true; changed = true; } - // Ensure that there's a newline before the next section if we added settings. - if (missed) ostream << std::endl; } - // This logic triggers when the input file was effectively empty. It could be extended - // to doing something more intelligent instead, like make a copy of the default settings - // file (complete with comments) before continuing. Other code prevents OpenMW from - // executing to this point with a missing config file. + // If there was absolutely nothing in the file (or more likely the file didn't + // exist), start the newly created file with a helpful comment. if (!existing) { - ostream << "# This file was automatically generated." << std::endl << std::endl; + ostream << "# This is the OpenMW user 'settings.cfg' file. This file only contains" << std::endl; + ostream << "# explicitly changed settings. If you would like to revert a setting" << std::endl; + ostream << "# to its default, simply remove it from this file. For available" << std::endl; + ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; + ostream << "#" << std::endl; + ostream << "# https://wiki.openmw.org/index.php?title=Settings" << std::endl; } // We still have one more thing to do before we're completely done writing the file. @@ -321,14 +309,11 @@ public: currentCategory = mit->first.first; std::cout << "Created new setting section: " << mit->first.first << std::endl; ostream << std::endl; - // Add new category comments only if we're amending an existing file. - if (existing) ostream << "# Automatically added category." << std::endl; ostream << "[" << currentCategory << "]" << std::endl; } std::cout << "Added new setting: [" << mit->first.first << "] " << mit->first.second << " = " << settings[mit->first] << std::endl; // Then write the setting. No need to mark it as written because we're done. - ostream << std::endl; ostream << mit->first.second << " = " << settings[mit->first] << std::endl; changed = true; } From 046538984c580c2dcf93920b67c9761b96ee987a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 01:49:14 -0500 Subject: [PATCH 1472/1812] Fix duplicate filename in what() message. Use newly create cfgError utility function consistently throughout code. --- apps/launcher/maindialog.cpp | 102 +++++++++++++---------------------- 1 file changed, 38 insertions(+), 64 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 1c56a9efd8..6453beacc2 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -24,6 +24,15 @@ using namespace Process; +void cfgError(const QString& title, const QString& msg) { + QMessageBox msgBox; + msgBox.setWindowTitle(title); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(msg); + msgBox.exec(); +} + Launcher::MainDialog::MainDialog(QWidget *parent) : QMainWindow(parent), mGameSettings (mCfgMgr) { @@ -261,14 +270,10 @@ bool Launcher::MainDialog::setupLauncherSettings() QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -296,14 +301,10 @@ bool Launcher::MainDialog::setupGameSettings() if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -324,14 +325,10 @@ bool Launcher::MainDialog::setupGameSettings() QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open %0 for reading

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); + cfgError(tr("Error opening OpenMW configuration file"), + tr("
    Could not open %0 for reading

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); return false; } QTextStream stream(&file); @@ -381,15 +378,6 @@ bool Launcher::MainDialog::setupGameSettings() return true; } -void cfgError(const QString& title, const QString& msg) { - QMessageBox msgBox; - msgBox.setWindowTitle(title); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(msg); - msgBox.exec(); -} - bool Launcher::MainDialog::setupGraphicsSettings() { // This method is almost a copy of OMW::Engine::loadSettings(). They should definitely @@ -420,8 +408,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.loadDefault(defaultPath); } catch (std::exception& e) { - std::string msg = "
    Error reading settings-default.cfg

    " + - defaultPath + "

    " + e.what(); + std::string msg = std::string("
    Error reading settings-default.cfg

    ") + e.what(); cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); return false; } @@ -435,8 +422,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() mEngineSettings.loadUser(userPath); } catch (std::exception& e) { - std::string msg = "
    Error reading settings-default.cfg

    " + - defaultPath + "

    " + e.what(); + std::string msg = std::string("
    Error reading settings.cfg

    ") + e.what(); cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); return false; } @@ -487,15 +473,11 @@ bool Launcher::MainDialog::writeSettings() if (!dir.exists()) { if (!dir.mkpath(userPath)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not create %0

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(userPath)); - msgBox.exec(); - return false; + cfgError(tr("Error creating OpenMW configuration directory"), + tr("
    Could not create %0

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(userPath)); + return false; } } @@ -504,15 +486,11 @@ bool Launcher::MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + cfgError(tr("Error writing OpenMW configuration file"), + tr("
    Could not open or create %0 for writing

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); + return false; } @@ -536,15 +514,11 @@ bool Launcher::MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error writing Launcher configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
    Could not open or create %0 for writing

    \ - Please make sure you have the right permissions \ - and try again.
    ").arg(file.fileName())); - msgBox.exec(); - return false; + cfgError(tr("Error writing Launcher configuration file"), + tr("
    Could not open or create %0 for writing

    \ + Please make sure you have the right permissions \ + and try again.
    ").arg(file.fileName())); + return false; } QTextStream stream(&file); From 8715add72fdff41b1d5d574f15545f747f707f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 01:26:33 -0800 Subject: [PATCH 1473/1812] Store sound buffers in a deque that's filled in as needed A deque allows existing Sound_Buffer references to remain valid as long as new ones are back-inserted. These references can be used instead of indices. --- apps/openmw/mwsound/soundmanagerimp.cpp | 159 +++++++++--------------- apps/openmw/mwsound/soundmanagerimp.hpp | 29 +++-- 2 files changed, 73 insertions(+), 115 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c7e5047701..f19f298e17 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -119,15 +119,8 @@ namespace MWSound return DecoderPtr(new DEFAULT_DECODER (mVFS)); } - void SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) + Sound_Buffer *SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - { - std::cerr<< "Duplicate sound record \""<getStore().get().find("fAudioDefaultMinDistance")->getFloat(); static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); @@ -152,64 +145,40 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx; - bufkey = mBufferKeys.insert(bufkey, soundId); - try { - BufferKeyList::difference_type id; - id = std::distance(mBufferKeys.begin(), bufkey); - mSoundBuffers.insert(mSoundBuffers.begin()+id, - Sound_Buffer("Sound/"+sound->mSound, volume, min, max) - ); - sfx = &mSoundBuffers[id]; - } - catch(...) { - mBufferKeys.erase(bufkey); - throw; - } - + Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + ); mVFS->normalizeFilename(sfx->mResourceName); + + mBufferNameMap.insert(std::make_pair(soundId, sfx)); + + return sfx; } - size_t SoundManager::lookupId(const std::string &soundId) + // Lookup a soundId for its sound data (resource name, local volume, + // minRange, and maxRange) + Sound_Buffer *SoundManager::lookupSound(const std::string &soundId) const { - BufferKeyList::iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); + NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); + if(snd != mBufferNameMap.end()) return snd->second; + return 0; + } - if(mBufferKeys.empty()) + // Lookup a soundId for its sound data (resource name, local volume, + // minRange, and maxRange), and ensure it's ready for use. + Sound_Buffer *SoundManager::loadSound(const std::string &soundId) + { + Sound_Buffer *sfx; + NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); + if(snd != mBufferNameMap.end()) + sfx = snd->second; + else { MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Store::iterator iter = world->getStore().get().begin(); - MWWorld::Store::iterator end = world->getStore().get().end(); - size_t storesize = world->getStore().get().getSize(); - mBufferKeys.reserve(storesize); - mSoundBuffers.reserve(storesize); - for(;iter != end;++iter) - insertSound(Misc::StringUtils::lowerCase(iter->mId), &*iter); - - bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); + const ESM::Sound *sound = world->getStore().get().find(soundId); + sfx = insertSound(soundId, sound); } - throw std::runtime_error("Sound "+soundId+" not found"); - } - - size_t SoundManager::lookupId(const std::string& soundId) const - { - BufferKeyList::const_iterator bufkey = std::lower_bound(mBufferKeys.begin(), mBufferKeys.end(), soundId); - if(bufkey != mBufferKeys.end() && *bufkey == soundId) - return std::distance(mBufferKeys.begin(), bufkey); - - throw std::runtime_error("Sound "+soundId+" not found"); - } - - // Lookup a sfxid for its sound data (resource name, local volume, - // minRange, and maxRange). - Sound_Buffer *SoundManager::lookup(size_t sfxid) - { - Sound_Buffer *sfx = &mSoundBuffers[sfxid]; - if(!sfx->mHandle) { sfx->mHandle = mOutput->loadSound(sfx->mResourceName); @@ -223,7 +192,7 @@ namespace MWSound std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); mOutput->unloadSound(unused->mHandle); @@ -231,19 +200,12 @@ namespace MWSound mUnusedBuffers.pop_back(); } - mUnusedBuffers.push_front(sfxid); + mUnusedBuffers.push_front(sfx); } return sfx; } - // Lookup a soundid for its sound data (resource name, local volume, - // minRange, and maxRange). - Sound_Buffer *SoundManager::lookup(const std::string &soundId) - { - return lookup(lookupId(soundId)); - } - DecoderPtr SoundManager::loadVoice(const std::string &voicefile) { DecoderPtr decoder = getDecoder(); @@ -511,8 +473,7 @@ namespace MWSound return sound; try { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, @@ -520,11 +481,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -542,8 +503,7 @@ namespace MWSound try { // Look up the sound in the ESM data - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -556,11 +516,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[ptr].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -578,8 +538,7 @@ namespace MWSound try { // Look up the sound in the ESM data - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - Sound_Buffer *sfx = lookup(sfxid); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, @@ -587,11 +546,11 @@ namespace MWSound ); if(sfx->mUses++ == 0) { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfxid); + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfxid)); + mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception &) { @@ -605,11 +564,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->stop(); } } @@ -620,7 +579,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) sndidx->first->stop(); } @@ -635,7 +594,7 @@ namespace MWSound snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) sndidx->first->stop(); } @@ -659,11 +618,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->stop(); } } @@ -675,11 +634,11 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid) + if(sndidx->second == sfx) sndidx->first->setFadeout(duration); } } @@ -690,11 +649,11 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - size_t sfxid = lookupId(Misc::StringUtils::lowerCase(soundId)); - SoundIndexPairList::const_iterator sndidx = snditer->second.begin(); + Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); + SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfxid && sndidx->first->isPlaying()) + if(sndidx->second == sfx && sndidx->first->isPlaying()) return true; } } @@ -825,14 +784,14 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { if(!updateSound(sndidx->first, snditer->first, duration)) { - Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; + Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) - mUnusedBuffers.push_front(sndidx->second); + mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); } else @@ -916,7 +875,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { MWBase::SoundPtr sound = sndidx->first; @@ -956,7 +915,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundIndexPairList sndlist = snditer->second; + SoundBufferRefPairList sndlist = snditer->second; mActiveSounds.erase(snditer); mActiveSounds[updated] = sndlist; } @@ -1039,13 +998,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); for(;snditer != mActiveSounds.end();++snditer) { - SoundIndexPairList::iterator sndidx = snditer->second.begin(); + SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { sndidx->first->stop(); - Sound_Buffer *sfx = &mSoundBuffers[sndidx->second]; + Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) - mUnusedBuffers.push_front(sndidx->second); + mUnusedBuffers.push_front(sfx); } } mActiveSounds.clear(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 15fdd86cf2..cdf35189fd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -51,28 +51,29 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::vector BufferKeyList; - typedef std::vector SoundBufferList; - // Each mBufferKeys index has a corresponding entry in mSoundBuffers. - // That is, if string "foo" is at index 10 in mBufferKeys, index 10 in - // mSoundBuffers contains the Sound_Buffer for "foo". - BufferKeyList mBufferKeys; + typedef std::deque SoundBufferList; + // List of sound buffers, grown as needed. New enties are added to the + // back, allowing existing Sound_Buffer references/pointers to remain + // valid. SoundBufferList mSoundBuffers; size_t mBufferCacheSize; + typedef std::map NameBufferMap; + NameBufferMap mBufferNameMap; + typedef std::map NameLoudnessMap; NameLoudnessMap mVoiceLipBuffers; // NOTE: unused buffers are stored in front-newest order. - typedef std::deque SoundList; + typedef std::deque SoundList; SoundList mUnusedBuffers; boost::shared_ptr mMusic; std::string mCurrentPlaylist; - typedef std::pair SoundIndexPair; - typedef std::vector SoundIndexPairList; - typedef std::map SoundMap; + typedef std::pair SoundBufferRefPair; + typedef std::vector SoundBufferRefPairList; + typedef std::map SoundMap; SoundMap mActiveSounds; typedef std::pair SoundNamePair; @@ -88,12 +89,10 @@ namespace MWSound int mPausedSoundTypes; - void insertSound(const std::string &soundId, const ESM::Sound *sound); + Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); - size_t lookupId(const std::string &soundId); - size_t lookupId(const std::string &soundId) const; - Sound_Buffer *lookup(size_t sfxid); - Sound_Buffer *lookup(const std::string &soundId); + Sound_Buffer *lookupSound(const std::string &soundId) const; + Sound_Buffer *loadSound(const std::string &soundId); // Ensures the loudness/"lip" data is loaded, and returns a decoder to // start streaming From d4238a6d91e9c804e298be8a5b304c0708e0fa03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 02:13:37 -0800 Subject: [PATCH 1474/1812] Add config options for the sound buffer cache size The cache size is specified with a min/max range, intended to avoid constant unloading once the limit is reached. This way, buffers can be unloaded down to a reasonable mimimum, allowing some more buffers to be subsequently loaded without causing more unloading. --- apps/openmw/mwsound/soundmanagerimp.cpp | 30 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ files/settings-default.cfg | 9 ++++++++ 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f19f298e17..4d0c7912cd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -66,6 +66,11 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); + mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); + mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); + mBufferCacheMax *= 1024*1024; + mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; @@ -184,21 +189,22 @@ namespace MWSound sfx->mHandle = mOutput->loadSound(sfx->mResourceName); mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); - // NOTE: Max sound buffer cache size is 15MB. Make configurable? - while(mBufferCacheSize > 15*1024*1024) + if(mBufferCacheSize > mBufferCacheMax) { - if(mUnusedBuffers.empty()) - { - std::cerr<< "No unused sound buffers to free, using "<getSoundDataSize(unused->mHandle); - mOutput->unloadSound(unused->mHandle); - unused->mHandle = 0; + mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); + mOutput->unloadSound(unused->mHandle); + unused->mHandle = 0; - mUnusedBuffers.pop_back(); + mUnusedBuffers.pop_back(); + } while(mBufferCacheSize > mBufferCacheMin); } mUnusedBuffers.push_front(sfx); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index cdf35189fd..38bad2194e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,6 +56,8 @@ namespace MWSound // back, allowing existing Sound_Buffer references/pointers to remain // valid. SoundBufferList mSoundBuffers; + size_t mBufferCacheMin; + size_t mBufferCacheMax; size_t mBufferCacheSize; typedef std::map NameBufferMap; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index cab6e7c4a1..7d0292c5ba 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -165,6 +165,15 @@ sfx volume = 1.0 # Voice dialog volume. voice volume = 0.8 +# Minimum size to use for the sound buffer cache, in MB. When the cache is +# filled, old buffers will be unloaded until it's using no more than this much +# memory. Must be less than or equal to 'buffer cache max'. +buffer cache min = 14 + +# Maximum size to use for the sound buffer cache, in MB. The cache can use up +# to this much memory until old buffers get purged. +buffer cache max = 16 + [Video] # Resolution of the OpenMW window or screen. From a9c9cc5508f49dc095fd5e518dab93239646620a Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 10:42:43 -0500 Subject: [PATCH 1475/1812] Remove unnecessary copy of mEngineSettings in mInitialSettings. --- apps/launcher/graphicspage.cpp | 16 +++++++--------- apps/launcher/graphicspage.hpp | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index d7f045f80e..f56c978884 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -80,8 +80,6 @@ bool Launcher::GraphicsPage::loadSettings() if (!setupSDL()) return false; - mInitialSettings = mEngineSettings; - if (mEngineSettings.getBool("vsync", "Video")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -119,22 +117,22 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - bool iVSync = mInitialSettings.getBool("vsync", "Video"); + bool iVSync = mEngineSettings.getBool("vsync", "Video"); bool cVSync = vSyncCheckBox->checkState(); if (iVSync != cVSync) mEngineSettings.setBool("vsync", "Video", cVSync); - bool iFullScreen = mInitialSettings.getBool("fullscreen", "Video"); + bool iFullScreen = mEngineSettings.getBool("fullscreen", "Video"); bool cFullScreen = fullScreenCheckBox->checkState(); if (iFullScreen != cFullScreen) mEngineSettings.setBool("fullscreen", "Video", cFullScreen); - bool iWindowBorder = mInitialSettings.getBool("window border", "Video"); + bool iWindowBorder = mEngineSettings.getBool("window border", "Video"); bool cWindowBorder = windowBorderCheckBox->checkState(); if (iWindowBorder != cWindowBorder) mEngineSettings.setBool("window border", "Video", cWindowBorder); - int iAAValue = mInitialSettings.getInt("antialiasing", "Video"); + int iAAValue = mEngineSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); if (iAAValue != cAAValue) @@ -154,15 +152,15 @@ void Launcher::GraphicsPage::saveSettings() cHeight = customHeightSpinBox->value(); } - int iWidth = mInitialSettings.getInt("resolution x", "Video"); + int iWidth = mEngineSettings.getInt("resolution x", "Video"); if (iWidth != cWidth) mEngineSettings.setInt("resolution x", "Video", cWidth); - int iHeight = mInitialSettings.getInt("resolution y", "Video"); + int iHeight = mEngineSettings.getInt("resolution y", "Video"); if (iHeight != cHeight) mEngineSettings.setInt("resolution y", "Video", cHeight); - int iScreen = mInitialSettings.getInt("screen", "Video"); + int iScreen = mEngineSettings.getInt("screen", "Video"); int cScreen = screenComboBox->currentIndex(); if (iScreen != cScreen) mEngineSettings.setInt("screen", "Video", cScreen); diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 0958f07dae..e6eb53a3b7 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -33,7 +33,6 @@ namespace Launcher private: Files::ConfigurationManager &mCfgMgr; Settings::Manager &mEngineSettings; - Settings::Manager mInitialSettings; QStringList getAvailableResolutions(int screen); QRect getMaximumResolution(); From c26463fd91b90bba390085228712fa7396c997f5 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Thu, 26 Nov 2015 10:52:20 -0500 Subject: [PATCH 1476/1812] Should have coded it the way scrawl said, since it's cleaner. --- apps/launcher/graphicspage.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index f56c978884..bc797574b6 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -117,25 +117,21 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { - bool iVSync = mEngineSettings.getBool("vsync", "Video"); bool cVSync = vSyncCheckBox->checkState(); - if (iVSync != cVSync) + if (cVSync != mEngineSettings.getBool("vsync", "Video")) mEngineSettings.setBool("vsync", "Video", cVSync); - bool iFullScreen = mEngineSettings.getBool("fullscreen", "Video"); bool cFullScreen = fullScreenCheckBox->checkState(); - if (iFullScreen != cFullScreen) + if (cFullScreen != mEngineSettings.getBool("fullscreen", "Video")) mEngineSettings.setBool("fullscreen", "Video", cFullScreen); - bool iWindowBorder = mEngineSettings.getBool("window border", "Video"); bool cWindowBorder = windowBorderCheckBox->checkState(); - if (iWindowBorder != cWindowBorder) + if (cWindowBorder != mEngineSettings.getBool("window border", "Video")) mEngineSettings.setBool("window border", "Video", cWindowBorder); - int iAAValue = mEngineSettings.getInt("antialiasing", "Video"); // The atoi() call is safe because the pull down constrains the string values. int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); - if (iAAValue != cAAValue) + if (cAAValue != mEngineSettings.getInt("antialiasing", "Video")) mEngineSettings.setInt("antialiasing", "Video", cAAValue); int cWidth = 0; @@ -152,17 +148,14 @@ void Launcher::GraphicsPage::saveSettings() cHeight = customHeightSpinBox->value(); } - int iWidth = mEngineSettings.getInt("resolution x", "Video"); - if (iWidth != cWidth) + if (cWidth != mEngineSettings.getInt("resolution x", "Video")) mEngineSettings.setInt("resolution x", "Video", cWidth); - int iHeight = mEngineSettings.getInt("resolution y", "Video"); - if (iHeight != cHeight) + if (cHeight != mEngineSettings.getInt("resolution y", "Video")) mEngineSettings.setInt("resolution y", "Video", cHeight); - int iScreen = mEngineSettings.getInt("screen", "Video"); int cScreen = screenComboBox->currentIndex(); - if (iScreen != cScreen) + if (cScreen != mEngineSettings.getInt("screen", "Video")) mEngineSettings.setInt("screen", "Video", cScreen); } From 3747843c921a20159bc7ab048064c72ceab61480 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:07:20 +0100 Subject: [PATCH 1477/1812] Use QString::toInt instead of atoi --- apps/launcher/graphicspage.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index bc797574b6..523d0bb049 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -129,8 +129,7 @@ void Launcher::GraphicsPage::saveSettings() if (cWindowBorder != mEngineSettings.getBool("window border", "Video")) mEngineSettings.setBool("window border", "Video", cWindowBorder); - // The atoi() call is safe because the pull down constrains the string values. - int cAAValue = atoi(antiAliasingComboBox->currentText().toLatin1().data()); + int cAAValue = antiAliasingComboBox->currentText().toInt(); if (cAAValue != mEngineSettings.getInt("antialiasing", "Video")) mEngineSettings.setInt("antialiasing", "Video", cAAValue); @@ -139,9 +138,8 @@ void Launcher::GraphicsPage::saveSettings() if (standardRadioButton->isChecked()) { QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - // The atoi() call is safe because the pull down constrains the string values. - cWidth = atoi(resolutionRe.cap(1).toLatin1().data()); - cHeight = atoi(resolutionRe.cap(2).toLatin1().data()); + cWidth = resolutionRe.cap(1).toInt(); + cHeight = resolutionRe.cap(2).toInt(); } } else { cWidth = customWidthSpinBox->value(); From 325d208b4a74ce9f1bd976ba76c07f69b9c61525 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:13:13 +0100 Subject: [PATCH 1478/1812] Fix incorrect error message --- apps/launcher/maindialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 6453beacc2..9bf135e7e2 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -505,7 +505,7 @@ bool Launcher::MainDialog::writeSettings() catch (std::exception& e) { std::string msg = "
    Error writing settings.cfg

    " + settingsPath + "

    " + e.what(); - cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str())); + cfgError(tr("Error writing user settings file"), tr(msg.c_str())); return false; } From 84aceedfa26352fd85d2364555e51d744258d287 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:15:12 +0100 Subject: [PATCH 1479/1812] Add comment --- apps/launcher/graphicspage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 523d0bb049..622db4da46 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -117,6 +117,8 @@ bool Launcher::GraphicsPage::loadSettings() void Launcher::GraphicsPage::saveSettings() { + // Ensure we only set the new settings if they changed. This is to avoid cluttering the + // user settings file (which by definition should only contain settings the user has touched) bool cVSync = vSyncCheckBox->checkState(); if (cVSync != mEngineSettings.getBool("vsync", "Video")) mEngineSettings.setBool("vsync", "Video", cVSync); From d894d54e41e7577dc7b54e06613712780a07bd65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:15:28 +0100 Subject: [PATCH 1480/1812] Improve path conversions --- apps/launcher/maindialog.cpp | 8 ++++---- apps/openmw/engine.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 9bf135e7e2..8738dae2ca 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -385,8 +385,8 @@ bool Launcher::MainDialog::setupGraphicsSettings() // the filenames should be in the CfgMgr component. // 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"; + const std::string localDefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); + const std::string globalDefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); std::string defaultPath; // Prefer the settings-default.cfg in the current directory. @@ -414,7 +414,7 @@ bool Launcher::MainDialog::setupGraphicsSettings() } // Load user settings if they exist - const std::string userPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string userPath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); // User settings are not required to exist, so if they don't we're done. if (!boost::filesystem::exists(userPath)) return true; @@ -498,7 +498,7 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Graphics settings - const std::string settingsPath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string settingsPath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); try { mEngineSettings.saveUser(settingsPath); } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a4f5f94407..66231dd987 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -298,8 +298,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // 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"; + 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)) @@ -310,7 +310,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) 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 - const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "settings.cfg"; + const std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); From 2ffcc2a2b4fdd49304c5a7ffc7c6421872413e5c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 17:34:22 +0100 Subject: [PATCH 1481/1812] Fix incorrect path encoding handling in debug message --- apps/launcher/maindialog.cpp | 6 +++--- apps/wizard/mainwizard.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 8738dae2ca..fb1b73c3e7 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -266,7 +266,7 @@ bool Launcher::MainDialog::setupLauncherSettings() paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -297,7 +297,7 @@ bool Launcher::MainDialog::setupGameSettings() QString path = userPath + QLatin1String("openmw.cfg"); QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -320,7 +320,7 @@ bool Launcher::MainDialog::setupGameSettings() paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 7538511fe9..19cdf9535d 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -138,7 +138,7 @@ void Wizard::MainWizard::setupGameSettings() QString path(userPath + QLatin1String("openmw.cfg")); QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -163,7 +163,7 @@ void Wizard::MainWizard::setupGameSettings() paths.append(globalPath + QLatin1String("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); QFile file(path); if (file.exists()) { @@ -197,7 +197,7 @@ void Wizard::MainWizard::setupLauncherSettings() QFile file(path); - qDebug() << "Loading config file:" << qPrintable(path); + qDebug() << "Loading config file:" << path.toUtf8().constData(); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { From 984c4550279907c432791fdeb07161339f3d1e57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 18:22:01 +0100 Subject: [PATCH 1482/1812] Fix Show Owned option affecting tooltips that are not objects (Fixes #3036) --- apps/openmw/mwgui/tooltips.cpp | 18 +++++++++--------- apps/openmw/mwgui/tooltips.hpp | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7c7f951af1..3356698df8 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -87,9 +87,9 @@ namespace MWGui return; } - bool gameMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if (gameMode) + if (guiMode) { const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); @@ -112,7 +112,7 @@ namespace MWGui if (info.caption.empty()) info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, true); } else tooltipSize = getToolTipViaPtr(true); @@ -178,7 +178,7 @@ namespace MWGui ToolTipInfo info; info.text = data.caption; info.notes = data.notes; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, false); } else if (type == "ItemPtr") { @@ -197,7 +197,7 @@ namespace MWGui } else if (type == "ToolTipInfo") { - tooltipSize = createToolTip(*focus->getUserData()); + tooltipSize = createToolTip(*focus->getUserData(), false); } else if (type == "AvatarItemSelection") { @@ -240,7 +240,7 @@ namespace MWGui info.text = "#{sSchool}: " + sSchoolNames[school]; } info.effects = effects; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, false); } else if (type == "Layout") { @@ -345,7 +345,7 @@ namespace MWGui ToolTipInfo info = object.getToolTipInfo(mFocusObject); if (!image) info.icon = ""; - tooltipSize = createToolTip(info); + tooltipSize = createToolTip(info, true); } return tooltipSize; @@ -370,13 +370,13 @@ namespace MWGui } } - MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isFocusObject) { mDynamicToolTipBox->setVisible(true); if(mShowOwned == 1 || mShowOwned == 3) { - if(checkOwned()) + if(isFocusObject && checkOwned()) { mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 983b50fe2f..fa1ae4f886 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -98,8 +98,9 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const ToolTipInfo& info); + MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); ///< @return requested tooltip size + /// @param isFocusObject Is the object this tooltips originates from mFocusObject? float mFocusToolTipX; float mFocusToolTipY; From fbee32729acb8af7e397b927031ac09e605ca84a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 26 Nov 2015 23:46:41 +0100 Subject: [PATCH 1483/1812] Cache CellId ESM::Cell::getCellId() was allocating a string on every call. This caused functions dealing with cellIds to be unnecessarily expensive. For example, World::moveObject spent almost as much time comparing CellIds as it did updating Bullet's AABB after the move. OpGetDistance was by far the most expensive script instruction because it has to compare cellIds. The total cost of getCellId() relative to the frame loop was about 0.3%. --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/esm/loadcell.cpp | 36 ++++++++++++------------- components/esm/loadcell.hpp | 6 +++-- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6a780f2ca7..b76d9eae55 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -475,7 +475,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWWorld::Ptr ptr = MWMechanics::getPlayer(); - ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); + const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId(); // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 8455daeac3..eb9d6b8d8e 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -91,6 +91,21 @@ namespace ESM if (!hasData) esm.fail("Missing DATA subrecord"); + + mCellId.mPaged = !(mData.mFlags & Interior); + + if (mCellId.mPaged) + { + mCellId.mWorldspace = "sys::default"; + mCellId.mIndex.mX = mData.mX; + mCellId.mIndex.mY = mData.mY; + } + else + { + mCellId.mWorldspace = Misc::StringUtils::lowerCase (mName); + mCellId.mIndex.mX = 0; + mCellId.mIndex.mY = 0; + } } void Cell::loadCell(ESMReader &esm, bool saveContext) @@ -266,25 +281,8 @@ namespace ESM mAmbi.mFogDensity = 0; } - CellId Cell::getCellId() const + const CellId& Cell::getCellId() const { - CellId id; - - id.mPaged = !(mData.mFlags & Interior); - - if (id.mPaged) - { - id.mWorldspace = "sys::default"; - id.mIndex.mX = mData.mX; - id.mIndex.mY = mData.mY; - } - else - { - id.mWorldspace = Misc::StringUtils::lowerCase (mName); - id.mIndex.mX = 0; - id.mIndex.mY = 0; - } - - return id; + return mCellId; } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 2a7a78a54a..f92e0b5b70 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -8,6 +8,7 @@ #include "esmcommon.hpp" #include "defs.hpp" #include "cellref.hpp" +#include "cellid.hpp" namespace MWWorld { @@ -18,7 +19,6 @@ namespace ESM { class ESMReader; class ESMWriter; -struct CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another @@ -97,6 +97,8 @@ struct Cell std::vector mContextList; // File position; multiple positions for multiple plugin support DATAstruct mData; + CellId mCellId; + AMBIstruct mAmbi; float mWater; // Water level @@ -173,7 +175,7 @@ struct Cell void blank(); ///< Set record to default state (does not touch the ID/index). - CellId getCellId() const; + const CellId& getCellId() const; }; } #endif From 783594033ad9c7be1461163d4f37b7d03aa423b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 01:02:29 +0100 Subject: [PATCH 1484/1812] Optimize MWMechanics::Spells Use pointers as map keys instead of string IDs. Resolves a nasty performance bottleneck on functions like hasCommonDisease() that previously had to look up all contained spells from the ESM store on every call. hasCommonDisease() is called hundreds of times per frame by the AI target update since it's used to calculate target disposition. The total cost of hasCommonDisease() was 2.7% of the frame loop, now it's negligible. --- apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellcreationdialog.cpp | 3 +- apps/openmw/mwgui/spellmodel.cpp | 6 +- apps/openmw/mwmechanics/aicombataction.cpp | 2 +- apps/openmw/mwmechanics/disease.hpp | 3 +- apps/openmw/mwmechanics/spellcasting.cpp | 4 +- apps/openmw/mwmechanics/spells.cpp | 144 +++++++++++---------- apps/openmw/mwmechanics/spells.hpp | 24 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- 9 files changed, 102 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 8c4520662d..843731cff8 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -95,8 +95,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) { - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + const ESM::Spell* spell = iter->first; if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers @@ -110,10 +109,10 @@ namespace MWGui continue; } - if (playerHasSpell(iter->first)) + if (playerHasSpell(iter->first->mId)) continue; - addSpell (iter->first); + addSpell (iter->first->mId); } updateLabels(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index ff5a27abe2..64d4d86c68 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -516,8 +516,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find (it->first); + const ESM::Spell* spell = it->first; // only normal spells count if (spell->mData.mType != ESM::Spell::ST_Spell) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 58ec057948..0d3b64f78a 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -52,7 +52,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = esmStore.get().find(it->first); + const ESM::Spell* spell = it->first; if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) continue; @@ -67,9 +67,9 @@ namespace MWGui } else newSpell.mType = Spell::Type_Power; - newSpell.mId = it->first; + newSpell.mId = spell->mId; - newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == it->first); + newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == spell->mId); newSpell.mActive = true; mSpells.push_back(newSpell); } diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 33e3c3d679..60446e524d 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -541,7 +541,7 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + const ESM::Spell* spell = it->first; float rating = rateSpell(spell, actor, target); if (rating > bestActionRating) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 27c19364f9..25bde56ab8 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -34,8 +34,7 @@ namespace MWMechanics Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells(); for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); - + const ESM::Spell* spell = it->first; if (actor.getClass().getCreatureStats(actor).getSpells().hasSpell(spell->mId)) continue; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 70d097687e..2485091ea4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -124,7 +124,7 @@ namespace MWMechanics } if (spell->mData.mType == ESM::Spell::ST_Power) - return stats.getSpells().canUsePower(spell->mId) ? 100 : 0; + return stats.getSpells().canUsePower(spell) ? 100 : 0; if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; @@ -823,7 +823,7 @@ namespace MWMechanics // A power can be used once per 24h if (spell->mData.mType == ESM::Spell::ST_Power) - stats.getSpells().usePower(spell->mId); + stats.getSpells().usePower(spell); } if (mCaster == getPlayer() && spellIncreasesSkill(spell)) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 330d78a201..a88b6b2633 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -25,9 +25,24 @@ namespace MWMechanics return mSpells.end(); } + const ESM::Spell* Spells::getSpell(const std::string& id) const + { + return MWBase::Environment::get().getWorld()->getStore().get().find(id); + } + + bool Spells::hasSpell(const std::string &spell) const + { + return hasSpell(getSpell(spell)); + } + + bool Spells::hasSpell(const ESM::Spell *spell) const + { + return mSpells.find(spell) != mSpells.end(); + } + void Spells::add (const ESM::Spell* spell) { - if (mSpells.find (spell->mId)==mSpells.end()) + if (mSpells.find (spell)==mSpells.end()) { std::map random; @@ -48,32 +63,32 @@ namespace MWMechanics corprus.mWorsenings = 0; corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; - mCorprusSpells[spell->mId] = corprus; + mCorprusSpells[spell] = corprus; } - mSpells.insert (std::make_pair (spell->mId, random)); + mSpells.insert (std::make_pair (spell, random)); } } void Spells::add (const std::string& spellId) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - add(spell); + add(getSpell(spellId)); } void Spells::remove (const std::string& spellId) { - std::string lower = Misc::StringUtils::lowerCase(spellId); - TContainer::iterator iter = mSpells.find (lower); - std::map::iterator corprusIt = mCorprusSpells.find(lower); + const ESM::Spell* spell = getSpell(spellId); + TContainer::iterator iter = mSpells.find (spell); + + std::map::iterator corprusIt = mCorprusSpells.find(spell); // if it's corprus, remove negative and keep positive effects if (corprusIt != mCorprusSpells.end()) { - worsenCorprus(lower); - if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end()) + worsenCorprus(spell); + if (mPermanentSpellEffects.find(spell) != mPermanentSpellEffects.end()) { - MagicEffects & effects = mPermanentSpellEffects[lower]; + MagicEffects & effects = mPermanentSpellEffects[spell]; for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();) { const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->first.mId); @@ -101,8 +116,7 @@ namespace MWMechanics for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + const ESM::Spell *spell = iter->first; if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) @@ -120,7 +134,7 @@ namespace MWMechanics } } - for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) + for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) { effects += it->second; } @@ -145,11 +159,10 @@ namespace MWMechanics bool Spells::isSpellActive(const std::string &id) const { - TContainer::const_iterator found = mSpells.find(id); + TContainer::const_iterator found = mSpells.find(getSpell(id)); if (found != mSpells.end()) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (id); + const ESM::Spell *spell = found->first; return (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse); @@ -161,9 +174,7 @@ namespace MWMechanics { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Disease) return true; } @@ -175,9 +186,7 @@ namespace MWMechanics { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Blight) return true; } @@ -189,9 +198,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Disease) mSpells.erase(iter++); else @@ -203,9 +210,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Blight && !hasCorprusEffect(spell)) mSpells.erase(iter++); else @@ -217,9 +222,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (hasCorprusEffect(spell)) mSpells.erase(iter++); else @@ -231,9 +234,7 @@ namespace MWMechanics { for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) { - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - + const ESM::Spell *spell = iter->first; if (spell->mData.mType == ESM::Spell::ST_Curse) mSpells.erase(iter++); else @@ -245,7 +246,7 @@ namespace MWMechanics { for (TIterator it = begin(); it != end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + const ESM::Spell* spell = it->first; // these are the spell types that are permanently in effect if (!(spell->mData.mType == ESM::Spell::ST_Ability) @@ -268,14 +269,13 @@ namespace MWMechanics } } - void Spells::worsenCorprus(const std::string &corpSpellId) + void Spells::worsenCorprus(const ESM::Spell* spell) { - mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; - mCorprusSpells[corpSpellId].mWorsenings++; + mCorprusSpells[spell].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; + mCorprusSpells[spell].mWorsenings++; // update worsened effects - mPermanentSpellEffects[corpSpellId] = MagicEffects(); - const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get().find(corpSpellId); + mPermanentSpellEffects[spell] = MagicEffects(); int i=0; for (std::vector::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i) { @@ -283,12 +283,12 @@ namespace MWMechanics if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE { float random = 1.f; - if (mSpells[corpSpellId].find(i) != mSpells[corpSpellId].end()) - random = mSpells[corpSpellId].at(i); + if (mSpells[spell].find(i) != mSpells[spell].end()) + random = mSpells[spell].at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - magnitude *= std::max(1, mCorprusSpells[corpSpellId].mWorsenings); - mPermanentSpellEffects[corpSpellId].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude)); + magnitude *= std::max(1, mCorprusSpells[spell].mWorsenings); + mPermanentSpellEffects[spell].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude)); } } } @@ -305,43 +305,47 @@ namespace MWMechanics return false; } - const std::map &Spells::getCorprusSpells() const + const std::map &Spells::getCorprusSpells() const { return mCorprusSpells; } - bool Spells::canUsePower(const std::string &power) const + bool Spells::canUsePower(const ESM::Spell* spell) const { - std::map::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power)); + std::map::const_iterator it = mUsedPowers.find(spell); if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) return true; else return false; } - void Spells::usePower(const std::string &power) + void Spells::usePower(const ESM::Spell* spell) { - mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp(); + mUsedPowers[spell] = MWBase::Environment::get().getWorld()->getTimeStamp(); } void Spells::readState(const ESM::SpellState &state) { - for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) + for (ESM::SpellState::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) { // Discard spells that are no longer available due to changed content files const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); if (spell) { - mSpells[it->first] = it->second; + mSpells[spell] = it->second; if (it->first == state.mSelectedSpell) mSelectedSpell = it->first; } } - // No need to discard spells here (doesn't really matter if non existent ids are kept) for (std::map::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it) - mUsedPowers[it->first] = MWWorld::TimeStamp(it->second); + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell) + continue; + mUsedPowers[spell] = MWWorld::TimeStamp(it->second); + } for (std::map >::const_iterator it = state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it) @@ -350,33 +354,35 @@ namespace MWMechanics if (!spell) continue; - mPermanentSpellEffects[it->first] = MagicEffects(); + mPermanentSpellEffects[spell] = MagicEffects(); for (std::vector::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) { - mPermanentSpellEffects[it->first].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude); + mPermanentSpellEffects[spell].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude); } } mCorprusSpells.clear(); for (std::map::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it) { - if (mSpells.find(it->first) != mSpells.end()) // Discard unavailable corprus spells - { - mCorprusSpells[it->first].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings; - mCorprusSpells[it->first].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening); - } + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell) // Discard unavailable corprus spells + continue; + mCorprusSpells[spell].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings; + mCorprusSpells[spell].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening); } } void Spells::writeState(ESM::SpellState &state) const { - state.mSpells = mSpells; + for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it) + state.mSpells.insert(std::make_pair(it->first->mId, it->second)); + state.mSelectedSpell = mSelectedSpell; - for (std::map::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) - state.mUsedPowers[it->first] = it->second.toEsm(); + for (std::map::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) + state.mUsedPowers[it->first->mId] = it->second.toEsm(); - for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) + for (std::map::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) { std::vector effectList; for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) @@ -388,13 +394,13 @@ namespace MWMechanics effectList.push_back(info); } - state.mPermanentSpellEffects[it->first] = effectList; + state.mPermanentSpellEffects[it->first->mId] = effectList; } - for (std::map::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) + for (std::map::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) { - state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings; - state.mCorprusSpells[it->first].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm(); + state.mCorprusSpells[it->first->mId].mWorsenings = mCorprusSpells.at(it->first).mWorsenings; + state.mCorprusSpells[it->first->mId].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm(); } } } diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 6b41499395..1b1993d5ef 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -31,7 +31,9 @@ namespace MWMechanics { public: - typedef std::map > TContainer; // ID, + typedef const ESM::Spell* SpellKey; + + typedef std::map > TContainer; // ID, typedef TContainer::const_iterator TIterator; struct CorprusStats @@ -47,23 +49,26 @@ namespace MWMechanics TContainer mSpells; // spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed) - std::map mPermanentSpellEffects; + std::map mPermanentSpellEffects; // Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different) std::string mSelectedSpell; - std::map mUsedPowers; + std::map mUsedPowers; - std::map mCorprusSpells; + std::map mCorprusSpells; + + /// Get spell from ID, throws exception if not found + const ESM::Spell* getSpell(const std::string& id) const; public: - void worsenCorprus(const std::string &corpSpellId); + void worsenCorprus(const ESM::Spell* spell); static bool hasCorprusEffect(const ESM::Spell *spell); - const std::map & getCorprusSpells() const; + const std::map & getCorprusSpells() const; - bool canUsePower (const std::string& power) const; - void usePower (const std::string& power); + bool canUsePower (const ESM::Spell* spell) const; + void usePower (const ESM::Spell* spell); void purgeCommonDisease(); void purgeBlightDisease(); @@ -74,7 +79,8 @@ namespace MWMechanics TIterator end() const; - bool hasSpell(const std::string& spell) const { return mSpells.find(Misc::StringUtils::lowerCase(spell)) != mSpells.end(); } + bool hasSpell(const std::string& spell) const; + bool hasSpell(const ESM::Spell* spell) const; void add (const std::string& spell); ///< Adding a spell that is already listed in *this is a no-op. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index df2e577d16..03a64bce86 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2581,7 +2581,7 @@ namespace MWWorld } // If this is a power, check if it was already used in the last 24h - if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell->mId)) + if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell)) { message = "#{sPowerAlreadyUsed}"; fail = true; From 44dd62067e31ab32745e148aa4a353146c7a356c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 02:10:10 +0100 Subject: [PATCH 1485/1812] Remove some unnecessary per-frame store searches --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/creaturestats.cpp | 6 ++++-- apps/openmw/mwworld/worldimp.cpp | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 59f8ecbc0f..02b73bff7c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -838,7 +838,7 @@ namespace MWMechanics if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.getAiSequence().isInCombat()) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); + static const int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); // Force dialogue on sight if bounty is greater than the cutoff // In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty) if ( player.getClass().getNpcStats(player).getBounty() >= cutoff @@ -846,7 +846,7 @@ namespace MWMechanics && MWBase::Environment::get().getWorld()->getLOS(ptr, player) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) { - static int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); + static const int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier) MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); else diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 0638637fa5..602e54a090 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -48,8 +48,10 @@ namespace MWMechanics const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - return gmst.find ("fFatigueBase")->getFloat() - - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); + static const float fFatigueBase = gmst.find("fFatigueBase")->getFloat(); + static const float fFatigueMult = gmst.find("fFatigueMult")->getFloat(); + + return fFatigueBase - fFatigueMult * (1-normalised); } const AttributeValue &CreatureStats::getAttribute(int index) const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index df2e577d16..896e95ec6e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1009,7 +1009,8 @@ namespace MWWorld if (mActivationDistanceOverride >= 0) return static_cast(mActivationDistanceOverride); - return getStore().get().find("iMaxActivateDist")->getFloat() * 5 / 4; + static const int iMaxActivateDist = getStore().get().find("iMaxActivateDist")->getInt(); + return iMaxActivateDist * 5.f / 4.f; } MWWorld::Ptr World::getFacedObject() From 27e669296e54621472ed5578103ad4306f8a94a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 03:22:52 +0100 Subject: [PATCH 1486/1812] StringUtils: use the locale-unaware tolower function There is no change in behaviour since we were using the C locale. The locale-aware tolower is much slower than the locale-unaware one. At least on Linux/GCC it calls dynamic_cast's, and is overall slower by an order of magnitude. --- components/misc/stringops.cpp | 8 -------- components/misc/stringops.hpp | 11 ++++------- 2 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 components/misc/stringops.cpp diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp deleted file mode 100644 index 723c1c1e0b..0000000000 --- a/components/misc/stringops.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "stringops.hpp" - -namespace Misc -{ - -std::locale StringUtils::mLocale = std::locale::classic(); - -} diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 04dedb0721..d6bc190695 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -4,18 +4,15 @@ #include #include #include -#include namespace Misc { class StringUtils { - - static std::locale mLocale; struct ci { bool operator()(char x, char y) const { - return std::tolower(x, StringUtils::mLocale) < std::tolower(y, StringUtils::mLocale); + return tolower(x) < tolower(y); } }; @@ -31,7 +28,7 @@ public: std::string::const_iterator xit = x.begin(); std::string::const_iterator yit = y.begin(); for (; xit != x.end(); ++xit, ++yit) { - if (std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) { + if (tolower(*xit) != tolower(*yit)) { return false; } } @@ -45,7 +42,7 @@ public: for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len) { int res = *xit - *yit; - if(res != 0 && std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) + if(res != 0 && tolower(*xit) != tolower(*yit)) return (res > 0) ? 1 : -1; } if(len > 0) @@ -61,7 +58,7 @@ public: /// Transforms input string to lower case w/o copy static std::string &toLower(std::string &inout) { for (unsigned int i=0; i Date: Thu, 26 Nov 2015 09:11:52 -0800 Subject: [PATCH 1487/1812] Avoid unnecessarily friending classes --- apps/openmw/mwsound/sound.hpp | 23 +++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.cpp | 22 +++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 53b258a6a3..dd16853673 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,8 +7,6 @@ namespace MWSound { class Sound { - virtual void update() = 0; - Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); @@ -20,19 +18,31 @@ namespace MWSound float mMinDistance; float mMaxDistance; int mFlags; + float mFadeOutTime; public: virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; + virtual void update() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } - void setFadeout(float duration) { mFadeOutTime=duration; } + void setBaseVolume(float volume) { mBaseVolume = volume; } + void setFadeout(float duration) { mFadeOutTime = duration; } + void updateFade(float duration) + { + if(mFadeOutTime > 0.0f) + { + float soundDuration = std::min(duration, mFadeOutTime); + mVolume *= (mFadeOutTime-soundDuration) / mFadeOutTime; + mFadeOutTime -= soundDuration; + } + } MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - + bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) @@ -42,12 +52,9 @@ namespace MWSound , mMinDistance(mindist) , mMaxDistance(maxdist) , mFlags(flags) - , mFadeOutTime(0) + , mFadeOutTime(0.0f) { } virtual ~Sound() { } - - friend class OpenAL_Output; - friend class SoundManager; }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4d0c7912cd..a125494ad9 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -828,10 +828,9 @@ namespace MWSound const osg::Vec3f objpos(pos.asVec3()); sound->setPosition(objpos); - if((sound->mFlags&Play_RemoveAtDistance)) + if(sound->getDistanceCull()) { - osg::Vec3f diff = mListenerPos - ptr.getRefData().getPosition().asVec3(); - if(diff.length2() > 2000*2000) + if((mListenerPos - objpos).length2() > 2000*2000) sound->stop(); } } @@ -839,15 +838,8 @@ namespace MWSound if(!sound->isPlaying()) return false; - // Update fade out - if(sound->mFadeOutTime > 0.0f) - { - float soundDuration = duration; - if(soundDuration > sound->mFadeOutTime) - soundDuration = sound->mFadeOutTime; - sound->setVolume(sound->mVolume - soundDuration/sound->mFadeOutTime*sound->mVolume); - sound->mFadeOutTime -= soundDuration; - } + sound->updateFade(duration); + sound->update(); return true; } @@ -885,7 +877,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { MWBase::SoundPtr sound = sndidx->first; - sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->update(); } } @@ -893,12 +885,12 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) { MWBase::SoundPtr sound = sayiter->second.first; - sound->mBaseVolume = volumeFromType(sound->getPlayType()); + sound->setBaseVolume(volumeFromType(sound->getPlayType())); sound->update(); } if(mMusic) { - mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); + mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); mMusic->update(); } mOutput->finishUpdate(); From 8b7587f9a699a7da1fffa2e76e30aca7d0f2f485 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 09:33:16 -0800 Subject: [PATCH 1488/1812] Track whether a sound is 3D --- apps/openmw/mwsound/sound.hpp | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 10 ++++++---- apps/openmw/mwsound/soundmanagerimp.hpp | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index dd16853673..8ef1d25dbb 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -43,6 +43,7 @@ namespace MWSound MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } + bool getIs3D() const { return mFlags&Play_3D; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a125494ad9..aa51977cc6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -483,7 +483,7 @@ namespace MWSound float basevol = volumeFromType(type); sound = mOutput->playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type, offset + volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset ); if(sfx->mUses++ == 0) { @@ -518,7 +518,8 @@ namespace MWSound return MWBase::SoundPtr(); sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset ); if(sfx->mUses++ == 0) { @@ -548,7 +549,8 @@ namespace MWSound float basevol = volumeFromType(type); sound = mOutput->playSound3D(sfx->mHandle, - initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, mode|type, offset + initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset ); if(sfx->mUses++ == 0) { @@ -822,7 +824,7 @@ namespace MWSound bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) { - if(!ptr.isEmpty()) + if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 38bad2194e..db0b06dc06 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -34,6 +34,11 @@ namespace MWSound Env_Normal, Env_Underwater }; + // Extra play flags, not intended for caller use + enum PlayModeEx { + Play_2D = 0, + Play_3D = 1<<31 + }; class SoundManager : public MWBase::SoundManager { From 82f3651f8130c4ad71cf4a5c4971accfe2619a36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Nov 2015 23:40:02 -0800 Subject: [PATCH 1489/1812] Treat the sound offset as the offset in seconds --- apps/openmw/mwbase/soundmanager.hpp | 4 ++-- apps/openmw/mwclass/door.cpp | 10 ++++---- apps/openmw/mwsound/openal_output.cpp | 31 ++++--------------------- apps/openmw/mwsound/openal_output.hpp | 2 -- apps/openmw/mwsound/sound_output.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 8 +++---- 6 files changed, 16 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9366875e34..67203d0a41 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -109,13 +109,13 @@ namespace MWBase PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a sound, independently of 3D-position - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index b469dc9e2f..47219deb77 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -169,7 +169,9 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f); - float offset = doorRot/ 3.14159265f * 2.0f; + // Doors rotate at 90 degrees per second, so start the sound at + // where it would be at the current rotation. + float offset = doorRot/(3.14159265f * 0.5f); action->setSoundOffset(offset); action->setSound(openSound); } @@ -177,10 +179,8 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0f - doorRot/ 3.14159265f * 2.0f; - //most if not all door have closing bang somewhere in the middle of the sound, - //so we divide offset by two - action->setSoundOffset(offset * 0.5f); + float offset = 1.0f - doorRot/(3.14159265f * 0.5f); + action->setSoundOffset(std::max(offset, 0.0f)); action->setSound(closeSound); } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bafd272af6..a5246bde94 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -146,18 +146,6 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } -static double getBufferLength(ALuint buffer) -{ - ALint bufferSize, frequency, channels, bitsPerSample; - alGetBufferi(buffer, AL_SIZE, &bufferSize); - alGetBufferi(buffer, AL_FREQUENCY, &frequency); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_BITS, &bitsPerSample); - throwALerror(); - - return (8.0*bufferSize)/(frequency*channels*bitsPerSample); -} - // // A streaming OpenAL sound. @@ -863,14 +851,9 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba } sound->updateAll(true); - if(offset < 0.0f) - offset = 0.0f; - if(offset > 1.0f) - offset = 1.0f; + alSourcei(src, AL_BUFFER, GET_PTRID(data)); + alSourcef(src, AL_SEC_OFFSET, offset/pitch); - ALuint buffer = GET_PTRID(data); - alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -898,14 +881,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f } sound->updateAll(false); - if(offset < 0.0f) - offset = 0.0f; - if(offset > 1.0f) - offset = 1.0f; - - ALuint buffer = GET_PTRID(data); - alSourcei(src, AL_BUFFER, buffer); - alSourcef(src, AL_SEC_OFFSET, static_cast(getBufferLength(buffer)*offset / pitch)); + alSourcei(src, AL_BUFFER, GET_PTRID(data)); + alSourcef(src, AL_SEC_OFFSET, offset/pitch); alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 0f54da9b5c..fdce32c8aa 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -42,9 +42,7 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index c91431f696..e358ba3447 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -30,9 +30,9 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; - /// @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index db0b06dc06..fa855646d6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -166,20 +166,18 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position - ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. - ///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts. + ///< @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. - - ///< Play a sound from an object - ///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end. + ///< @param offset Number of seconds into the sound to start playback. virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, From 5f8a09df9728d3dbdd017857f46f5b8af973de8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 01:02:53 -0800 Subject: [PATCH 1490/1812] Play player sounds (except footsteps) local to the listener --- apps/openmw/mwbase/soundmanager.hpp | 12 +++++++----- apps/openmw/mwmechanics/character.cpp | 11 ++++++++--- apps/openmw/mwsound/soundmanagerimp.cpp | 13 +++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 67203d0a41..a91149777d 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -38,15 +38,17 @@ namespace MWBase played by the PlayLoopSound family of script functions. Perhaps we can make this cut off a more subtle fade later, but have to be careful to not change the overall volume of areas by too much. */ + Play_NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the + player is making it. */ Play_LoopNoEnv = Play_Loop | Play_NoEnv, Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance }; enum PlayType { - Play_TypeSfx = 1<<3, /* Normal SFX sound */ - Play_TypeVoice = 1<<4, /* Voice sound */ - Play_TypeFoot = 1<<5, /* Footstep sound */ - Play_TypeMusic = 1<<6, /* Music track */ - Play_TypeMovie = 1<<7, /* Movie audio track */ + Play_TypeSfx = 1<<4, /* Normal SFX sound */ + Play_TypeVoice = 1<<5, /* Voice sound */ + Play_TypeFoot = 1<<6, /* Footstep sound */ + Play_TypeMusic = 1<<7, /* Music track */ + Play_TypeMovie = 1<<8, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie }; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ff23844dd2..f7f355a389 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -777,10 +777,15 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: if(!sound.empty()) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) - type = MWBase::SoundManager::Play_TypeFoot; - sndMgr->playSound3D(mPtr, sound, volume, pitch, type); + { + // Don't make foot sounds local for the player, it makes sense to keep them + // positioned on the ground. + sndMgr->playSound3D(mPtr, sound, volume, pitch, MWBase::SoundManager::Play_TypeFoot, + MWBase::SoundManager::Play_NoPlayerLocal); + } + else + sndMgr->playSound3D(mPtr, sound, volume, pitch); } return; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index aa51977cc6..5ae8243931 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -517,10 +517,15 @@ namespace MWSound if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); - sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + sound = mOutput->playSound(sfx->mHandle, + volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset + ); + else + sound = mOutput->playSound3D(sfx->mHandle, + objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, + mode|type|Play_3D, offset + ); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); From 21bb2e9314c68f49ca4fae9ec51c29957540252b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 01:58:13 -0800 Subject: [PATCH 1491/1812] Use a deque for loudness buffers with a map lookup Similar to Sound_Buffer, this allows individual Sound_Loudness objects to retain a constant pointer when new ones are inserted on to the end. --- apps/openmw/mwsound/soundmanagerimp.cpp | 45 +++++++++++++++---------- apps/openmw/mwsound/soundmanagerimp.hpp | 13 ++++--- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 5ae8243931..0cdaddfd25 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -212,7 +212,7 @@ namespace MWSound return sfx; } - DecoderPtr SoundManager::loadVoice(const std::string &voicefile) + DecoderPtr SoundManager::loadVoice(const std::string &voicefile, Sound_Loudness **lipdata) { DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -227,8 +227,12 @@ namespace MWSound decoder->open(file); } - NameLoudnessMap::iterator lipiter = mVoiceLipBuffers.find(voicefile); - if(lipiter != mVoiceLipBuffers.end()) return decoder; + NameLoudnessRefMap::iterator lipiter = mVoiceLipNameMap.find(voicefile); + if(lipiter != mVoiceLipNameMap.end()) + { + *lipdata = lipiter->second; + return decoder; + } ChannelConfig chans; SampleType type; @@ -241,9 +245,13 @@ namespace MWSound Sound_Loudness loudness; loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); - mVoiceLipBuffers.insert(std::make_pair(voicefile, loudness)); + mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), loudness); + lipiter = mVoiceLipNameMap.insert( + std::make_pair(voicefile, &mVoiceLipBuffers.back()) + ).first; decoder->rewind(); + *lipdata = lipiter->second; return decoder; } @@ -375,17 +383,19 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); + std::string voicefile = "Sound/"+filename; float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - DecoderPtr decoder = loadVoice(voicefile); + Sound_Loudness *loudness; + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice ); - mActiveSaySounds[ptr] = std::make_pair(sound, voicefile); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) { @@ -399,13 +409,10 @@ namespace MWSound if(snditer != mActiveSaySounds.end()) { MWBase::SoundPtr sound = snditer->second.first; - NameLoudnessMap::const_iterator lipiter = mVoiceLipBuffers.find(snditer->second.second); - if(lipiter != mVoiceLipBuffers.end()) - { - float sec = sound->getTimeOffset(); - if(sound->isPlaying()) - return lipiter->second.getLoudnessAtTime(sec); - } + Sound_Loudness *loudness = snditer->second.second; + float sec = sound->getTimeOffset(); + if(sound->isPlaying()) + return loudness->getLoudnessAtTime(sec); } return 0.0f; @@ -417,15 +424,17 @@ namespace MWSound return; try { - std::string voicefile = "sound/"+Misc::StringUtils::lowerCase(filename); + std::string voicefile = "Sound/"+filename; float basevol = volumeFromType(Play_TypeVoice); - DecoderPtr decoder = loadVoice(voicefile); + Sound_Loudness *loudness; + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound(decoder, basevol, 1.0f, Play_Normal|Play_TypeVoice ); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, voicefile); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } catch(std::exception &e) { @@ -927,7 +936,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { - SoundNamePair sndlist = sayiter->second; + SoundLoudnessPair sndlist = sayiter->second; mActiveSaySounds.erase(sayiter); mActiveSaySounds[updated] = sndlist; } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index fa855646d6..e12fe16fc4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -68,8 +68,11 @@ namespace MWSound typedef std::map NameBufferMap; NameBufferMap mBufferNameMap; - typedef std::map NameLoudnessMap; - NameLoudnessMap mVoiceLipBuffers; + typedef std::deque LoudnessList; + LoudnessList mVoiceLipBuffers; + + typedef std::map NameLoudnessRefMap; + NameLoudnessRefMap mVoiceLipNameMap; // NOTE: unused buffers are stored in front-newest order. typedef std::deque SoundList; @@ -83,8 +86,8 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::pair SoundNamePair; - typedef std::map SaySoundMap; + typedef std::pair SoundLoudnessPair; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; MWBase::SoundPtr mUnderwaterSound; @@ -103,7 +106,7 @@ namespace MWSound // Ensures the loudness/"lip" data is loaded, and returns a decoder to // start streaming - DecoderPtr loadVoice(const std::string &voicefile); + DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); From 449eca4fb4913b0c377e525da022426990f96266 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 02:36:33 -0800 Subject: [PATCH 1492/1812] Properly mark streams as 2D or 3D --- apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0cdaddfd25..7e1244febd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -304,7 +304,7 @@ namespace MWSound decoder->open(filename); mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), - 1.0f, Play_NoEnv|Play_TypeMusic); + 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); } catch(std::exception &e) { @@ -393,7 +393,8 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } @@ -432,7 +433,7 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); MWBase::SoundPtr sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D ); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } From 4a078725d4a669bfa1863e50547ed9025f3c532d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 02:57:44 -0800 Subject: [PATCH 1493/1812] Play player voices locally --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7e1244febd..d08aa4ca01 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -392,10 +392,16 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); + MWBase::SoundPtr sound; + if(ptr == MWMechanics::getPlayer()) + sound = mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D + ); + else + sound = mOutput->streamSound3D(decoder, + objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D + ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) From 9568aa6a84af76e9f33db7dde600eee9b7fbb386 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 04:30:09 -0800 Subject: [PATCH 1494/1812] Use a condition variable to wake up the audio stream thread This should make starting streams a bit more responsive, and allows us to do more in it that really shouldn't wait for its next wake up. --- apps/openmw/mwsound/openal_output.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a5246bde94..685979bcfd 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -217,6 +217,7 @@ struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; boost::recursive_mutex mMutex; + boost::condition_variable_any mCondVar; boost::thread mThread; StreamThread() @@ -231,9 +232,9 @@ struct OpenAL_Output::StreamThread { // boost::thread entry point void operator()() { + boost::unique_lock lock(mMutex); while(1) { - boost::unique_lock lock(mMutex); StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) { @@ -242,16 +243,19 @@ struct OpenAL_Output::StreamThread { else ++iter; } - lock.unlock(); - boost::this_thread::sleep(boost::posix_time::milliseconds(50)); + mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); } } void add(OpenAL_SoundStream *stream) { - boost::lock_guard lock(mMutex); + boost::unique_lock lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) + { mStreams.push_back(stream); + lock.unlock(); + mCondVar.notify_all(); + } } void remove(OpenAL_SoundStream *stream) From f3c035907c9daa4706e2ca29936c53de154c1d73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 04:55:17 -0800 Subject: [PATCH 1495/1812] Rename Sound::update to Sound::applyUpdates --- apps/openmw/mwsound/openal_output.cpp | 20 ++++++++++---------- apps/openmw/mwsound/sound.hpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 685979bcfd..87667019e1 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -188,7 +188,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual void update(); + virtual void applyUpdates(); void play(); bool process(); @@ -206,7 +206,7 @@ public: : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) { } - virtual void update(); + virtual void applyUpdates(); }; @@ -411,10 +411,10 @@ void OpenAL_SoundStream::updateAll(bool local) } alSourcei(mSource, AL_LOOPING, AL_FALSE); - update(); + applyUpdates(); } -void OpenAL_SoundStream::update() +void OpenAL_SoundStream::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -490,7 +490,7 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } -void OpenAL_SoundStream3D::update() +void OpenAL_SoundStream3D::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -536,7 +536,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); - virtual void update(); + virtual void applyUpdates(); }; // @@ -552,7 +552,7 @@ public: : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) { } - virtual void update(); + virtual void applyUpdates(); }; OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) @@ -614,10 +614,10 @@ void OpenAL_Sound::updateAll(bool local) } alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - update(); + applyUpdates(); } -void OpenAL_Sound::update() +void OpenAL_Sound::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; @@ -636,7 +636,7 @@ void OpenAL_Sound::update() throwALerror(); } -void OpenAL_Sound3D::update() +void OpenAL_Sound3D::applyUpdates() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 8ef1d25dbb..944fbc0327 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -25,7 +25,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; - virtual void update() = 0; + virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setBaseVolume(float volume) { mBaseVolume = volume; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d08aa4ca01..b31ae90197 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -863,7 +863,7 @@ namespace MWSound sound->updateFade(duration); - sound->update(); + sound->applyUpdates(); return true; } @@ -901,7 +901,7 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->update(); + sound->applyUpdates(); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -909,12 +909,12 @@ namespace MWSound { MWBase::SoundPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->update(); + sound->applyUpdates(); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); - mMusic->update(); + mMusic->applyUpdates(); } mOutput->finishUpdate(); } From b5ed2e65f8f5572f8a0f1a39f691e37f699bbe12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 06:01:50 -0800 Subject: [PATCH 1496/1812] Add a method to get the sound stream delay This helps avoid a lock during the movie player's read method, since it needs to sync with the current playback position which would otherwise need to get the movie decoder's current position. --- apps/openmw/mwsound/movieaudiofactory.cpp | 3 ++- apps/openmw/mwsound/openal_output.cpp | 21 +++++++++++++++++++++ apps/openmw/mwsound/sound.hpp | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 47889051ae..925c966da4 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -60,7 +60,8 @@ namespace MWSound virtual double getAudioClock() { - return mAudioTrack->getTimeOffset(); + return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate - + mAudioTrack->getStreamDelay(); } virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 87667019e1..dd440674f0 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -188,6 +188,7 @@ public: virtual void stop(); virtual bool isPlaying(); virtual double getTimeOffset(); + virtual double getStreamDelay() const; virtual void applyUpdates(); void play(); @@ -395,6 +396,26 @@ double OpenAL_SoundStream::getTimeOffset() return t; } +double OpenAL_SoundStream::getStreamDelay() const +{ + ALint state = AL_STOPPED; + double d = 0.0; + ALint offset; + + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) + { + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + ALint inqueue = mBufferSize/mFrameSize*queued - offset; + d = (double)inqueue / (double)mSampleRate; + } + + throwALerror(); + return d; +} + void OpenAL_SoundStream::updateAll(bool local) { alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 944fbc0327..f95ff169d0 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -25,6 +25,7 @@ namespace MWSound virtual void stop() = 0; virtual bool isPlaying() = 0; virtual double getTimeOffset() = 0; + virtual double getStreamDelay() const { return 0.0; } virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } From 0f05ccf72a20b0a2a927509c58b30dabdb0520a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 08:13:23 -0800 Subject: [PATCH 1497/1812] Use a non-recursive mutex and properly end the streaming thrread --- apps/openmw/mwsound/openal_output.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index dd440674f0..533e7e657d 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -217,24 +217,28 @@ public: struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; - boost::recursive_mutex mMutex; - boost::condition_variable_any mCondVar; + volatile bool mQuitNow; + boost::mutex mMutex; + boost::condition_variable mCondVar; boost::thread mThread; StreamThread() - : mThread(boost::ref(*this)) + : mQuitNow(false), mThread(boost::ref(*this)) { } ~StreamThread() { - mThread.interrupt(); + mQuitNow = true; + mMutex.lock(); mMutex.unlock(); + mCondVar.notify_all(); + mThread.join(); } // boost::thread entry point void operator()() { - boost::unique_lock lock(mMutex); - while(1) + boost::unique_lock lock(mMutex); + while(!mQuitNow) { StreamVec::iterator iter = mStreams.begin(); while(iter != mStreams.end()) @@ -250,7 +254,7 @@ struct OpenAL_Output::StreamThread { void add(OpenAL_SoundStream *stream) { - boost::unique_lock lock(mMutex); + boost::unique_lock lock(mMutex); if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) { mStreams.push_back(stream); @@ -261,14 +265,14 @@ struct OpenAL_Output::StreamThread { void remove(OpenAL_SoundStream *stream) { - boost::lock_guard lock(mMutex); + boost::lock_guard lock(mMutex); StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); if(iter != mStreams.end()) mStreams.erase(iter); } void removeAll() { - boost::lock_guard lock(mMutex); + boost::lock_guard lock(mMutex); mStreams.clear(); } @@ -360,7 +364,7 @@ bool OpenAL_SoundStream::isPlaying() { ALint state; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -375,7 +379,7 @@ double OpenAL_SoundStream::getTimeOffset() ALint offset; double t; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); + boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) From 4ee409af84ff9dac4083cd0a0e6af0266136d311 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Nov 2015 09:47:14 -0800 Subject: [PATCH 1498/1812] Load loudness data asynchronously Currently abuses the output audio streams' background processing thread to do the work, since there's no generalized threaded processing mechanism. --- apps/openmw/mwsound/loudness.cpp | 2 + apps/openmw/mwsound/loudness.hpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 53 +++++++++++ apps/openmw/mwsound/openal_output.hpp | 2 + apps/openmw/mwsound/sound_output.hpp | 5 + apps/openmw/mwsound/soundmanagerimp.cpp | 120 +++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 10 +- 7 files changed, 150 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index 21f399ddc5..326c59c079 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -52,6 +52,8 @@ void Sound_Loudness::analyzeLoudness(const std::vector< char >& data, int sample mSamples.push_back(rms); ++segment; } + + mReady = true; } diff --git a/apps/openmw/mwsound/loudness.hpp b/apps/openmw/mwsound/loudness.hpp index a0af2b5586..366d29de51 100644 --- a/apps/openmw/mwsound/loudness.hpp +++ b/apps/openmw/mwsound/loudness.hpp @@ -12,9 +12,10 @@ class Sound_Loudness { // Loudness sample info float mSamplesPerSec; std::vector mSamples; + volatile bool mReady; public: - Sound_Loudness() : mSamplesPerSec(0.0f) { } + Sound_Loudness() : mSamplesPerSec(0.0f), mReady(false) { } /** * Analyzes the energy (closely related to loudness) of a sound buffer. @@ -30,6 +31,7 @@ public: ChannelConfig chans, SampleType type, float valuesPerSecond); + bool isReady() { return mReady; } float getLoudnessAtTime(float sec) const; }; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 533e7e657d..d4c890ceec 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -23,6 +23,13 @@ #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) +namespace +{ + +const int sLoudnessFPS = 20; // loudness values per second of audio + +} + namespace MWSound { @@ -217,6 +224,10 @@ public: struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; + + typedef std::vector > DecoderLoudnessVec; + DecoderLoudnessVec mDecoderLoudness; + volatile bool mQuitNow; boost::mutex mMutex; boost::condition_variable mCondVar; @@ -248,6 +259,33 @@ struct OpenAL_Output::StreamThread { else ++iter; } + + // Only do one loudness decode at a time, in case it takes particularly long we don't + // want to block up anything. + DecoderLoudnessVec::iterator dliter = mDecoderLoudness.begin(); + if(dliter != mDecoderLoudness.end()) + { + DecoderPtr decoder = dliter->first; + Sound_Loudness *loudness = dliter->second; + mDecoderLoudness.erase(dliter); + lock.unlock(); + + std::vector data; + ChannelConfig chans = ChannelConfig_Mono; + SampleType type = SampleType_Int16; + int srate = 48000; + try { + decoder->getInfo(&srate, &chans, &type); + decoder->readAll(data); + } + catch(std::exception &e) { + std::cerr<< "Failed to decode audio: "<analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); + lock.lock(); + continue; + } mCondVar.timed_wait(lock, boost::posix_time::milliseconds(50)); } } @@ -274,6 +312,15 @@ struct OpenAL_Output::StreamThread { { boost::lock_guard lock(mMutex); mStreams.clear(); + mDecoderLoudness.clear(); + } + + void add(DecoderPtr decoder, Sound_Loudness *loudness) + { + boost::unique_lock lock(mMutex); + mDecoderLoudness.push_back(std::make_pair(decoder, loudness)); + lock.unlock(); + mCondVar.notify_all(); } private: @@ -1052,6 +1099,12 @@ void OpenAL_Output::resumeSounds(int types) } +void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness) +{ + mStreamThread->add(decoder, loudness); +} + + OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index fdce32c8aa..751ec4fd29 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -57,6 +57,8 @@ namespace MWSound virtual void pauseSounds(int types); virtual void resumeSounds(int types); + virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness); + OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index e358ba3447..0f69498aa8 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -47,6 +47,11 @@ namespace MWSound virtual void pauseSounds(int types) = 0; virtual void resumeSounds(int types) = 0; + // HACK: The sound output implementation really shouldn't be handling + // asynchronous loudness data loading, but it's currently where we have + // a background processing thread. + virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness) = 0; + Sound_Output& operator=(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b31ae90197..0f5cee7375 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -30,11 +30,6 @@ #endif -namespace -{ - const int sLoudnessFPS = 20; // loudness values per second of audio -} - namespace MWSound { SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) @@ -234,27 +229,38 @@ namespace MWSound return decoder; } - ChannelConfig chans; - SampleType type; - int srate; - decoder->getInfo(&srate, &chans, &type); - - std::vector data; - decoder->readAll(data); - - Sound_Loudness loudness; - loudness.analyzeLoudness(data, srate, chans, type, static_cast(sLoudnessFPS)); - - mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), loudness); + mVoiceLipBuffers.insert(mVoiceLipBuffers.end(), Sound_Loudness()); lipiter = mVoiceLipNameMap.insert( std::make_pair(voicefile, &mVoiceLipBuffers.back()) ).first; - decoder->rewind(); + mOutput->loadLoudnessAsync(decoder, lipiter->second); + *lipdata = lipiter->second; return decoder; } + MWBase::SoundPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); + static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + + float basevol = volumeFromType(Play_TypeVoice); + if(playlocal) + return mOutput->streamSound(decoder, + basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D + ); + return mOutput->streamSound3D(decoder, + pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D + ); + } + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const @@ -375,16 +381,7 @@ namespace MWSound return; try { - MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); - static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); - static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - std::string voicefile = "Sound/"+filename; - float basevol = volumeFromType(Play_TypeVoice); const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); @@ -392,17 +389,13 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound; - if(ptr == MWMechanics::getPlayer()) - sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); + if(!loudness->isReady()) + mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else - sound = mOutput->streamSound3D(decoder, - objpos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + { + MWBase::SoundPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + } } catch(std::exception &e) { @@ -432,16 +425,18 @@ namespace MWSound try { std::string voicefile = "Sound/"+filename; - float basevol = volumeFromType(Play_TypeVoice); Sound_Loudness *loudness; mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile, &loudness); - MWBase::SoundPtr sound = mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + if(!loudness->isReady()) + mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); + else + { + MWBase::SoundPtr sound = playVoice(decoder, osg::Vec3f(), true); + mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + } } catch(std::exception &e) { @@ -456,8 +451,9 @@ namespace MWSound { if(snditer->second.first->isPlaying()) return false; + return true; } - return true; + return mPendingSaySounds.find(ptr) == mPendingSaySounds.end(); } void SoundManager::stopSay(const MWWorld::Ptr &ptr) @@ -468,6 +464,7 @@ namespace MWSound snditer->second.first->stop(); mActiveSaySounds.erase(snditer); } + mPendingSaySounds.erase(ptr); } @@ -832,6 +829,35 @@ namespace MWSound ++snditer; } + SayDecoderMap::iterator penditer = mPendingSaySounds.begin(); + while(penditer != mPendingSaySounds.end()) + { + Sound_Loudness *loudness = penditer->second.second; + if(loudness->isReady()) + { + try { + DecoderPtr decoder = penditer->second.first; + decoder->rewind(); + + MWWorld::Ptr ptr = penditer->first; + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + + MWBase::SoundPtr sound = playVoice(decoder, + objpos, (ptr == MWMechanics::getPlayer()) + ); + mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + } + catch(std::exception &e) { + std::cerr<< "Sound Error: "<second; + mPendingSaySounds.erase(penditer); + mPendingSaySounds[updated] = dl; + } } // Default readAll implementation, for decoders that can't do anything @@ -1033,6 +1066,7 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) sayiter->second.first->stop(); mActiveSaySounds.clear(); + mPendingSaySounds.clear(); mUnderwaterSound.reset(); stopMusic(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e12fe16fc4..8e2df9f1aa 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -90,6 +90,10 @@ namespace MWSound typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; + typedef std::pair DecoderLoudnessPair; + typedef std::map SayDecoderMap; + SayDecoderMap mPendingSaySounds; + MWBase::SoundPtr mUnderwaterSound; bool mListenerUnderwater; @@ -104,10 +108,12 @@ namespace MWSound Sound_Buffer *lookupSound(const std::string &soundId) const; Sound_Buffer *loadSound(const std::string &soundId); - // Ensures the loudness/"lip" data is loaded, and returns a decoder to - // start streaming + // Ensures the loudness/"lip" data gets loaded, and returns a decoder + // to start streaming DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); + MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + void streamMusicFull(const std::string& filename); bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); From 89783e047b6a373b4be276638d4de9794469ae9b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 19:40:31 +0100 Subject: [PATCH 1499/1812] Fix typo --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7fd73b4827..6bced30c45 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2281,7 +2281,7 @@ namespace MWWorld { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled - if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) + if (!targetActor.getRefData().getBaseNode() || !actor.getRefData().getBaseNode()) return false; // not in active cell return mPhysics->getLineOfSight(actor, targetActor); From ace4cfc0a850dc62f6b6a0069a894b1634fe9ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 20:32:45 +0100 Subject: [PATCH 1500/1812] Fix 'duplicate setting' errors when running installation wizard --- apps/launcher/maindialog.cpp | 3 +++ components/settings/settings.cpp | 7 +++++++ components/settings/settings.hpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fb1b73c3e7..a979a2125e 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -384,6 +384,9 @@ bool Launcher::MainDialog::setupGraphicsSettings() // remain consistent, and possibly be merged into a shared component. At the very least // the filenames should be in the CfgMgr component. + // Ensure to clear previous settings in case we had already loaded settings. + mEngineSettings.clear(); + // 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(); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index acad1a98e8..0e5324bd97 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -353,6 +353,13 @@ private: int mLine; }; +void Manager::clear() +{ + mDefaultSettings.clear(); + mUserSettings.clear(); + mChangedSettings.clear(); +} + void Manager::loadDefault(const std::string &file) { SettingsFileParser parser; diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index c16ff5a1ef..7adcb9b396 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -23,6 +23,9 @@ namespace Settings static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call + void clear(); + ///< clears all settings and default settings + void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) From 177a6f4a683bdefa0707e426c746f1c5deaf8d20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 20:52:29 +0100 Subject: [PATCH 1501/1812] Launcher: ensure to clear previous settings when reloading settings --- apps/launcher/maindialog.cpp | 4 ++++ components/config/gamesettings.cpp | 8 ++++++++ components/config/gamesettings.hpp | 2 ++ components/config/settingsbase.hpp | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index a979a2125e..60ae5b3a07 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -257,6 +257,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem bool Launcher::MainDialog::setupLauncherSettings() { + mLauncherSettings.clear(); + mLauncherSettings.setMultiValueEnabled(true); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); @@ -289,6 +291,8 @@ bool Launcher::MainDialog::setupLauncherSettings() bool Launcher::MainDialog::setupGameSettings() { + mGameSettings.clear(); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index ca6bfd80da..a897806c2a 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -454,3 +454,11 @@ QStringList Config::GameSettings::getContentList() const return Config::LauncherSettings::reverse(values(sContentKey)); } +void Config::GameSettings::clear() +{ + mSettings.clear(); + mUserSettings.clear(); + mDataDirs.clear(); + mDataLocal.clear(); +} + diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 992a3e5655..eeac893c23 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -72,6 +72,8 @@ namespace Config void setContentList(const QStringList& fileNames); QStringList getContentList() const; + void clear(); + private: Files::ConfigurationManager &mCfgMgr; diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index c798d2893b..08cd0bfc6f 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -101,6 +101,11 @@ namespace Config return true; } + void clear() + { + mSettings.clear(); + } + private: Map mSettings; From 5b8fd79b4bdc6871e3dbd7e32adcde1dc930b2bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:38:57 +0100 Subject: [PATCH 1502/1812] Fix crash when exception is thrown in startNewGame() --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 02b73bff7c..2d794b3e00 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -926,7 +926,7 @@ namespace MWMechanics PtrActorMap::iterator iter = mActors.begin(); while(iter != mActors.end()) { - if(iter->first.getCell()==cellStore && iter->first != ignore) + if((iter->first.isInCell() && iter->first.getCell()==cellStore) && iter->first != ignore) { delete iter->second; mActors.erase(iter++); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 5caee80462..55b732613f 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -185,7 +185,7 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) { - if (it->mPtr.getCell() == store && it->mPtr != MWMechanics::getPlayer()) + if ((it->mPtr.isInCell() && it->mPtr.getCell() == store) && it->mPtr != MWMechanics::getPlayer()) { it = mEmitters.erase(it); } From 4687c4baad4397d55d42ab37b225dbbf25cf8781 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:40:36 +0100 Subject: [PATCH 1503/1812] Do not assert() for invalid land data in plugins (Bug #3037) The resizing of LTEX store to the correct number of plugins was done in the load() method, but the load method won't be called if a plugin contains LAND records but doesn't contain LTEX records. For such plugins the Store::search() function would then fail an assertion. --- apps/openmw/mwworld/esmstore.cpp | 6 ++++++ apps/openmw/mwworld/store.cpp | 16 ++++++++++------ apps/openmw/mwworld/store.hpp | 3 +++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 50324f3e8e..9cf8de6bbc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -32,6 +32,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) ESM::Dialogue *dialogue = 0; + // Land texture loading needs to use a separate internal store for each plugin. + // We set the number of plugins here to avoid continual resizes during loading, + // and so we can properly verify if valid plugin indices are being passed to the + // LandTexture Store retrieval methods. + mLandTextures.resize(esm.getGlobalReaderList()->size()); + /// \todo Move this to somewhere else. ESMReader? // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 644c3d0cfc..3d23f3da43 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -351,8 +351,9 @@ namespace MWWorld assert(plugin < mStatic.size()); const LandTextureList <exl = mStatic[plugin]; - assert(index < ltexl.size()); - return <exl.at(index); + if (index >= ltexl.size()) + return NULL; + return <exl[index]; } const ESM::LandTexture *Store::find(size_t index, size_t plugin) const { @@ -380,10 +381,8 @@ namespace MWWorld lt.load(esm, isDeleted); - // Make sure we have room for the structure - if (plugin >= mStatic.size()) { - mStatic.resize(plugin+1); - } + assert(plugin < mStatic.size()); + LandTextureList <exl = mStatic[plugin]; if(lt.mIndex + 1 > (int)ltexl.size()) ltexl.resize(lt.mIndex+1); @@ -407,6 +406,11 @@ namespace MWWorld assert(plugin < mStatic.size()); return mStatic[plugin].end(); } + void Store::resize(size_t num) + { + if (mStatic.size() < num) + mStatic.resize(num); + } // Land //========================================================================= diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index ef551e205f..443dd4175e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -210,6 +210,9 @@ namespace MWWorld const ESM::LandTexture *search(size_t index, size_t plugin) const; const ESM::LandTexture *find(size_t index, size_t plugin) const; + /// Resize the internal store to hold at least \a num plugins. + void resize(size_t num); + size_t getSize() const; size_t getSize(size_t plugin) const; From 35fa1f5865bcb8370505f0a2b641c8363024c8a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 21:45:37 +0100 Subject: [PATCH 1504/1812] Not found Land Textures are no longer a fatal error (Bug #3037) Log warning message and show the default texture when encountering invalid ESM::LandTexture references. --- apps/opencs/view/render/terrainstorage.cpp | 4 +--- apps/openmw/mwrender/terrainstorage.cpp | 2 +- components/esmterrain/storage.cpp | 8 +++++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index 860ed00805..2be4efd73e 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -37,9 +37,7 @@ namespace CSVRender return ltex; } - std::stringstream error; - error << "Can't find LandTexture " << index << " from plugin " << plugin; - throw std::runtime_error(error.str()); + return NULL; } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index f9a9083f01..a98084709c 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -69,7 +69,7 @@ namespace MWRender { const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - return esmStore.get().find(index, plugin); + return esmStore.get().search(index, plugin); } } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index c36e3efe0c..fc56b883c3 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -299,11 +299,17 @@ namespace ESMTerrain std::string Storage::getTextureName(UniqueTextureId id) { + static const std::string defaultTexture = "textures\\_land_default.dds"; if (id.first == 0) - return "textures\\_land_default.dds"; // Not sure if the default texture really is hardcoded? + return defaultTexture; // Not sure if the default texture really is hardcoded? // NB: All vtex ids are +1 compared to the ltex ids const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); + if (!ltex) + { + std::cerr << "Unable to find land texture index " << id.first-1 << " in plugin " << id.second << ", using default texture instead" << std::endl; + return defaultTexture; + } // this is needed due to MWs messed up texture handling std::string texture = Misc::ResourceHelpers::correctTexturePath(ltex->mTexture, mVFS); From 30cc633f2c485452b817a500889ded1790fcf3d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Nov 2015 22:21:01 +0100 Subject: [PATCH 1505/1812] Missing include fix --- components/esmterrain/storage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index fc56b883c3..f0865a0a98 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,6 +1,7 @@ #include "storage.hpp" #include +#include #include #include From 4c0c20b1a0510d6d224f74a07a7f24aeda654854 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 27 Nov 2015 21:01:28 -0500 Subject: [PATCH 1506/1812] Changed relative includes to library header format --- components/bsa/bsa_file.cpp | 2 -- components/contentselector/view/contentselector.cpp | 2 +- components/contentselector/view/contentselector.hpp | 2 +- components/nifbullet/bulletnifloader.cpp | 11 +++++------ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 401d043d98..2b9a3f6325 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -28,8 +28,6 @@ #include #include -#include "../files/constrainedfilestream.hpp" - using namespace std; using namespace Bsa; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 78aa20cd26..87c9cea082 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -1,6 +1,6 @@ #include "contentselector.hpp" -#include "../model/esmfile.hpp" +#include #include diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 4e9fcfb3c8..9f775d5978 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -4,7 +4,7 @@ #include #include "ui_contentselector.h" -#include "../model/contentmodel.hpp" +#include class QSortFilterProxyModel; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 5de6d51ca0..0b8e9c1638 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -12,12 +12,11 @@ #include -#include "../nif/niffile.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 +#include namespace From c66fd69c47336cb610a2880800fc450d941a3e49 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 27 Nov 2015 21:20:54 -0500 Subject: [PATCH 1507/1812] Fix #include error --- components/contentselector/model/contentmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 769afee37b..8dc4351f6d 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -7,7 +7,7 @@ #include #include -#include "components/esm/esmreader.hpp" +#include ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), From debce0fb8090b704bb08523cca99507960409390 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:12:15 +0100 Subject: [PATCH 1508/1812] crashcatcher: show the message box before killing crashed process This change fixes a random X server lock-up that I get about 1 in 10 times when a crash is caught. I'm presuming it's an X server bug since faulty applications shouldn't be able to crash or freeze the X server under any circumstances. --- apps/openmw/crashcatcher.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 373d78746c..8d812efd3f 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -382,16 +382,17 @@ static void crash_handler(const char *logfile) fflush(stdout); if(crash_info.pid > 0) - { gdb_info(crash_info.pid); - kill(crash_info.pid, SIGKILL); - } if(logfile) { std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !"; SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); } + + if (crash_info.pid > 0) + kill(crash_info.pid, SIGKILL); + exit(0); } From 93a76e2f56b18fc5abff5e92dc338d208441a906 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:36:57 +0100 Subject: [PATCH 1509/1812] Revert debce0fb80, use a sleep() to work around the X11 bug Problem with debce0fb80 is the crashed process won't be killed until the user accepts the message box, and it's harder to get to the message box when the window is in full screen or the cursor is locked. --- apps/openmw/crashcatcher.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 8d812efd3f..0b4ff6304f 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -382,7 +382,15 @@ static void crash_handler(const char *logfile) fflush(stdout); if(crash_info.pid > 0) + { gdb_info(crash_info.pid); + kill(crash_info.pid, SIGKILL); + } + + // delay between killing of the crashed process and showing the message box to + // work around occasional X server lock-up. this can only be a bug in X11 since + // even faulty applications shouldn't be able to freeze the X server. + usleep(100000); if(logfile) { @@ -390,9 +398,6 @@ static void crash_handler(const char *logfile) SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); } - if (crash_info.pid > 0) - kill(crash_info.pid, SIGKILL); - exit(0); } From d97dda05c9533b751caa0e33b2509d50a6c35290 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 05:55:36 +0100 Subject: [PATCH 1510/1812] Don't attempt to play unset weather sounds --- apps/openmw/mwworld/weather.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6d9a85ada4..a5e4db5476 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -158,6 +158,9 @@ Weather::Weather(const std::string& name, else mAmbientLoopSoundID = fallback.getFallbackString("Weather_" + name + "_Ambient_Loop_Sound_ID"); + if (Misc::StringUtils::ciEqual(mAmbientLoopSoundID, "None")) + mAmbientLoopSoundID.clear(); + /* Unhandled: Rain Diameter=600 ? From a1fa1b2b2ec5f8d5366b4c7f72115eee84d0dbab Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 06:00:18 +0100 Subject: [PATCH 1511/1812] Don't attempt to open an empty texture --- apps/openmw/mwrender/sky.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 66253f70d5..68ee17e6b3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1550,11 +1550,13 @@ void SkyManager::setWeather(const WeatherResult& weather) { mNextClouds = weather.mNextCloudTexture; - std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); + if (!mNextClouds.empty()) + { + std::string texture = Misc::ResourceHelpers::correctTexturePath(mNextClouds, mSceneManager->getVFS()); - if (!texture.empty()) mCloudUpdater2->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, osg::Texture::REPEAT, osg::Texture::REPEAT)); + } } if (mCloudBlendFactor != weather.mCloudBlendFactor) From c9bfe0112084708fb27b47d35af4e133582881a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 17:57:35 +0100 Subject: [PATCH 1512/1812] Fix applying of weather changes after serving a jail sentence --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a5e4db5476..afa819121e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -627,7 +627,7 @@ void WeatherManager::update(float duration, bool paused) MWBase::World& world = *MWBase::Environment::get().getWorld(); TimeStamp time = world.getTimeStamp(); - if(!paused) + if(!paused || mFastForward) { // Add new transitions when either the player's current external region changes. std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); From db71634a2d66dd6a41a706410463364e90b91c9b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Nov 2015 19:14:47 +0100 Subject: [PATCH 1513/1812] Allow replacing of interactive message boxes (Fixes #3040) --- apps/openmw/mwgui/messagebox.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c647ecaf52..f8ddeba3ee 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -117,8 +117,11 @@ namespace MWGui bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { - if(mInterMessageBoxe != NULL) { - throw std::runtime_error("There is a message box already"); + if (mInterMessageBoxe != NULL) + { + std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl; + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); From cd4a1ffd164a4f98878e440b3c33a1e6a0236d16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Nov 2015 14:13:14 +0100 Subject: [PATCH 1514/1812] Fast version of dynamic_cast for MWClass --- apps/openmw/mwclass/container.cpp | 15 ++++---- apps/openmw/mwclass/creature.cpp | 35 ++++++++++-------- apps/openmw/mwclass/creaturelevlist.cpp | 21 ++++++----- apps/openmw/mwclass/door.cpp | 23 ++++++------ apps/openmw/mwclass/npc.cpp | 48 ++++++++++++++----------- apps/openmw/mwworld/customdata.cpp | 46 ++++++++++++++++++++++++ apps/openmw/mwworld/customdata.hpp | 21 +++++++++++ 7 files changed, 150 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwworld/customdata.cpp diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index f785797c10..6c44c97e25 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -27,23 +27,26 @@ #include "../mwmechanics/npcstats.hpp" -namespace +namespace MWClass { - struct ContainerCustomData : public MWWorld::CustomData + class ContainerCustomData : public MWWorld::CustomData { + public: MWWorld::ContainerStore mContainerStore; virtual MWWorld::CustomData *clone() const; + + virtual ContainerCustomData& asContainerCustomData() + { + return *this; + } }; MWWorld::CustomData *ContainerCustomData::clone() const { return new ContainerCustomData (*this); } -} -namespace MWClass -{ std::string Container::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -202,7 +205,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore; + return ptr.getRefData().getCustomData()->asContainerCustomData().mContainerStore; } std::string Container::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 95bc429e3b..2cd11d1136 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -40,14 +40,29 @@ namespace { - struct CreatureCustomData : public MWWorld::CustomData + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) { + return (ptr.get()->mBase->mFlags & bitMask) != 0; + } +} + +namespace MWClass +{ + + class CreatureCustomData : public MWWorld::CustomData + { + public: MWMechanics::CreatureStats mCreatureStats; MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures MWMechanics::Movement mMovement; virtual MWWorld::CustomData *clone() const; + virtual CreatureCustomData& asCreatureCustomData() + { + return *this; + } + CreatureCustomData() : mContainerStore(0) {} virtual ~CreatureCustomData() { delete mContainerStore; } }; @@ -59,14 +74,6 @@ namespace return cloned; } - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) - { - return (ptr.get()->mBase->mFlags & bitMask) != 0; - } -} - -namespace MWClass -{ const Creature::GMST& Creature::getGmst() { static GMST gmst; @@ -193,7 +200,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mCreatureStats; + return ptr.getRefData().getCustomData()->asCreatureCustomData().mCreatureStats; } @@ -421,7 +428,7 @@ namespace MWClass { ensureCustomData (ptr); - return *dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore; + return *ptr.getRefData().getCustomData()->asCreatureCustomData().mContainerStore; } MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const @@ -511,7 +518,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -711,7 +718,7 @@ namespace MWClass else ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. - CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->readState (state2.mInventory); customData.mCreatureStats.readState (state2.mCreatureStats); @@ -730,7 +737,7 @@ namespace MWClass ensureCustomData (ptr); - CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 433e5fcea6..c015d53d6a 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -7,25 +7,28 @@ #include "../mwworld/customdata.hpp" -namespace +namespace MWClass { - struct CreatureLevListCustomData : public MWWorld::CustomData + class CreatureLevListCustomData : public MWWorld::CustomData { + public: // actorId of the creature we spawned int mSpawnActorId; bool mSpawn; // Should a new creature be spawned? virtual MWWorld::CustomData *clone() const; + + virtual CreatureLevListCustomData& asCreatureLevListCustomData() + { + return *this; + } }; MWWorld::CustomData *CreatureLevListCustomData::clone() const { return new CreatureLevListCustomData (*this); } -} -namespace MWClass -{ std::string CreatureLevList::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -40,7 +43,7 @@ namespace MWClass { ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); customData.mSpawn = true; } @@ -55,7 +58,7 @@ namespace MWClass { ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); if (!customData.mSpawn) return; @@ -104,7 +107,7 @@ namespace MWClass const ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); customData.mSpawnActorId = state2.mSpawnActorId; customData.mSpawn = state2.mSpawn; } @@ -115,7 +118,7 @@ namespace MWClass ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); - CreatureLevListCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 47219deb77..6fee79ddf0 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -28,23 +28,26 @@ #include "../mwmechanics/actorutil.hpp" -namespace +namespace MWClass { - struct DoorCustomData : public MWWorld::CustomData + class DoorCustomData : public MWWorld::CustomData { + public: int mDoorState; // 0 = nothing, 1 = opening, 2 = closing virtual MWWorld::CustomData *clone() const; + + virtual DoorCustomData& asDoorCustomData() + { + return *this; + } }; MWWorld::CustomData *DoorCustomData::clone() const { return new DoorCustomData (*this); } -} -namespace MWClass -{ std::string Door::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; @@ -65,7 +68,7 @@ namespace MWClass // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) { - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); if (customData.mDoorState > 0) { MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState); @@ -324,7 +327,7 @@ namespace MWClass int Door::getDoorState (const MWWorld::Ptr &ptr) const { ensureCustomData(ptr); - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); return customData.mDoorState; } @@ -334,14 +337,14 @@ namespace MWClass throw std::runtime_error("load doors can't be moved"); ensureCustomData(ptr); - DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); customData.mDoorState = state; } void Door::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { ensureCustomData(ptr); - DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); const ESM::DoorState& state2 = dynamic_cast(state); customData.mDoorState = state2.mDoorState; @@ -350,7 +353,7 @@ namespace MWClass void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { ensureCustomData(ptr); - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5679dc3e9e..6633b3490b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -42,19 +42,6 @@ namespace { - struct NpcCustomData : public MWWorld::CustomData - { - MWMechanics::NpcStats mNpcStats; - MWMechanics::Movement mMovement; - MWWorld::InventoryStore mInventoryStore; - - virtual MWWorld::CustomData *clone() const; - }; - - MWWorld::CustomData *NpcCustomData::clone() const - { - return new NpcCustomData (*this); - } int is_even(double d) { double int_part; @@ -251,6 +238,27 @@ namespace namespace MWClass { + + class NpcCustomData : public MWWorld::CustomData + { + public: + MWMechanics::NpcStats mNpcStats; + MWMechanics::Movement mMovement; + MWWorld::InventoryStore mInventoryStore; + + virtual MWWorld::CustomData *clone() const; + + virtual NpcCustomData& asNpcCustomData() + { + return *this; + } + }; + + MWWorld::CustomData *NpcCustomData::clone() const + { + return new NpcCustomData (*this); + } + const Npc::GMST& Npc::getGmst() { static GMST gmst; @@ -446,14 +454,14 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mNpcStats; + return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats; } MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mNpcStats; + return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats; } @@ -780,7 +788,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; + return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr) @@ -788,7 +796,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; + return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } std::string Npc::getScript (const MWWorld::Ptr& ptr) const @@ -897,7 +905,7 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement; } bool Npc::isEssential (const MWWorld::Ptr& ptr) const @@ -1161,7 +1169,7 @@ namespace MWClass else ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. - NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.readState (state2.mInventory); customData.mNpcStats.readState (state2.mNpcStats); @@ -1181,7 +1189,7 @@ namespace MWClass ensureCustomData (ptr); - NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); + NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp new file mode 100644 index 0000000000..8edbb345fb --- /dev/null +++ b/apps/openmw/mwworld/customdata.cpp @@ -0,0 +1,46 @@ +#include "customdata.hpp" + +#include +#include +#include + +namespace MWWorld +{ + +MWClass::CreatureCustomData &CustomData::asCreatureCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::NpcCustomData &CustomData::asNpcCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to NpcCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::ContainerCustomData &CustomData::asContainerCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to ContainerCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::DoorCustomData &CustomData::asDoorCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to DoorCustomData"; + throw std::logic_error(error.str()); +} + +MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureLevListCustomData"; + throw std::logic_error(error.str()); +} + + +} diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 588991fe40..8c3890580b 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -1,6 +1,15 @@ #ifndef GAME_MWWORLD_CUSTOMDATA_H #define GAME_MWWORLD_CUSTOMDATA_H +namespace MWClass +{ + class CreatureCustomData; + class NpcCustomData; + class ContainerCustomData; + class DoorCustomData; + class CreatureLevListCustomData; +} + namespace MWWorld { /// \brief Base class for the MW-class-specific part of RefData @@ -11,6 +20,18 @@ namespace MWWorld virtual ~CustomData() {} virtual CustomData *clone() const = 0; + + // Fast version of dynamic_cast. Needs to be overridden in the respective class. + + virtual MWClass::CreatureCustomData& asCreatureCustomData(); + + virtual MWClass::NpcCustomData& asNpcCustomData(); + + virtual MWClass::ContainerCustomData& asContainerCustomData(); + + virtual MWClass::DoorCustomData& asDoorCustomData(); + + virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); }; } From f962ce0bbe6848b572cd83582a36cae458b2b7d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Nov 2015 19:56:43 +0100 Subject: [PATCH 1515/1812] Don't link against unnecessary OSG libraries --- apps/opencs/CMakeLists.txt | 8 +++++++- apps/openmw/CMakeLists.txt | 8 +++++++- components/CMakeLists.txt | 10 +++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6af04e8fc2..dc90072fa4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -205,7 +205,13 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGQT_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 48d10e2028..e2d333e562 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -118,7 +118,13 @@ include_directories( ) target_link_libraries(openmw - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c80e27e4d8..0f2906ce5d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -177,7 +177,15 @@ target_link_libraries(components ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} ${BULLET_LIBRARIES} ${SDL2_LIBRARY} # For MyGUI platform From d5a738bd392b0b28a3a65cb1128ce3fd35731046 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 00:38:52 +0100 Subject: [PATCH 1516/1812] Apply 27e669296e5 (locale-unaware tolower) to more code In particular, the one in VFS::normalizeFilename was affecting cell loading performance. --- apps/openmw/mwdialogue/keywordsearch.hpp | 15 +++++++-------- apps/openmw/mwgui/journalviewmodel.cpp | 6 ++---- components/files/multidircollection.cpp | 4 ++-- components/files/multidircollection.hpp | 6 ++---- components/vfs/manager.cpp | 4 ++-- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index c4e1d75538..3b68d3d6b9 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -2,7 +2,7 @@ #define GAME_MWDIALOGUE_KEYWORDSEARCH_H #include -#include +#include #include #include #include // std::reverse @@ -44,7 +44,7 @@ public: typename Entry::childen_t::iterator current; typename Entry::childen_t::iterator next; - current = mRoot.mChildren.find (std::tolower (*keyword.begin(), mLocale)); + current = mRoot.mChildren.find (tolower (*keyword.begin())); if (current == mRoot.mChildren.end()) return false; else if (current->second.mKeyword.size() && Misc::StringUtils::ciEqual(current->second.mKeyword, keyword)) @@ -55,7 +55,7 @@ public: for (Point i = ++keyword.begin(); i != keyword.end(); ++i) { - next = current->second.mChildren.find(std::tolower (*i, mLocale)); + next = current->second.mChildren.find(tolower (*i)); if (next == current->second.mChildren.end()) return false; if (Misc::StringUtils::ciEqual(next->second.mKeyword, keyword)) @@ -89,7 +89,7 @@ public: // check first character - typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale)); + typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (tolower (*i)); // no match, on to next character if (candidate == mRoot.mChildren.end ()) @@ -104,7 +104,7 @@ public: while ((j + 1) != end) { - typename Entry::childen_t::iterator next = candidate->second.mChildren.find (std::tolower (*++j, mLocale)); + typename Entry::childen_t::iterator next = candidate->second.mChildren.find (tolower (*++j)); if (next == candidate->second.mChildren.end ()) { @@ -136,7 +136,7 @@ public: while (k != end && t != candidate->second.mKeyword.end ()) { - if (std::tolower (*k, mLocale) != std::tolower (*t, mLocale)) + if (tolower (*k) != tolower (*t)) break; ++k, ++t; @@ -212,7 +212,7 @@ private: void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry) { - int ch = tolower (keyword.at (depth), mLocale); + int ch = tolower (keyword.at (depth)); typename Entry::childen_t::iterator j = entry.mChildren.find (ch); @@ -249,7 +249,6 @@ private: } Entry mRoot; - std::locale mLocale; }; } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index d05257e46c..03e4813b3e 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -29,8 +29,6 @@ struct JournalViewModelImpl : JournalViewModel mutable bool mKeywordSearchLoaded; mutable KeywordSearchT mKeywordSearch; - std::locale mLocale; - JournalViewModelImpl () { mKeywordSearchLoaded = false; @@ -74,7 +72,7 @@ struct JournalViewModelImpl : JournalViewModel } } - wchar_t tolower (wchar_t ch) const { return std::tolower (ch, mLocale); } + wchar_t tolower (wchar_t ch) const { return tolower (ch); } bool isEmpty () const { @@ -319,7 +317,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != std::tolower (character, mLocale)) + if (i->first [0] != tolower (character)) continue; visitor (i->second.getName()); diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 7b3b0c440c..9b4a542f58 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -28,8 +28,8 @@ namespace Files for (std::size_t i=0; i #include #include -#include #include #include @@ -25,12 +24,11 @@ namespace Files return left #include -#include #include "archive.hpp" @@ -15,7 +15,7 @@ namespace char nonstrict_normalize_char(char ch) { - return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic()); + return ch == '\\' ? '/' : tolower(ch); } void normalize_path(std::string& path, bool strict) From d2290a81837e404c4f1b22965c67e282f647bc44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 00:41:26 +0100 Subject: [PATCH 1517/1812] Don't crash when Water_SurfaceFrameCount is 0 --- apps/openmw/mwrender/water.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ca099991ea..1afb74bd73 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -551,6 +551,8 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + node->setStateSet(stateset); + std::vector > textures; int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); @@ -561,12 +563,15 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } + if (!textures.size()) + return; + float fps = mFallback->getFallbackFloat("Water_SurfaceFPS"); osg::ref_ptr controller (new NifOsg::FlipController(0, 1.f/fps, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); node->setUpdateCallback(controller); - node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); } From e49bce7b401c1a3fa31823dcc4e3688eaf365f68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 01:39:41 +0100 Subject: [PATCH 1518/1812] Share the bvh of btBvhTriangleMeshShape's when possible Results in decent cell-loading speed up. (only affects bullet versions < 2.83, since we use btScaledBvhTriangleMeshShape for >=2.83) --- components/resource/bulletshape.cpp | 11 ++++++++++- components/resource/bulletshape.hpp | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 00bcb9e046..968dbe6c67 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -62,7 +62,16 @@ btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) // work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); - TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true); + + // Do not build a new bvh (not needed, since it's the same as the original shape's bvh) + bool buildBvh = true; + if (trishape->getOptimizedBvh()) + buildBvh = false; + TriangleMeshShape* newShape = new TriangleMeshShape(newMesh, true, buildBvh); + // Set original shape's bvh via pointer + // The pointer is safe because the BulletShapeInstance keeps a ref_ptr to the original BulletShape + if (!buildBvh) + newShape->setOptimizedBvh(trishape->getOptimizedBvh()); #endif return newShape; } diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index 78e509db71..cfae27eac4 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -60,8 +60,8 @@ namespace Resource // Subclass btBhvTriangleMeshShape to auto-delete the meshInterface struct TriangleMeshShape : public btBvhTriangleMeshShape { - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, buildBvh) { } From ac366f1603213f7ad12b25d35f9b4a97d5053057 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 04:28:20 +0100 Subject: [PATCH 1519/1812] Fix the rig bounds being updated twice per frame Unlike what I expected, the osgUtil::UpdateVisitor is set to traverse all children (not only active children). The FrameSwitch was thus traversing both RigGeometries part of the double-buffering scheme, rather than only the one active in the current frame. --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 45e7c16df8..18ece51016 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -100,7 +100,7 @@ namespace virtual void traverse(osg::NodeVisitor& nv) { - if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN && nv.getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR) osg::Group::traverse(nv); else { From 8fb328ef4f306cfe1048943aedb3186701b4eca6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 05:19:14 +0100 Subject: [PATCH 1520/1812] Fix updating of character preview size in InventoryWindow::setGuiMode --- apps/openmw/mwgui/inventorywindow.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e5bf1f4b41..7678cb006c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -167,13 +167,15 @@ namespace MWGui MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); + bool needUpdate = (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()); + mMainWidget->setPosition(pos); mMainWidget->setSize(size); - if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) - updatePreviewSize(); - adjustPanes(); + + if (needUpdate) + updatePreviewSize(); } SortFilterItemModel* InventoryWindow::getSortFilterModel() From 0655abcd8b40e41f650def00f7151bba3186194d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 05:39:51 +0100 Subject: [PATCH 1521/1812] Fix some character preview raycasting issues (Bug #2769) --- apps/openmw/mwrender/characterpreview.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index f7296b1bd0..7ba8369dfc 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -30,6 +30,7 @@ namespace MWRender public: DrawOnceCallback () : mRendered(false) + , mLastRenderedFrame(0) { } @@ -38,13 +39,14 @@ namespace MWRender if (!mRendered) { mRendered = true; + + mLastRenderedFrame = nv->getTraversalNumber(); + traverse(node, nv); } else { node->setNodeMask(0); } - - traverse(node, nv); } void redrawNextFrame() @@ -52,8 +54,14 @@ namespace MWRender mRendered = false; } + unsigned int getLastRenderedFrame() const + { + return mLastRenderedFrame; + } + private: bool mRendered; + unsigned int mLastRenderedFrame; }; CharacterPreview::CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, @@ -262,8 +270,11 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); - intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_ONE); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor visitor(intersector); + visitor.setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); + // Set the traversal number from the last draw, so that the frame switch used for RigGeometry double buffering works correctly + visitor.setTraversalNumber(mDrawOnceCallback->getLastRenderedFrame()); osg::Node::NodeMask nodeMask = mCamera->getNodeMask(); mCamera->setNodeMask(~0); From b085c09f86f9256c898fc0c629dab3f930ee9624 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 13:36:15 +0100 Subject: [PATCH 1522/1812] Fix windows builds Can't instantiate a container (at least with MSVC) without knowing the exact size of the object being stored, forward-declares only work with pointers. I couldn't see a simple way to remove the forward declare, so pointers and memory management it is. --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 ++++++----- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0f5cee7375..71e1c97a87 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -104,9 +104,10 @@ namespace MWSound SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; + if((*sfxiter)->mHandle) + mOutput->unloadSound((*sfxiter)->mHandle); + (*sfxiter)->mHandle = 0; + delete (*sfxiter); } mUnusedBuffers.clear(); } @@ -145,8 +146,8 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), - Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + Sound_Buffer *sfx = *mSoundBuffers.insert(mSoundBuffers.end(), + new Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8e2df9f1aa..196fb28f2a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,7 +56,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::deque SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 14b143231c2c11ee90b46e02f17d965ce747523e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 15:26:43 +0100 Subject: [PATCH 1523/1812] Don't crash OpGetTarget when the target disappeared (Fixes #3048) --- apps/openmw/mwmechanics/aisequence.cpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index a1c5ab14f0..d55dc240e0 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -72,7 +72,7 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const targetActor = combat->getTarget(); - return true; + return !targetActor.isEmpty(); } std::list::const_iterator AiSequence::begin() const diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 78c84141a6..22b6ac8d10 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -424,7 +424,7 @@ namespace MWScript MWWorld::Ptr targetPtr; if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { - if (targetPtr.getCellRef().getRefId() == testedTargetId) + if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); From 576d5111a5747d1773c13439033754541b5d22d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 17:04:45 +0100 Subject: [PATCH 1524/1812] Prefer Intersector::PROJECTION over Intersector::WINDOW --- apps/openmw/mwrender/characterpreview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 7ba8369dfc..e2ff08b6b5 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -269,7 +269,11 @@ namespace MWRender int InventoryPreview::getSlotSelected (int posX, int posY) { - osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, posX, posY)); + float projX = (posX / mCamera->getViewport()->width()) * 2 - 1.f; + float projY = (posY / mCamera->getViewport()->height()) * 2 - 1.f; + // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. TODO: investigate + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, projX, projY)); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor visitor(intersector); visitor.setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); From f5f3d18b8e7e4842cd4be02729ffd51eb24b73a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 17:19:27 +0100 Subject: [PATCH 1525/1812] Add comment --- apps/openmw/mwrender/characterpreview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index e2ff08b6b5..a6f68b5d4c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -271,7 +271,10 @@ namespace MWRender { float projX = (posX / mCamera->getViewport()->width()) * 2 - 1.f; float projY = (posY / mCamera->getViewport()->height()) * 2 - 1.f; - // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. TODO: investigate + // With Intersector::WINDOW, the intersection ratios are slightly inaccurate. Seems to be a + // precision issue - compiling with OSG_USE_FLOAT_MATRIX=0, Intersector::WINDOW works ok. + // Using Intersector::PROJECTION results in better precision because the start/end points and the model matrices + // don't go through as many transformations. osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, projX, projY)); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); From a69e751089d5d7c9189b64687560033cf14cda0c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:38:46 +0100 Subject: [PATCH 1526/1812] Revert "Fix windows builds" This reverts commit b085c09f86f9256c898fc0c629dab3f930ee9624. --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 +++++------ apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 71e1c97a87..0f5cee7375 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -104,10 +104,9 @@ namespace MWSound SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); for(;sfxiter != mSoundBuffers.end();++sfxiter) { - if((*sfxiter)->mHandle) - mOutput->unloadSound((*sfxiter)->mHandle); - (*sfxiter)->mHandle = 0; - delete (*sfxiter); + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } mUnusedBuffers.clear(); } @@ -146,8 +145,8 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = *mSoundBuffers.insert(mSoundBuffers.end(), - new Sound_Buffer("Sound/"+sound->mSound, volume, min, max) + Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 196fb28f2a..8e2df9f1aa 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -56,7 +56,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::deque SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 682329851633b6cb956ca01514a4b0cf26c9844b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:42:25 +0100 Subject: [PATCH 1527/1812] Different way to solve the type deduction issue --- apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++++--- apps/openmw/mwsound/soundmanagerimp.hpp | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0f5cee7375..ceff1a6191 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -40,6 +40,7 @@ namespace MWSound , mMusicVolume(1.0f) , mVoiceVolume(1.0f) , mFootstepsVolume(1.0f) + , mSoundBuffers(new SoundBufferList::element_type()) , mBufferCacheSize(0) , mListenerUnderwater(false) , mListenerPos(0,0,0) @@ -101,8 +102,8 @@ namespace MWSound clear(); if(mOutput->isInitialized()) { - SoundBufferList::iterator sfxiter = mSoundBuffers.begin(); - for(;sfxiter != mSoundBuffers.end();++sfxiter) + SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); + for(;sfxiter != mSoundBuffers->end();++sfxiter) { if(sfxiter->mHandle) mOutput->unloadSound(sfxiter->mHandle); @@ -145,7 +146,7 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer *sfx = &*mSoundBuffers.insert(mSoundBuffers.end(), + Sound_Buffer *sfx = &*mSoundBuffers->insert(mSoundBuffers->end(), Sound_Buffer("Sound/"+sound->mSound, volume, min, max) ); mVFS->normalizeFilename(sfx->mResourceName); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 8e2df9f1aa..424fa712cf 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -1,6 +1,7 @@ #ifndef GAME_SOUND_SOUNDMANAGER_H #define GAME_SOUND_SOUNDMANAGER_H +#include #include #include #include @@ -56,7 +57,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::deque SoundBufferList; + typedef std::auto_ptr> SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 24340bff959fef20cc4277afd2666caa07dcd4de Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 30 Nov 2015 17:47:36 +0100 Subject: [PATCH 1528/1812] Add a space --- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 424fa712cf..9c090585b9 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -57,7 +57,7 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; - typedef std::auto_ptr> SoundBufferList; + typedef std::auto_ptr > SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain // valid. From 695fcf41c436ab67e00094772db736964a3eddba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 20:45:32 +0100 Subject: [PATCH 1529/1812] Optimize ValueInterpolator / KeyframeController Cache the current position in the animation track and attempt to reuse it in the next frame. Decent speed up for the Update phase, about 0.3 ms faster in Balmora. --- components/nif/nifkey.hpp | 3 + components/nifosg/controller.cpp | 107 +++++++++--------------- components/nifosg/controller.hpp | 138 ++++++++++++++++++++++++------- components/nifosg/particle.cpp | 4 +- components/nifosg/particle.hpp | 5 +- 5 files changed, 151 insertions(+), 106 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index d702d02925..682baed059 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -37,6 +37,9 @@ template struct KeyMapT { typedef std::map< float, KeyT > MapType; + typedef T ValueType; + typedef KeyT KeyType; + static const unsigned int sLinearInterpolation = 1; static const unsigned int sQuadraticInterpolation = 2; static const unsigned int sTBCInterpolation = 3; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 93c1de89a1..b8a38cf0fd 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -86,56 +86,23 @@ KeyframeController::KeyframeController(const KeyframeController ©, const osg KeyframeController::KeyframeController(const Nif::NiKeyframeData *data) : mRotations(data->mRotations) - , mXRotations(data->mXRotations) - , mYRotations(data->mYRotations) - , mZRotations(data->mZRotations) - , mTranslations(data->mTranslations) - , mScales(data->mScales) + , mXRotations(data->mXRotations, 0.f) + , mYRotations(data->mYRotations, 0.f) + , mZRotations(data->mZRotations, 0.f) + , mTranslations(data->mTranslations, osg::Vec3f()) + , mScales(data->mScales, 1.f) { } -osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) -{ - if(time <= keys.begin()->first) - return keys.begin()->second.mValue; - - Nif::QuaternionKeyMap::MapType::const_iterator it = keys.lower_bound(time); - if (it != keys.end()) - { - float aTime = it->first; - const Nif::QuaternionKey* aKey = &it->second; - - assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - - Nif::QuaternionKeyMap::MapType::const_iterator last = --it; - float aLastTime = last->first; - const Nif::QuaternionKey* aLastKey = &last->second; - - float a = (time - aLastTime) / (aTime - aLastTime); - - osg::Quat v1 = aLastKey->mValue; - osg::Quat v2 = aKey->mValue; - // don't take the long path - if (v1.x()*v2.x() + v1.y()*v2.y() + v1.z()*v2.z() + v1.w()*v2.w() < 0) // dotProduct(v1,v2) - v1 = -v1; - - osg::Quat result; - result.slerp(a, v1, v2); - return result; - } - else - return keys.rbegin()->second.mValue; -} - osg::Quat KeyframeController::getXYZRotation(float time) const { float xrot = 0, yrot = 0, zrot = 0; - if (mXRotations.get()) - xrot = interpKey(mXRotations->mKeys, time); - if (mYRotations.get()) - yrot = interpKey(mYRotations->mKeys, time); - if (mZRotations.get()) - zrot = interpKey(mZRotations->mKeys, time); + if (!mXRotations.empty()) + xrot = mXRotations.interpKey(time); + if (!mYRotations.empty()) + yrot = mYRotations.interpKey(time); + if (!mZRotations.empty()) + zrot = mZRotations.interpKey(time); osg::Quat xr(xrot, osg::Vec3f(1,0,0)); osg::Quat yr(yrot, osg::Vec3f(0,1,0)); osg::Quat zr(zrot, osg::Vec3f(0,0,1)); @@ -144,8 +111,8 @@ osg::Quat KeyframeController::getXYZRotation(float time) const osg::Vec3f KeyframeController::getTranslation(float time) const { - if(mTranslations.get() && mTranslations->mKeys.size() > 0) - return interpKey(mTranslations->mKeys, time); + if(!mTranslations.empty()) + return mTranslations.interpKey(time); return osg::Vec3f(); } @@ -162,12 +129,12 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) Nif::Matrix3& rot = userdata->mRotationScale; bool setRot = false; - if(mRotations.get() && !mRotations->mKeys.empty()) + if(!mRotations.empty()) { - mat.setRotate(interpKey(mRotations->mKeys, time)); + mat.setRotate(mRotations.interpKey(time)); setRot = true; } - else if (mXRotations.get() || mYRotations.get() || mZRotations.get()) + else if (!mXRotations.empty() || !mYRotations.empty() || !mZRotations.empty()) { mat.setRotate(getXYZRotation(time)); setRot = true; @@ -186,15 +153,15 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) rot.mValues[i][j] = mat(j,i); // NB column/row major difference float& scale = userdata->mScale; - if(mScales.get() && !mScales->mKeys.empty()) - scale = interpKey(mScales->mKeys, time); + if(!mScales.empty()) + scale = mScales.interpKey(time); for (int i=0;i<3;++i) for (int j=0;j<3;++j) mat(i,j) *= scale; - if(mTranslations.get() && !mTranslations->mKeys.empty()) - mat.setTrans(interpKey(mTranslations->mKeys, time)); + if(!mTranslations.empty()) + mat.setTrans(mTranslations.interpKey(time)); trans->setMatrix(mat); } @@ -216,7 +183,7 @@ GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) { for (unsigned int i=0; imMorphs.size(); ++i) - mKeyFrames.push_back(data->mMorphs[i].mKeyFrames); + mKeyFrames.push_back(FloatInterpolator(data->mMorphs[i].mKeyFrames)); } void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) @@ -228,11 +195,11 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable return; float input = getInputValue(nv); int i = 0; - for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) + for (std::vector::iterator it = mKeyFrames.begin()+1; it != mKeyFrames.end(); ++it,++i) { float val = 0; - if (!(*it)->mKeys.empty()) - val = interpKey((*it)->mKeys, input); + if (!(*it).empty()) + val = it->interpKey(input); val = std::max(0.f, std::min(1.f, val)); osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); @@ -252,10 +219,10 @@ UVController::UVController() } UVController::UVController(const Nif::NiUVData *data, std::set textureUnits) - : mUTrans(data->mKeyList[0]) - , mVTrans(data->mKeyList[1]) - , mUScale(data->mKeyList[2]) - , mVScale(data->mKeyList[3]) + : mUTrans(data->mKeyList[0], 0.f) + , mVTrans(data->mKeyList[1], 0.f) + , mUScale(data->mKeyList[2], 1.f) + , mVScale(data->mKeyList[3], 1.f) , mTextureUnits(textureUnits) { } @@ -282,10 +249,10 @@ void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) if (hasInput()) { float value = getInputValue(nv); - float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); - float uScale = interpKey(mUScale->mKeys, value, 1.0f); - float vScale = interpKey(mVScale->mKeys, value, 1.0f); + float uTrans = mUTrans.interpKey(value); + float vTrans = mVTrans.interpKey(value); + float uScale = mUScale.interpKey(value); + float vScale = mVScale.interpKey(value); osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); mat.setTrans(uTrans, vTrans, 0); @@ -340,7 +307,7 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) } AlphaController::AlphaController(const Nif::NiFloatData *data) - : mData(data->mKeyList) + : mData(data->mKeyList, 1.f) { } @@ -350,7 +317,7 @@ AlphaController::AlphaController() } AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) - : StateSetUpdater(copy, copyop), Controller(copy), ValueInterpolator() + : StateSetUpdater(copy, copyop), Controller(copy) , mData(copy.mData) { } @@ -366,7 +333,7 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) { - float value = interpKey(mData->mKeys, getInputValue(nv)); + float value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); diffuse.a() = value; @@ -375,7 +342,7 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) } MaterialColorController::MaterialColorController(const Nif::NiPosData *data) - : mData(data->mKeyList) + : mData(data->mKeyList, osg::Vec3f(1,1,1)) { } @@ -400,7 +367,7 @@ void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *n { if (hasInput()) { - osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); + osg::Vec3f value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 803ce77a2d..eabf80f131 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -42,38 +42,116 @@ namespace osgAnimation namespace NifOsg { + // interpolation of keyframes + template class ValueInterpolator { - protected: - template - T interpKey (const std::map< float, Nif::KeyT >& keys, float time, T defaultValue = T()) const + public: + ValueInterpolator() + : mDefaultVal(typename MapT::ValueType()) { - if (keys.size() == 0) - return defaultValue; + } + + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + : mKeys(keys) + , mDefaultVal(defaultVal) + { + if (keys) + { + mLastLowKey = mKeys->mKeys.end(); + mLastHighKey = mKeys->mKeys.end(); + } + } + + typename MapT::ValueType interpKey(float time) const + { + if (empty()) + return mDefaultVal; + + const typename MapT::MapType & keys = mKeys->mKeys; if(time <= keys.begin()->first) return keys.begin()->second.mValue; - typename std::map< float, Nif::KeyT >::const_iterator it = keys.lower_bound(time); + // retrieve the current position in the map, optimized for the most common case + // where time moves linearly along the keyframe track + typename MapT::MapType::const_iterator it = mLastHighKey; + if (mLastHighKey != keys.end()) + { + if (time > mLastHighKey->first) + { + // try if we're there by incrementing one + ++mLastLowKey; + ++mLastHighKey; + it = mLastHighKey; + } + if (mLastHighKey == keys.end() || (time < mLastLowKey->first || time > mLastHighKey->first)) + it = keys.lower_bound(time); // still not there, reorient by performing lower_bound check on the whole map + } + else + it = keys.lower_bound(time); + + // now do the actual interpolation if (it != keys.end()) { float aTime = it->first; - const Nif::KeyT* aKey = &it->second; + const typename MapT::KeyType* aKey = &it->second; + + // cache for next time + mLastHighKey = it; assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function - typename std::map< float, Nif::KeyT >::const_iterator last = --it; + typename MapT::MapType::const_iterator last = --it; + mLastLowKey = last; float aLastTime = last->first; - const Nif::KeyT* aLastKey = &last->second; + const typename MapT::KeyType* aLastKey = &last->second; float a = (time - aLastTime) / (aTime - aLastTime); - return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); + + return InterpolationFunc()(aLastKey->mValue, aKey->mValue, a); } else return keys.rbegin()->second.mValue; } + + bool empty() const + { + return !mKeys || mKeys->mKeys.empty(); + } + + private: + mutable typename MapT::MapType::const_iterator mLastLowKey; + mutable typename MapT::MapType::const_iterator mLastHighKey; + + boost::shared_ptr mKeys; + + typename MapT::ValueType mDefaultVal; }; + struct LerpFunc + { + template + inline ValueType operator()(const ValueType& a, const ValueType& b, float fraction) + { + return a + ((b - a) * fraction); + } + }; + + struct QuaternionSlerpFunc + { + inline osg::Quat operator()(const osg::Quat& a, const osg::Quat& b, float fraction) + { + osg::Quat result; + result.slerp(fraction, a, b); + return result; + } + }; + + typedef ValueInterpolator QuaternionInterpolator; + typedef ValueInterpolator FloatInterpolator; + typedef ValueInterpolator Vec3Interpolator; + class ControllerFunction : public SceneUtil::ControllerFunction { private: @@ -98,7 +176,7 @@ namespace NifOsg }; /// Must be set on an osgAnimation::MorphGeometry. - class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller, public ValueInterpolator + class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller { public: GeomMorpherController(const Nif::NiMorphData* data); @@ -110,10 +188,10 @@ namespace NifOsg virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - std::vector mKeyFrames; + std::vector mKeyFrames; }; - class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller { public: KeyframeController(const Nif::NiKeyframeData *data); @@ -127,23 +205,19 @@ namespace NifOsg virtual void operator() (osg::Node*, osg::NodeVisitor*); private: - Nif::QuaternionKeyMapPtr mRotations; + QuaternionInterpolator mRotations; - Nif::FloatKeyMapPtr mXRotations; - Nif::FloatKeyMapPtr mYRotations; - Nif::FloatKeyMapPtr mZRotations; + FloatInterpolator mXRotations; + FloatInterpolator mYRotations; + FloatInterpolator mZRotations; - Nif::Vector3KeyMapPtr mTranslations; - Nif::FloatKeyMapPtr mScales; - - using ValueInterpolator::interpKey; - - osg::Quat interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time); + Vec3Interpolator mTranslations; + FloatInterpolator mScales; osg::Quat getXYZRotation(float time) const; }; - class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { public: UVController(); @@ -156,10 +230,10 @@ namespace NifOsg virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv); private: - Nif::FloatKeyMapPtr mUTrans; - Nif::FloatKeyMapPtr mVTrans; - Nif::FloatKeyMapPtr mUScale; - Nif::FloatKeyMapPtr mVScale; + FloatInterpolator mUTrans; + FloatInterpolator mVTrans; + FloatInterpolator mUScale; + FloatInterpolator mVScale; std::set mTextureUnits; }; @@ -180,10 +254,10 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: - Nif::FloatKeyMapPtr mData; + FloatInterpolator mData; public: AlphaController(const Nif::NiFloatData *data); @@ -197,10 +271,10 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller, public ValueInterpolator + class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: - Nif::Vector3KeyMapPtr mData; + Vec3Interpolator mData; public: MaterialColorController(const Nif::NiPosData *data); diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index e30837d394..08b62901b3 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -127,7 +127,7 @@ void GrowFadeAffector::operate(osgParticle::Particle* particle, double /* dt */) } ParticleColorAffector::ParticleColorAffector(const Nif::NiColorData *clrdata) - : mData(*clrdata) + : mData(clrdata->mKeyMap, osg::Vec4f(1,1,1,1)) { } @@ -145,7 +145,7 @@ ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */) { float time = static_cast(particle->getAge()/particle->getLifeTime()); - osg::Vec4f color = interpKey(mData.mKeyMap->mKeys, time, osg::Vec4f(1,1,1,1)); + osg::Vec4f color = mData.interpKey(time); particle->setColorRange(osgParticle::rangev4(color, color)); } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index bfb127218d..ff4c66758f 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -130,7 +130,8 @@ namespace NifOsg float mCachedDefaultSize; }; - class ParticleColorAffector : public osgParticle::Operator, public ValueInterpolator + typedef ValueInterpolator Vec4Interpolator; + class ParticleColorAffector : public osgParticle::Operator { public: ParticleColorAffector(const Nif::NiColorData* clrdata); @@ -142,7 +143,7 @@ namespace NifOsg virtual void operate(osgParticle::Particle* particle, double dt); private: - Nif::NiColorData mData; + Vec4Interpolator mData; }; class GravityAffector : public osgParticle::Operator From e5ec4fe042f34a163c441b9de7ab04be1e8377c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Nov 2015 21:02:16 +0100 Subject: [PATCH 1530/1812] Add const specifier --- components/nifosg/controller.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index eabf80f131..ba353e2474 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,7 @@ namespace NifOsg { } - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) : mKeys(keys) , mDefaultVal(defaultVal) { @@ -124,7 +124,7 @@ namespace NifOsg mutable typename MapT::MapType::const_iterator mLastLowKey; mutable typename MapT::MapType::const_iterator mLastHighKey; - boost::shared_ptr mKeys; + boost::shared_ptr mKeys; typename MapT::ValueType mDefaultVal; }; From e42f4999bdf6e49e2a1eefbc4e058a4723e17244 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 1 Dec 2015 04:06:34 +0100 Subject: [PATCH 1531/1812] Quick fix for building on MSVC --- components/nifosg/controller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index ba353e2474..7dae7f88a6 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,7 @@ namespace NifOsg { } - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) : mKeys(keys) , mDefaultVal(defaultVal) { From cfcbd20d996132697cfaaa0ad3d6fd8829b02579 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 1 Dec 2015 04:19:30 +0100 Subject: [PATCH 1532/1812] Let's put it as a MSVC-only fix for now --- components/nifosg/controller.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 7dae7f88a6..a8f52b4437 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -52,7 +52,11 @@ namespace NifOsg { } +#ifdef _MSC_VER ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) +#else + ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) +#endif : mKeys(keys) , mDefaultVal(defaultVal) { From 2327a418262880877ae51169ec19ac7e91de5bff Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:09:05 +0100 Subject: [PATCH 1533/1812] Fix journal freeze --- apps/openmw/mwgui/journalviewmodel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 03e4813b3e..f566e7769c 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -72,8 +72,6 @@ struct JournalViewModelImpl : JournalViewModel } } - wchar_t tolower (wchar_t ch) const { return tolower (ch); } - bool isEmpty () const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); From c912310c52816aa0ff657253ad1fe3fe1643a4b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:16:21 +0100 Subject: [PATCH 1534/1812] Don't add persuasion results to the journal --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f8c9bb38e4..c5e271b7a3 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -298,15 +298,18 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); - // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, - // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); - iter!=dialogue.mInfo.end(); ++iter) + if (dialogue.mType == ESM::Dialogue::Topic) { - if (iter->mId == info->mId) + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal. + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); - break; + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); + break; + } } } From c9d710f3340e19e3fb7260f6076ff33a53a3299a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 16:18:19 +0100 Subject: [PATCH 1535/1812] Use a typedef to avoid conditional compiling --- components/nifosg/controller.hpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index a8f52b4437..e1e969d066 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -47,16 +47,14 @@ namespace NifOsg class ValueInterpolator { public: + typedef typename MapT::ValueType ValueT; + ValueInterpolator() - : mDefaultVal(typename MapT::ValueType()) + : mDefaultVal(ValueT()) { } -#ifdef _MSC_VER - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = MapT::ValueType()) -#else - ValueInterpolator(boost::shared_ptr keys, typename MapT::ValueType defaultVal = typename MapT::ValueType()) -#endif + ValueInterpolator(boost::shared_ptr keys, ValueT defaultVal = ValueT()) : mKeys(keys) , mDefaultVal(defaultVal) { @@ -67,7 +65,7 @@ namespace NifOsg } } - typename MapT::ValueType interpKey(float time) const + ValueT interpKey(float time) const { if (empty()) return mDefaultVal; @@ -130,7 +128,7 @@ namespace NifOsg boost::shared_ptr mKeys; - typename MapT::ValueType mDefaultVal; + ValueT mDefaultVal; }; struct LerpFunc From 84305a1297f6749a8ec82df2ec95e4a4a6d7d91c Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 2 Dec 2015 04:17:54 +0300 Subject: [PATCH 1536/1812] Reuse DATADIR in data paths --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d038936d3d..5106db666c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,8 @@ if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") elseif(UNIX) - set(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") else() set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") From 3d12b2ca9d242fdc55d8dfb0895d23e76b17b3df Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Dec 2015 23:04:02 +0100 Subject: [PATCH 1537/1812] Add NifFileManager to avoid duplicate parsing of the NIFFile in SceneManager and BulletShapeManager. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 4 ++ components/CMakeLists.txt | 2 +- components/resource/bulletshapemanager.cpp | 8 +-- components/resource/bulletshapemanager.hpp | 4 +- components/resource/niffilemanager.cpp | 64 ++++++++++++++++++++++ components/resource/niffilemanager.hpp | 45 +++++++++++++++ components/resource/resourcesystem.cpp | 14 ++++- components/resource/resourcesystem.hpp | 8 ++- components/resource/scenemanager.cpp | 12 ++-- components/resource/scenemanager.hpp | 6 +- 11 files changed, 153 insertions(+), 16 deletions(-) create mode 100644 components/resource/niffilemanager.cpp create mode 100644 components/resource/niffilemanager.hpp diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1f59c5c997..db010d0fb5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -636,7 +636,7 @@ namespace MWPhysics // --------------------------------------------------------------- PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) - : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) + : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager())) , mDebugDrawEnabled(false) , mTimeAccum(0.0f) , mWaterHeight(0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 5598598d05..c6b50aae3e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -403,6 +403,8 @@ namespace MWWorld // Delay the map update until scripts have been given a chance to run. // If we don't do this, objects that should be disabled will still appear on the map. mNeedMapUpdate = true; + + mRendering.getResourceSystem()->clearCache(); } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -518,6 +520,8 @@ namespace MWWorld // Delay the map update until scripts have been given a chance to run. // If we don't do this, objects that should be disabled will still appear on the map. mNeedMapUpdate = true; + + mRendering.getResourceSystem()->clearCache(); } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0f2906ce5d..3e4225d7cd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager ) add_component_dir (sceneutil diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 9aae1cad43..5933221906 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -12,6 +12,7 @@ #include "bulletshape.hpp" #include "scenemanager.hpp" +#include "niffilemanager.hpp" namespace Resource @@ -94,9 +95,10 @@ private: btTriangleMesh* mTriangleMesh; }; -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) : mVFS(vfs) , mSceneManager(sceneMgr) + , mNifFileManager(nifFileManager) { } @@ -115,8 +117,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - Files::IStreamPtr file = mVFS->get(normalized); - size_t extPos = normalized.find_last_of('.'); std::string ext; if (extPos != std::string::npos && extPos+1 < normalized.size()) @@ -126,7 +126,7 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: { NifBullet::BulletNifLoader loader; // might be worth sharing NIFFiles with SceneManager in some way - shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); + shape = loader.load(mNifFileManager->get(normalized)); } else { diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index 6b8e64c21b..ac1523495c 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -16,6 +16,7 @@ namespace VFS namespace Resource { class SceneManager; + class NifFileManager; class BulletShape; class BulletShapeInstance; @@ -23,7 +24,7 @@ namespace Resource class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr); + BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); @@ -31,6 +32,7 @@ namespace Resource private: const VFS::Manager* mVFS; SceneManager* mSceneManager; + NifFileManager* mNifFileManager; typedef std::map > Index; Index mIndex; diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp new file mode 100644 index 0000000000..9e426bf60d --- /dev/null +++ b/components/resource/niffilemanager.cpp @@ -0,0 +1,64 @@ +#include "niffilemanager.hpp" + +#include +#include + +#include + +namespace Resource +{ + + class NifFileHolder : public osg::Object + { + public: + NifFileHolder(const Nif::NIFFilePtr& file) + : mNifFile(file) + { + } + NifFileHolder(const NifFileHolder& copy, const osg::CopyOp& copyop) + : mNifFile(copy.mNifFile) + { + } + + NifFileHolder() + { + } + + META_Object(Resource, NifFileHolder) + + Nif::NIFFilePtr mNifFile; + }; + + NifFileManager::NifFileManager(const VFS::Manager *vfs) + : mVFS(vfs) + { + mCache = new osgDB::ObjectCache; + } + + NifFileManager::~NifFileManager() + { + + } + + void NifFileManager::clearCache() + { + // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager, + // so we'll simply drop all nif files here, unlikely to need them again + mCache->clear(); + } + + Nif::NIFFilePtr NifFileManager::get(const std::string &name) + { + osg::ref_ptr obj = mCache->getRefFromObjectCache(name); + if (obj) + return static_cast(obj.get())->mNifFile; + else + { + Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->get(name), name)); + obj = new NifFileHolder(file); + mCache->addEntryToObjectCache(name, obj); + return file; + } + } + +} diff --git a/components/resource/niffilemanager.hpp b/components/resource/niffilemanager.hpp new file mode 100644 index 0000000000..90ad9fc294 --- /dev/null +++ b/components/resource/niffilemanager.hpp @@ -0,0 +1,45 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H +#define OPENMW_COMPONENTS_RESOURCE_NIFFILEMANAGER_H + +#include + +#include + +namespace VFS +{ + class Manager; +} + +namespace osgDB +{ + class ObjectCache; +} + +namespace Resource +{ + + /// @brief Handles caching of NIFFiles. + /// @note The NifFileManager is completely thread safe. + class NifFileManager + { + public: + NifFileManager(const VFS::Manager* vfs); + ~NifFileManager(); + + void clearCache(); + + /// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet. + /// @note For performance reasons the NifFileManager does not handle case folding, needs + /// to be done in advance by other managers accessing the NifFileManager. + Nif::NIFFilePtr get(const std::string& name); + + private: + // Use the osgDB::ObjectCache so objects are retrieved in thread safe way + osg::ref_ptr mCache; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index bd6824079e..2dfd30314e 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,6 +2,7 @@ #include "scenemanager.hpp" #include "texturemanager.hpp" +#include "niffilemanager.hpp" namespace Resource { @@ -9,8 +10,9 @@ namespace Resource ResourceSystem::ResourceSystem(const VFS::Manager *vfs) : mVFS(vfs) { + mNifFileManager.reset(new NifFileManager(vfs)); mTextureManager.reset(new TextureManager(vfs)); - mSceneManager.reset(new SceneManager(vfs, mTextureManager.get())); + mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); } ResourceSystem::~ResourceSystem() @@ -28,6 +30,16 @@ namespace Resource return mTextureManager.get(); } + NifFileManager *ResourceSystem::getNifFileManager() + { + return mNifFileManager.get(); + } + + void ResourceSystem::clearCache() + { + mNifFileManager->clearCache(); + } + const VFS::Manager* ResourceSystem::getVFS() const { return mVFS; diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 7c00a11eef..7f90bff27a 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -13,8 +13,9 @@ namespace Resource class SceneManager; class TextureManager; + class NifFileManager; - /// @brief Wrapper class that constructs and provides access to the various resource subsystems. + /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but /// are built around the use of a single virtual file system. class ResourceSystem @@ -25,12 +26,17 @@ namespace Resource SceneManager* getSceneManager(); TextureManager* getTextureManager(); + NifFileManager* getNifFileManager(); + + /// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced. + void clearCache(); const VFS::Manager* getVFS() const; private: std::auto_ptr mSceneManager; std::auto_ptr mTextureManager; + std::auto_ptr mNifFileManager; const VFS::Manager* mVFS; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b2ba5c4cfa..3ee7a8c001 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -21,6 +21,7 @@ #include #include "texturemanager.hpp" +#include "niffilemanager.hpp" namespace { @@ -104,9 +105,10 @@ namespace namespace Resource { - SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) + SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager) : mVFS(vfs) , mTextureManager(textureManager) + , mNifFileManager(nifFileManager) , mParticleSystemMask(~0u) { } @@ -150,11 +152,11 @@ namespace Resource return std::string(); } - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr) + osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr, Resource::NifFileManager* nifFileManager) { std::string ext = getFileExtension(normalizedFilename); if (ext == "nif") - return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr); + return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), textureMgr); else { osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); @@ -195,14 +197,14 @@ namespace Resource { Files::IStreamPtr file = mVFS->get(normalized); - loaded = load(file, normalized, mTextureManager); + loaded = load(file, normalized, mTextureManager, mNifFileManager); } catch (std::exception& e) { std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); normalized = "meshes/marker_error.nif"; - loaded = load(file, normalized, mTextureManager); + loaded = load(file, normalized, mTextureManager, mNifFileManager); } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 5ecb875acd..3c1984fd91 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -10,6 +10,7 @@ namespace Resource { class TextureManager; + class NifFileManager; } namespace VFS @@ -34,7 +35,7 @@ namespace Resource class SceneManager { public: - SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager); + SceneManager(const VFS::Manager* vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager); ~SceneManager(); /// Get a read-only copy of this scene "template" @@ -66,7 +67,7 @@ namespace Resource /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); - /// @note If you used SceneManager::attachTo, this was called automatically. + /// @note SceneManager::attachTo calls this method automatically, only needs to be called by users if manually attaching void notifyAttached(osg::Node* node) const; const VFS::Manager* getVFS() const; @@ -79,6 +80,7 @@ namespace Resource private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; + Resource::NifFileManager* mNifFileManager; osg::ref_ptr mIncrementalCompileOperation; From 6cf2c352351e4ea9071cdfd99e39ccdf794e9eae Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 13:57:42 +0100 Subject: [PATCH 1538/1812] Don't rely on the _particles vector implementation details This will allow compiling OpenMW with an osgParticle optimization to be pushed to OpenMW/osg. --- components/nifosg/particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 08b62901b3..e3162bcd95 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -23,7 +23,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp &co { // For some reason the osgParticle constructor doesn't copy the particles for (int i=0;i Date: Wed, 2 Dec 2015 14:24:48 +0100 Subject: [PATCH 1539/1812] Eliminate a dynamic_cast in ParticleSystemController --- components/nifosg/controller.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index b8a38cf0fd..28f61e4b6c 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -435,10 +435,9 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv { if (hasInput()) { - osgParticle::ParticleProcessor* emitter = dynamic_cast(node); + osgParticle::ParticleProcessor* emitter = static_cast(node); float time = getInputValue(nv); - if (emitter) - emitter->setEnabled(time >= mEmitStart && time < mEmitStop); + emitter->setEnabled(time >= mEmitStart && time < mEmitStop); } traverse(node, nv); } From d3fa8a8602de45f06a995302e426e03dfaa61580 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 15:14:39 +0100 Subject: [PATCH 1540/1812] Add osgDB::ObjectCache to the repository to work around it not being available in OSG 3.2 --- components/CMakeLists.txt | 2 +- components/resource/niffilemanager.cpp | 3 +- components/resource/objectcache.cpp | 141 +++++++++++++++++++++++++ components/resource/objectcache.hpp | 92 ++++++++++++++++ 4 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 components/resource/objectcache.cpp create mode 100644 components/resource/objectcache.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3e4225d7cd..a6e9d8f137 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager + scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache ) add_component_dir (sceneutil diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 9e426bf60d..fd25c1c409 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -1,8 +1,9 @@ #include "niffilemanager.hpp" -#include #include +#include "objectcache.hpp" + #include namespace Resource diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp new file mode 100644 index 0000000000..c369e5c249 --- /dev/null +++ b/components/resource/objectcache.cpp @@ -0,0 +1,141 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + +#include "objectcache.hpp" + +#if OSG_VERSION_LESS_THAN(3,4,0) + +#include + +using namespace osgDB; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// ObjectCache +// +ObjectCache::ObjectCache(): + osg::Referenced(true) +{ +// OSG_NOTICE<<"Constructed ObjectCache"< lock1(_objectCacheMutex); + OpenThreads::ScopedLock lock2(objectCache->_objectCacheMutex); + + // OSG_NOTICE<<"Inserting objects to main ObjectCache "<_objectCache.size()<_objectCache.begin(), objectCache->_objectCache.end()); +} + + +void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache[filename]=ObjectTimeStampPair(object,timestamp); +} + +osg::Object* ObjectCache::getFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) return itr->second.first.get(); + else return 0; +} + +osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) + { + // OSG_NOTICE<<"Found "<second.first; + } + else return 0; +} + +void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // look for objects with external references and update their time stamp. + for(ObjectCacheMap::iterator itr=_objectCache.begin(); + itr!=_objectCache.end(); + ++itr) + { + // if ref count is greater the 1 the object has an external reference. + if (itr->second.first->referenceCount()>1) + { + // so update it time stamp. + itr->second.second = referenceTime; + } + } +} + +void ObjectCache::removeExpiredObjectsInCache(double expiryTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // Remove expired entries from object cache + ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) + { + if (oitr->second.second<=expiryTime) + { + _objectCache.erase(oitr++); + } + else + { + ++oitr; + } + } +} + +void ObjectCache::removeFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) _objectCache.erase(itr); +} + +void ObjectCache::clear() +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); +} + +void ObjectCache::releaseGLObjects(osg::State* state) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + for(ObjectCacheMap::iterator itr = _objectCache.begin(); + itr != _objectCache.end(); + ++itr) + { + osg::Object* object = itr->second.first.get(); + object->releaseGLObjects(state); + } +} + +#endif diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp new file mode 100644 index 0000000000..0a342f27f6 --- /dev/null +++ b/components/resource/objectcache.hpp @@ -0,0 +1,92 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + +// Wrapper for osgDB/ObjectCache. Works around ObjectCache not being available in old OSG 3.2. +// Use "#include objectcache.hpp" in place of "#include + +#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) +#include +#else + +#include + +#include +#include + +#include + +namespace osgDB { + +class /*OSGDB_EXPORT*/ ObjectCache : public osg::Referenced +{ + public: + + ObjectCache(); + + /** For each object in the cache which has an reference count greater than 1 + * (and therefore referenced by elsewhere in the application) set the time stamp + * for that object in the cache to specified time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required. + * The time used should be taken from the FrameStamp::getReferenceTime().*/ + void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime); + + /** Removed object in the cache which have a time stamp at or before the specified expiry time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required, and called after the a called + * after the call to updateTimeStampOfObjectsInCacheWithExternalReferences(expirtyTime).*/ + void removeExpiredObjectsInCache(double expiryTime); + + /** Remove all objects in the cache regardless of having external references or expiry times.*/ + void clear(); + + /** Add contents of specified ObjectCache to this object cache.*/ + void addObjectCache(ObjectCache* object); + + /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ + void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + + /** Remove Object from cache.*/ + void removeFromObjectCache(const std::string& fileName); + + /** Get an Object from the object cache*/ + osg::Object* getFromObjectCache(const std::string& fileName); + + /** Get an ref_ptr from the object cache*/ + osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + + /** call rleaseGLObjects on all objects attached to the object cache.*/ + void releaseGLObjects(osg::State* state); + + protected: + + virtual ~ObjectCache(); + + typedef std::pair, double > ObjectTimeStampPair; + typedef std::map ObjectCacheMap; + + ObjectCacheMap _objectCache; + OpenThreads::Mutex _objectCacheMutex; + +}; + +} + +#endif + +#endif From 87e44bf627e726dd3ea6c5a834de25ae4c8b31b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 15:21:13 +0100 Subject: [PATCH 1541/1812] Small fix --- components/resource/objectcache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index c369e5c249..8c2c524165 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -11,11 +11,11 @@ * OpenSceneGraph Public License for more details. */ -#include "objectcache.hpp" +#include #if OSG_VERSION_LESS_THAN(3,4,0) -#include +#include "objectcache.hpp" using namespace osgDB; From 7d6fa1b65a828f700170fbaa4f25af090f4cd3bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 16:14:04 +0100 Subject: [PATCH 1542/1812] CMakeLists.txt: Don't use DATADIR before it's defined --- CMakeLists.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5106db666c..498b439611 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,18 +83,6 @@ if (MSVC) option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) endif() -# Location of morrowind data files -if (APPLE) - set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") -elseif(UNIX) - set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") -else() - set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") -endif(APPLE) - if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() @@ -436,6 +424,18 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) +# Location of morrowind data files +if (APPLE) + set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") +elseif(UNIX) + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") +else() + set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") +endif(APPLE) + if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") From 77965501d4011aece811b3efecdfd89a3af260c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 17:33:55 +0100 Subject: [PATCH 1543/1812] CMakeLists.txt: set the OPENMW_RESOURCE_FILES before configuring openmw.cfg --- CMakeLists.txt | 55 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 498b439611..f403b99e0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,33 @@ if (MSVC) option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF) endif() +# Set up common paths +if (APPLE) + set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") +elseif(UNIX) + # Paths + SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") + SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") + SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") + SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") + SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") + SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") + IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr") + SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix") + ELSE() + SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix") + ENDIF() + SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") + + set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") +else() + set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") +endif(APPLE) + if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() @@ -349,21 +376,7 @@ elseif (MSVC) endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) - # Linux building - # Paths - SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") - SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") - SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") - SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") - SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") - SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") - IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr") - SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix") - ELSE() - SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix") - ENDIF() - SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") + # Linux installation # Install binaries IF(BUILD_OPENMW) @@ -424,18 +437,6 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) -# Location of morrowind data files -if (APPLE) - set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") -elseif(UNIX) - set(MORROWIND_DATA_FILES "${DATADIR}/data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "${DATADIR}/resources" CACHE PATH "location of OpenMW resources files") -else() - set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") -endif(APPLE) - if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") From 647bed7f40c06d2e805952ebf55c69606a3e2a62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 Dec 2015 19:21:10 +0100 Subject: [PATCH 1544/1812] Do not read openmw.cfg from global path if one was found in the local path --- components/files/configurationmanager.cpp | 15 +++++++++++---- components/files/configurationmanager.hpp | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index dc6f02b608..9c9cebe96f 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -60,10 +60,14 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m loadConfig(mFixedPath.getUserConfigPath(), variables, description); boost::program_options::notify(variables); - loadConfig(mFixedPath.getLocalPath(), variables, description); - boost::program_options::notify(variables); - loadConfig(mFixedPath.getGlobalConfigPath(), variables, description); + // read either local or global config depending on type of installation + bool loaded = loadConfig(mFixedPath.getLocalPath(), variables, description); boost::program_options::notify(variables); + if (!loaded) + { + loadConfig(mFixedPath.getGlobalConfigPath(), variables, description); + boost::program_options::notify(variables); + } mSilent = silent; } @@ -126,7 +130,7 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool cre boost::bind(&boost::filesystem::path::empty, _1)), dataDirs.end()); } -void ConfigurationManager::loadConfig(const boost::filesystem::path& path, +bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, boost::program_options::options_description& description) { @@ -145,13 +149,16 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path, if (!mSilent) std::cout << "done." << std::endl; + return true; } else { if (!mSilent) std::cout << "failed." << std::endl; + return false; } } + return false; } const boost::filesystem::path& ConfigurationManager::getGlobalPath() const diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 102f7c3cb7..58ee5c1aef 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -58,7 +58,7 @@ struct ConfigurationManager typedef std::tr1::unordered_map TokensMappingContainer; #endif - void loadConfig(const boost::filesystem::path& path, + bool loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, boost::program_options::options_description& description); From bd5057aa3cf7f15c3cab799f13311922389f45c5 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Wed, 2 Dec 2015 22:40:04 +0300 Subject: [PATCH 1545/1812] enable opengl es1 --- CMakeLists.txt | 42 ++++++-- apps/openmw/CMakeLists.txt | 35 ++++++- apps/openmw/android_main.c | 1 - apps/openmw/main.cpp | 2 +- cmake/FindOpenGLES.cmake | 94 +++++++++++++++++ components/CMakeLists.txt | 124 ++++++++++++++--------- components/sdlutil/sdlcursormanager.cpp | 7 ++ components/sdlutil/sdlgraphicswindow.cpp | 8 +- 8 files changed, 250 insertions(+), 63 deletions(-) create mode 100644 cmake/FindOpenGLES.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f403b99e0b..61a44b758d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,20 +159,36 @@ if (WIN32) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) endif() +if (ANDROID) + set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") + set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) + add_definitions (-DOSG_PLUGINS_DIR) + set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) +endif (ANDROID) + +option(OPENGL_ES "enable opengl es support" FALSE ) + +if (OPENGL_ES) + INCLUDE(cmake/FindOpenGLES.cmake) + add_definitions (-DOPENGL_ES) + INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) +endif (OPENGLES) + # Dependencies +if (NOT ANDROID) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + message(STATUS "Using Qt${DESIRED_QT_VERSION}") -set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") -message(STATUS "Using Qt${DESIRED_QT_VERSION}") - -if (DESIRED_QT_VERSION MATCHES 4) - find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) -else() - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Core REQUIRED) - find_package(Qt5Network REQUIRED) - find_package(Qt5OpenGL REQUIRED) + if (DESIRED_QT_VERSION MATCHES 4) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL) + else() + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Core REQUIRED) + find_package(Qt5Network REQUIRED) + find_package(Qt5OpenGL REQUIRED) # Instruct CMake to run moc automatically when needed. #set(CMAKE_AUTOMOC ON) + endif() endif() # Fix for not visible pthreads functions for linker with glibc 2.15 @@ -204,7 +220,11 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +if (NOT ANDROID) + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +else() + find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +endif() include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e2d333e562..5883d9a26c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -140,18 +140,51 @@ target_link_libraries(openmw ) if (ANDROID) + set (OSG_PLUGINS + -Wl,--whole-archive + ${OSG_PLUGINS_DIR}/libosgdb_dds.a + ${OSG_PLUGINS_DIR}/libosgdb_bmp.a + ${OSG_PLUGINS_DIR}/libosgdb_tga.a + ${OSG_PLUGINS_DIR}/libosgdb_gif.a + ${OSG_PLUGINS_DIR}/libosgdb_jpeg.a + ${OSG_PLUGINS_DIR}/libosgdb_png.a + -Wl,--no-whole-archive + ) target_link_libraries(openmw EGL android log dl MyGUIEngineStatic - cpufeatures BulletCollision LinearMath + z + osg + osgDB + osgAnimation + osgText + osgUtil + osgShadow + ${OPENSCENEGRAPH_LIBRARIES} + ${OSG_PLUGINS} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + jpeg + gif + png ) endif (ANDROID) + +if (OPENGL_ES) + target_link_libraries(openmw + ${OPENGLES_gl_LIBRARY} + ${OPENGLES2_gl_LIBRARY} + ) +endif (OPENGL_ES) + if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 47b77a8b38..8cd69e8f01 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,4 +1,3 @@ -#include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 17ef46246a..c3f0f8688e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -23,7 +23,7 @@ #endif -#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 #else #define USE_CRASH_CATCHER 0 diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake new file mode 100644 index 0000000000..7ee2c07f18 --- /dev/null +++ b/cmake/FindOpenGLES.cmake @@ -0,0 +1,94 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find OpenGLES +# Once done this will define +# +# OPENGLES_FOUND - system has OpenGLES +# OPENGLES_INCLUDE_DIR - the GL include directory +# OPENGLES_LIBRARIES - Link these to use OpenGLES + +IF (WIN32) + IF (CYGWIN) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) + + ELSE (CYGWIN) + + IF(BORLAND) + SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") + ELSE(BORLAND) + #MS compiler - todo - fix the following line: + SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") + ENDIF(BORLAND) + + ENDIF (CYGWIN) + +ELSE (WIN32) + + IF (APPLE) + + #create_search_paths(/Developer/Platforms) + #findpkg_framework(OpenGLES) + #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") + + ELSE(APPLE) + + FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h + /opt/vc/include + /opt/graphics/OpenGL/include + /usr/openwin/share/include + /usr/X11R6/include + /usr/include + ) + + FIND_LIBRARY(OPENGLES_gl_LIBRARY + NAMES GLES_CM GLESv1_CM + PATHS /opt/vc/lib + /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib + ) + + # On Unix OpenGL most certainly always requires X11. + # Feel free to tighten up these conditions if you don't + # think this is always true. + + #IF (OPENGLES_gl_LIBRARY) + # IF(NOT X11_FOUND) + # INCLUDE(FindX11) + # ENDIF(NOT X11_FOUND) + # IF (X11_FOUND) + # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) + # ENDIF (X11_FOUND) + #ENDIF (OPENGLES_gl_LIBRARY) + + ENDIF(APPLE) +ENDIF (WIN32) + +SET( OPENGLES_FOUND "NO" ) +IF(OPENGLES_gl_LIBRARY) + + SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) + + SET( OPENGLES_FOUND "YES" ) + +ENDIF(OPENGLES_gl_LIBRARY) + +MARK_AS_ADVANCED( + OPENGLES_INCLUDE_DIR + OPENGLES_gl_LIBRARY +) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6e9d8f137..92e11c51c3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,7 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -find_package(OpenGL REQUIRED) +if (NOT OPENGL_ES) + find_package(OpenGL REQUIRED) +endif() # source files @@ -137,29 +139,31 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -add_component_qt_dir (contentselector - model/modelitem model/esmfile - model/naturalsort model/contentmodel - model/loadordererror - view/combobox view/contentselector - ) -add_component_qt_dir (config - gamesettings - launchersettings - settingsbase - ) +if (NOT ANDROID) + add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + model/loadordererror + view/combobox view/contentselector + ) + add_component_qt_dir (config + gamesettings + launchersettings + settingsbase + ) -add_component_qt_dir (process - processinvoker -) + add_component_qt_dir (process + processinvoker + ) -if (DESIRED_QT_VERSION MATCHES 4) - include(${QT_USE_FILE}) - QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) -else() - QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + if (DESIRED_QT_VERSION MATCHES 4) + include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + else() + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) + QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + endif() endif() if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -172,38 +176,62 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} -) +if (NOT ANDROID) + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} + ) +else() + target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${MYGUI_LIBRARIES} + ) +endif() if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (DESIRED_QT_VERSION MATCHES 4) - target_link_libraries(components - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY}) -else() - qt5_use_modules(components Widgets Core) +if (NOT ANDROID) + if (DESIRED_QT_VERSION MATCHES 4) + target_link_libraries(components + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY}) + else() + qt5_use_modules(components Widgets Core) + endif() endif() if (GIT_CHECKOUT) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index e1a67aff81..c131621a8f 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,6 +217,13 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { + #ifdef ANDROID + return; + #endif + + if (mCursorMap.find(name) != mCursorMap.end()) + return; + if (mCursorMap.find(name) != mCursorMap.end()) return; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 49afe32a88..a0483e84df 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -92,7 +92,13 @@ void GraphicsWindowSDL2::init() // have to get the current one to be able to restore it afterward. SDL_Window *oldWin = SDL_GL_GetCurrentWindow(); SDL_GLContext oldCtx = SDL_GL_GetCurrentContext(); - + +#ifdef OPENGL_ES + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); +#endif + mContext = SDL_GL_CreateContext(mWindow); if(!mContext) { From b0b3192520aef8b5ab5f932282dc42816303a978 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Wed, 2 Dec 2015 22:50:54 +0300 Subject: [PATCH 1546/1812] delete bad symbol --- apps/openmw/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5883d9a26c..4512e004d2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -181,7 +181,6 @@ endif (ANDROID) if (OPENGL_ES) target_link_libraries(openmw ${OPENGLES_gl_LIBRARY} - ${OPENGLES2_gl_LIBRARY} ) endif (OPENGL_ES) From 816015d6e668f57bf2c4fac32d7d74fee8c0e3c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 05:42:51 -0800 Subject: [PATCH 1547/1812] Avoid inheriting from Sound for sound types --- apps/openmw/mwbase/soundmanager.hpp | 11 + apps/openmw/mwsound/movieaudiofactory.cpp | 4 +- apps/openmw/mwsound/openal_output.cpp | 609 +++++++++------------- apps/openmw/mwsound/openal_output.hpp | 14 +- apps/openmw/mwsound/sound.hpp | 25 +- apps/openmw/mwsound/sound_output.hpp | 7 + apps/openmw/mwsound/soundmanagerimp.cpp | 131 +++-- apps/openmw/mwsound/soundmanagerimp.hpp | 12 +- apps/openmw/mwworld/projectilemanager.cpp | 4 +- apps/openmw/mwworld/weather.cpp | 2 +- 10 files changed, 390 insertions(+), 429 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a91149777d..e75949a5b1 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -107,6 +107,14 @@ namespace MWBase virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder + virtual void stopTrack(SoundPtr sound) = 0; + ///< Stop the given audio track from playing + + virtual double getTrackTimeDelay(SoundPtr sound) = 0; + ///< Retives the time delay, in seconds, of the audio track (must be a sound + /// returned by \ref playTrack). Only intended to be called by the track + /// decoder's read method. + virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; @@ -123,6 +131,9 @@ namespace MWBase float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. + virtual void stopSound(SoundPtr sound) = 0; + ///< Stop the given sound from playing + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 925c966da4..1f7b8a515b 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -61,7 +61,7 @@ namespace MWSound virtual double getAudioClock() { return (double)getSampleOffset()/(double)mAVStream->codec->sample_rate - - mAudioTrack->getStreamDelay(); + MWBase::Environment::get().getSoundManager()->getTrackTimeDelay(mAudioTrack); } virtual void adjustAudioSettings(AVSampleFormat& sampleFormat, uint64_t& channelLayout, int& sampleRate) @@ -86,6 +86,8 @@ namespace MWSound public: ~MovieAudioDecoder() { + if(mAudioTrack.get()) + MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack); mAudioTrack.reset(); mDecoderBridge.reset(); } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index d4c890ceec..3607f71a44 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -157,17 +157,14 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) // // A streaming OpenAL sound. // -class OpenAL_SoundStream : public Sound +class OpenAL_SoundStream { static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; -protected: - OpenAL_Output &mOutput; - +private: ALuint mSource; -private: ALuint mBuffers[sNumBuffers]; ALint mCurrentBufIdx; @@ -189,34 +186,18 @@ private: friend class OpenAL_Output; public: - OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); - virtual ~OpenAL_SoundStream(); + OpenAL_SoundStream(ALuint src, DecoderPtr decoder); + ~OpenAL_SoundStream(); - virtual void stop(); - virtual bool isPlaying(); - virtual double getTimeOffset(); - virtual double getStreamDelay() const; - virtual void applyUpdates(); + bool isPlaying(); + double getStreamDelay() const; + double getStreamOffset() const; - void play(); bool process(); ALint refillQueue(); }; const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; -class OpenAL_SoundStream3D : public OpenAL_SoundStream -{ - OpenAL_SoundStream3D(const OpenAL_SoundStream3D &rhs); - OpenAL_SoundStream3D& operator=(const OpenAL_SoundStream3D &rhs); - -public: - OpenAL_SoundStream3D(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_SoundStream(output, src, decoder, pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - - virtual void applyUpdates(); -}; - // // A background streaming thread (keeps active streams processed) @@ -329,13 +310,9 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0) - , mDecoder(decoder), mIsFinished(true) +OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) + : mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false) { - throwALerror(); - alGenBuffers(sNumBuffers, mBuffers); throwALerror(); try @@ -358,8 +335,6 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mFrameSize = framesToBytes(1, chans, type); mBufferSize = static_cast(sBufferLength*srate); mBufferSize *= mFrameSize; - - mOutput.mActiveStreams.push_back(this); } catch(std::exception&) { @@ -367,51 +342,20 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode alGetError(); throw; } + mIsFinished = false; } OpenAL_SoundStream::~OpenAL_SoundStream() { - mOutput.mStreamThread->remove(this); - - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - - mOutput.mFreeSources.push_back(mSource); alDeleteBuffers(sNumBuffers, mBuffers); alGetError(); mDecoder->close(); - - mOutput.mActiveStreams.erase(std::find(mOutput.mActiveStreams.begin(), - mOutput.mActiveStreams.end(), this)); -} - -void OpenAL_SoundStream::play() -{ - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - throwALerror(); - - mIsFinished = false; - mOutput.mStreamThread->add(this); -} - -void OpenAL_SoundStream::stop() -{ - mOutput.mStreamThread->remove(this); - mIsFinished = true; - - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - throwALerror(); - - mDecoder->rewind(); } bool OpenAL_SoundStream::isPlaying() { ALint state; - boost::lock_guard lock(mOutput.mStreamThread->mMutex); alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); @@ -420,33 +364,6 @@ bool OpenAL_SoundStream::isPlaying() return !mIsFinished; } -double OpenAL_SoundStream::getTimeOffset() -{ - ALint state = AL_STOPPED; - ALint offset; - double t; - - boost::lock_guard lock(mOutput.mStreamThread->mMutex); - alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - if(state == AL_PLAYING || state == AL_PAUSED) - { - ALint queued; - alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - ALint inqueue = mBufferSize/mFrameSize*queued - offset; - t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; - } - else - { - /* Underrun, or not started yet. The decoder offset is where we'll play - * next. */ - t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; - } - - throwALerror(); - return t; -} - double OpenAL_SoundStream::getStreamDelay() const { ALint state = AL_STOPPED; @@ -467,41 +384,30 @@ double OpenAL_SoundStream::getStreamDelay() const return d; } -void OpenAL_SoundStream::updateAll(bool local) +double OpenAL_SoundStream::getStreamOffset() const { - alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); - alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); - if(local) + ALint state = AL_STOPPED; + ALint offset; + double t; + + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + ALint inqueue = mBufferSize/mFrameSize*queued - offset; + t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate; } else { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - alSourcei(mSource, AL_LOOPING, AL_FALSE); - - applyUpdates(); -} - -void OpenAL_SoundStream::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; + /* Underrun, or not started yet. The decoder offset is where we'll play + * next. */ + t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); + return t; } bool OpenAL_SoundStream::process() @@ -562,172 +468,6 @@ ALint OpenAL_SoundStream::refillQueue() return queued; } -void OpenAL_SoundStream3D::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) - gain = 0.0f; - else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - - -// -// A regular 2D OpenAL sound -// -class OpenAL_Sound : public Sound -{ -protected: - OpenAL_Output &mOutput; - - ALuint mSource; - - friend class OpenAL_Output; - - void updateAll(bool local); - -private: - OpenAL_Sound(const OpenAL_Sound &rhs); - OpenAL_Sound& operator=(const OpenAL_Sound &rhs); - -public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); - virtual ~OpenAL_Sound(); - - virtual void stop(); - virtual bool isPlaying(); - virtual double getTimeOffset(); - virtual void applyUpdates(); -}; - -// -// A regular 3D OpenAL sound -// -class OpenAL_Sound3D : public OpenAL_Sound -{ - OpenAL_Sound3D(const OpenAL_Sound &rhs); - OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); - -public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : OpenAL_Sound(output, src, pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - - virtual void applyUpdates(); -}; - -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - , mOutput(output), mSource(src) -{ - mOutput.mActiveSounds.push_back(this); -} -OpenAL_Sound::~OpenAL_Sound() -{ - alSourceStop(mSource); - alSourcei(mSource, AL_BUFFER, 0); - - mOutput.mFreeSources.push_back(mSource); - - mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), - mOutput.mActiveSounds.end(), this)); -} - -void OpenAL_Sound::stop() -{ - alSourceStop(mSource); - throwALerror(); -} - -bool OpenAL_Sound::isPlaying() -{ - ALint state; - - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - throwALerror(); - - return state==AL_PLAYING || state==AL_PAUSED; -} - -double OpenAL_Sound::getTimeOffset() -{ - ALfloat t; - - alGetSourcef(mSource, AL_SEC_OFFSET, &t); - throwALerror(); - - return t; -} - -void OpenAL_Sound::updateAll(bool local) -{ - alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); - alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); - if(local) - { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); - } - else - { - alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - - applyUpdates(); -} - -void OpenAL_Sound::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - - if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - -void OpenAL_Sound3D::applyUpdates() -{ - ALfloat gain = mVolume*mBaseVolume; - ALfloat pitch = mPitch; - if((mPos - mOutput.mPos).length2() > mMaxDistance*mMaxDistance) - gain = 0.0f; - else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(mSource, AL_GAIN, gain); - alSourcef(mSource, AL_PITCH, pitch); - alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]); - alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - throwALerror(); -} - // // An OpenAL output device @@ -881,15 +621,16 @@ void OpenAL_Output::unloadSound(Sound_Handle data) SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) { - if(!(*iter)->mSource) + if(!(*iter)->mHandle) continue; + ALuint source = GET_PTRID((*iter)->mHandle); ALint srcbuf; - alGetSourcei((*iter)->mSource, AL_BUFFER, &srcbuf); + alGetSourcei(source, AL_BUFFER, &srcbuf); if((ALuint)srcbuf == buffer) { - alSourceStop((*iter)->mSource); - alSourcei((*iter)->mSource, AL_BUFFER, 0); + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); } } alDeleteBuffers(1, &buffer); @@ -907,123 +648,281 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } -MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags,float offset) +MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); try { - sound.reset(new OpenAL_Sound(*this, src, osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + + ALfloat gain = vol*basevol; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + + alSourcePlay(source); + throwALerror(); + + sound.reset(new Sound(osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); + sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mFreeSources.push_back(source); throw; } - sound->updateAll(true); - alSourcei(src, AL_BUFFER, GET_PTRID(data)); - alSourcef(src, AL_SEC_OFFSET, offset/pitch); - - alSourcePlay(src); - throwALerror(); - return sound; } MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float min, float max, int flags, float offset) + float mindist, float maxdist, int flags, float offset) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); try { - sound.reset(new OpenAL_Sound3D(*this, src, pos, vol, basevol, pitch, min, max, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + + ALfloat gain = vol*basevol; + if((pos - mPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + + alSourcePlay(source); + throwALerror(); + + sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); + sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mFreeSources.push_back(source); throw; } - sound->updateAll(false); - alSourcei(src, AL_BUFFER, GET_PTRID(data)); - alSourcef(src, AL_SEC_OFFSET, offset/pitch); + return sound; +} - alSourcePlay(src); +void OpenAL_Output::stopSound(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return; + + ALuint source = GET_PTRID(sound->mHandle); + sound->mHandle = 0; + + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); + + mFreeSources.push_back(source); + mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); +} + +bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return false; + ALuint source = GET_PTRID(sound->mHandle); + ALint state; + + alGetSourcei(source, AL_SOURCE_STATE, &state); throwALerror(); - return sound; + return state == AL_PLAYING || state == AL_PAUSED; } MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + OpenAL_SoundStream *stream = 0; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try - { - sound.reset(new OpenAL_SoundStream(*this, src, decoder, osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + try { + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, AL_FALSE); + + ALfloat gain = basevol; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); + + sound.reset(new Sound(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + stream = new OpenAL_SoundStream(source, decoder); + mStreamThread->add(stream); + sound->mHandle = stream; + mActiveStreams.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mStreamThread->remove(stream); + delete stream; + mFreeSources.push_back(source); throw; } - sound->updateAll(true); - - sound->play(); return sound; } - -MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float min, float max, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) { - boost::shared_ptr sound; - ALuint src; + boost::shared_ptr sound; + OpenAL_SoundStream *stream = 0; + ALuint source; if(mFreeSources.empty()) fail("No free sources"); - src = mFreeSources.front(); + source = mFreeSources.front(); mFreeSources.pop_front(); if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try - { - sound.reset(new OpenAL_SoundStream3D(*this, src, decoder, pos, volume, basevol, pitch, min, max, flags)); + try { + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, AL_FALSE); + + ALfloat gain = volume*basevol; + if((pos - mPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); + + sound.reset(new Sound(pos, volume, basevol, pitch, mindist, maxdist, flags)); + stream = new OpenAL_SoundStream(source, decoder); + mStreamThread->add(stream); + sound->mHandle = stream; + mActiveStreams.push_back(sound); } - catch(std::exception&) - { - mFreeSources.push_back(src); + catch(std::exception&) { + mStreamThread->remove(stream); + delete stream; + mFreeSources.push_back(source); throw; } - sound->updateAll(false); - - sound->play(); return sound; } +void OpenAL_Output::stopStream(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + ALuint source = stream->mSource; + + sound->mHandle = 0; + mStreamThread->remove(stream); + + alSourceStop(source); + alSourcei(source, AL_BUFFER, 0); + + mFreeSources.push_back(source); + mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound)); + + delete stream; +} + +double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return 0.0; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + return stream->getStreamDelay(); +} + +double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return 0.0; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + boost::lock_guard lock(mStreamThread->mMutex); + return stream->getStreamOffset(); +} + +bool OpenAL_Output::isStreamPlaying(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) + return false; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + boost::lock_guard lock(mStreamThread->mMutex); + return stream->isPlaying(); +} + void OpenAL_Output::startUpdate() { @@ -1060,14 +959,17 @@ void OpenAL_Output::pauseSounds(int types) SoundVec::const_iterator sound = mActiveSounds.begin(); for(;sound != mActiveSounds.end();++sound) { - if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) - sources.push_back((*sound)->mSource); + if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) + sources.push_back(GET_PTRID((*sound)->mHandle)); } StreamVec::const_iterator stream = mActiveStreams.begin(); for(;stream != mActiveStreams.end();++stream) { - if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) - sources.push_back((*stream)->mSource); + if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + { + OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); + sources.push_back(strm->mSource); + } } if(!sources.empty()) { @@ -1082,14 +984,17 @@ void OpenAL_Output::resumeSounds(int types) SoundVec::const_iterator sound = mActiveSounds.begin(); for(;sound != mActiveSounds.end();++sound) { - if(*sound && (*sound)->mSource && ((*sound)->getPlayType()&types)) - sources.push_back((*sound)->mSource); + if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) + sources.push_back(GET_PTRID((*sound)->mHandle)); } StreamVec::const_iterator stream = mActiveStreams.begin(); for(;stream != mActiveStreams.end();++stream) { - if(*stream && (*stream)->mSource && ((*stream)->getPlayType()&types)) - sources.push_back((*stream)->mSource); + if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + { + OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); + sources.push_back(strm->mSource); + } } if(!sources.empty()) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 751ec4fd29..b7c3603c6c 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -16,9 +16,6 @@ namespace MWSound class SoundManager; class Sound; - class OpenAL_Sound; - class OpenAL_SoundStream; - class OpenAL_Output : public Sound_Output { ALCdevice *mDevice; @@ -27,9 +24,9 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; Environment mLastEnvironment; @@ -45,9 +42,16 @@ namespace MWSound virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset); + virtual void stopSound(MWBase::SoundPtr sound); + virtual bool isSoundPlaying(MWBase::SoundPtr sound); + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags); + virtual void stopStream(MWBase::SoundPtr sound); + virtual double getStreamDelay(MWBase::SoundPtr sound); + virtual double getStreamOffset(MWBase::SoundPtr sound); + virtual bool isStreamPlaying(MWBase::SoundPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index f95ff169d0..f467ba1216 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -10,7 +10,6 @@ namespace MWSound Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); - protected: osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mBaseVolume; @@ -21,12 +20,13 @@ namespace MWSound float mFadeOutTime; + protected: + void *mHandle; + + friend class Sound_Output; + friend class OpenAL_Output; + public: - virtual void stop() = 0; - virtual bool isPlaying() = 0; - virtual double getTimeOffset() = 0; - virtual double getStreamDelay() const { return 0.0; } - virtual void applyUpdates() = 0; void setPosition(const osg::Vec3f &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } void setBaseVolume(float volume) { mBaseVolume = volume; } @@ -47,16 +47,11 @@ namespace MWSound bool getIs3D() const { return mFlags&Play_3D; } Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : mPos(pos) - , mVolume(vol) - , mBaseVolume(basevol) - , mPitch(pitch) - , mMinDistance(mindist) - , mMaxDistance(maxdist) - , mFlags(flags) - , mFadeOutTime(0.0f) + : mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) + , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) + , mFadeOutTime(0.0f), mHandle(0) { } - virtual ~Sound() { } + ~Sound() { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 0f69498aa8..bdf40bf447 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -35,9 +35,16 @@ namespace MWSound /// @param offset Number of seconds into the sound to start playback. virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; + virtual void stopSound(MWBase::SoundPtr sound) = 0; + virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void stopStream(MWBase::SoundPtr sound) = 0; + virtual double getStreamDelay(MWBase::SoundPtr sound) = 0; + virtual double getStreamOffset(MWBase::SoundPtr sound) = 0; + virtual bool isStreamPlaying(MWBase::SoundPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ceff1a6191..82dd49f320 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -293,7 +293,7 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) - mMusic->stop(); + mOutput->stopStream(mMusic); mMusic.reset(); } @@ -303,8 +303,7 @@ namespace MWSound return; std::cout <<"Playing "<streamSound(decoder, volumeFromType(Play_TypeMusic), 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); } - catch(std::exception &e) - { + catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; } } @@ -366,7 +364,7 @@ namespace MWSound bool SoundManager::isMusicPlaying() { - return mMusic && mMusic->isPlaying(); + return mMusic && mOutput->isStreamPlaying(mMusic); } void SoundManager::playPlaylist(const std::string &playlist) @@ -411,9 +409,8 @@ namespace MWSound { MWBase::SoundPtr sound = snditer->second.first; Sound_Loudness *loudness = snditer->second.second; - float sec = sound->getTimeOffset(); - if(sound->isPlaying()) - return loudness->getLoudnessAtTime(sec); + float sec = mOutput->getStreamOffset(sound); + return loudness->getLoudnessAtTime(sec); } return 0.0f; @@ -450,7 +447,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - if(snditer->second.first->isPlaying()) + if(mOutput->isStreamPlaying(snditer->second.first)) return false; return true; } @@ -462,7 +459,7 @@ namespace MWSound SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - snditer->second.first->stop(); + mOutput->stopStream(snditer->second.first); mActiveSaySounds.erase(snditer); } mPendingSaySounds.erase(ptr); @@ -485,6 +482,16 @@ namespace MWSound return track; } + void SoundManager::stopTrack(MWBase::SoundPtr sound) + { + mOutput->stopStream(sound); + } + + double SoundManager::getTrackTimeDelay(MWBase::SoundPtr sound) + { + return mOutput->getStreamDelay(sound); + } + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { @@ -586,6 +593,11 @@ namespace MWSound return sound; } + void SoundManager::stopSound(MWBase::SoundPtr sound) + { + mOutput->stopSound(sound); + } + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); @@ -596,7 +608,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } } @@ -608,7 +620,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } @@ -623,7 +635,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } ++snditer; } @@ -634,7 +646,7 @@ namespace MWSound sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { - sayiter->second.first->stop(); + mOutput->stopStream(sayiter->second.first); } ++sayiter; } @@ -650,7 +662,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); } } } @@ -680,7 +692,7 @@ namespace MWSound SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - if(sndidx->second == sfx && sndidx->first->isPlaying()) + if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first)) return true; } } @@ -788,7 +800,7 @@ namespace MWSound env = Env_Underwater; else if(mUnderwaterSound) { - mUnderwaterSound->stop(); + mOutput->stopSound(mUnderwaterSound); mUnderwaterSound.reset(); } @@ -803,7 +815,7 @@ namespace MWSound if(mListenerUnderwater) { // Play underwater sound (after updating listener) - if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) + if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); } @@ -814,15 +826,35 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - if(!updateSound(sndidx->first, snditer->first, duration)) + MWWorld::Ptr ptr = snditer->first; + MWBase::SoundPtr sound = sndidx->first; + if(!ptr.isEmpty() && sound->getIs3D()) { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if(sound->getDistanceCull()) + { + if((mListenerPos - objpos).length2() > 2000*2000) + mOutput->stopSound(sound); + } + } + + if(!mOutput->isSoundPlaying(sound)) + { + mOutput->stopSound(sound); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); } else + { + sound->updateFade(duration); + ++sndidx; + } } if(snditer->second.empty()) mActiveSounds.erase(snditer++); @@ -862,36 +894,34 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - if(!updateSound(sayiter->second.first, sayiter->first, duration)) - mActiveSaySounds.erase(sayiter++); - else - ++sayiter; - } - mOutput->finishUpdate(); - } - - bool SoundManager::updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr& ptr, float duration) - { - if(!ptr.isEmpty() && sound->getIs3D()) - { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); - - if(sound->getDistanceCull()) + MWWorld::Ptr ptr = sayiter->first; + MWBase::SoundPtr sound = sayiter->second.first; + if(!ptr.isEmpty() && sound->getIs3D()) { - if((mListenerPos - objpos).length2() > 2000*2000) - sound->stop(); + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); + sound->setPosition(objpos); + + if(sound->getDistanceCull()) + { + if((mListenerPos - objpos).length2() > 2000*2000) + mOutput->stopStream(sound); + } + } + + if(!mOutput->isStreamPlaying(sound)) + { + mOutput->stopStream(sound); + mActiveSaySounds.erase(sayiter++); + } + else + { + sound->updateFade(duration); + + ++sayiter; } } - - if(!sound->isPlaying()) - return false; - - sound->updateFade(duration); - - sound->applyUpdates(); - return true; + mOutput->finishUpdate(); } @@ -928,7 +958,6 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->applyUpdates(); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -936,12 +965,10 @@ namespace MWSound { MWBase::SoundPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); - sound->applyUpdates(); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); - mMusic->applyUpdates(); } mOutput->finishUpdate(); } @@ -1056,7 +1083,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - sndidx->first->stop(); + mOutput->stopSound(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1065,7 +1092,7 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) - sayiter->second.first->stop(); + mOutput->stopStream(sayiter->second.first); mActiveSaySounds.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9c090585b9..5f4cf6ebca 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -116,7 +116,6 @@ namespace MWSound MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); - bool updateSound(MWBase::SoundPtr sound, const MWWorld::Ptr &ptr, float duration); void updateSounds(float duration); void updateRegionSound(float duration); @@ -174,6 +173,14 @@ namespace MWSound virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder + virtual void stopTrack(MWBase::SoundPtr sound); + ///< Stop the given audio track from playing + + virtual double getTrackTimeDelay(MWBase::SoundPtr sound); + ///< Retives the time delay, in seconds, of the audio track (must be a sound + /// returned by \ref playTrack). Only intended to be called by the track + /// decoder's read method. + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. @@ -189,6 +196,9 @@ namespace MWSound ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. + virtual void stopSound(MWBase::SoundPtr sound); + ///< Stop the given sound from playing + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 4ec4d14325..08ae6f2b0c 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -190,7 +190,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); - it->mSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); @@ -264,7 +264,7 @@ namespace MWWorld for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { mParent->removeChild(it->mNode); - it->mSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index afa819121e..9a93f38279 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -738,7 +738,7 @@ void WeatherManager::update(float duration, bool paused) void WeatherManager::stopSounds() { if (mAmbientSound.get()) - mAmbientSound->stop(); + MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); mAmbientSound.reset(); mPlayingSoundID.clear(); } From 1ce3e7f5b999e95829205c4c2f93b7df00716194 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 07:32:42 -0800 Subject: [PATCH 1548/1812] Use a separate type for streams They're basically the same, but it's to help avoid accidents with passing non- streaming sounds to the stream functions, or vice-versa. --- apps/openmw/mwbase/soundmanager.hpp | 10 +++++---- apps/openmw/mwsound/movieaudiofactory.cpp | 5 +++-- apps/openmw/mwsound/openal_output.cpp | 20 ++++++++--------- apps/openmw/mwsound/openal_output.hpp | 16 +++++++------- apps/openmw/mwsound/sound.hpp | 15 ++++++++++--- apps/openmw/mwsound/sound_output.hpp | 14 ++++++------ apps/openmw/mwsound/soundmanagerimp.cpp | 26 +++++++++++------------ apps/openmw/mwsound/soundmanagerimp.hpp | 12 +++++------ 8 files changed, 65 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index e75949a5b1..46f245c463 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -15,6 +15,7 @@ namespace MWWorld namespace MWSound { class Sound; + class Stream; struct Sound_Decoder; typedef boost::shared_ptr DecoderPtr; } @@ -22,6 +23,7 @@ namespace MWSound namespace MWBase { typedef boost::shared_ptr SoundPtr; + typedef boost::shared_ptr SoundStreamPtr; /// \brief Interface for sound manager (implemented in MWSound) class SoundManager @@ -104,13 +106,13 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(SoundPtr sound) = 0; + virtual void stopTrack(SoundStreamPtr stream) = 0; ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(SoundPtr sound) = 0; + virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0; ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. @@ -166,7 +168,7 @@ namespace MWBase virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; - virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; + virtual void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; virtual void clear() = 0; }; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 1f7b8a515b..554b62d264 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -92,7 +92,7 @@ namespace MWSound mDecoderBridge.reset(); } - MWBase::SoundPtr mAudioTrack; + MWBase::SoundStreamPtr mAudioTrack; boost::shared_ptr mDecoderBridge; }; @@ -163,7 +163,8 @@ namespace MWSound boost::shared_ptr decoder(new MWSound::MovieAudioDecoder(videoState)); decoder->setupFormat(); - MWBase::SoundPtr sound = MWBase::Environment::get().getSoundManager()->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + MWBase::SoundStreamPtr sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); if (!sound.get()) { decoder.reset(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3607f71a44..5757e92cf3 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -776,9 +776,9 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) } -MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) +MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { - boost::shared_ptr sound; + MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -810,7 +810,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Sound(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); + sound.reset(new Stream(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -826,9 +826,9 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, f return sound; } -MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) +MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) { - boost::shared_ptr sound; + MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -862,7 +862,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Sound(pos, volume, basevol, pitch, mindist, maxdist, flags)); + sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -878,7 +878,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec return sound; } -void OpenAL_Output::stopStream(MWBase::SoundPtr sound) +void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return; @@ -897,7 +897,7 @@ void OpenAL_Output::stopStream(MWBase::SoundPtr sound) delete stream; } -double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) +double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; @@ -905,7 +905,7 @@ double OpenAL_Output::getStreamDelay(MWBase::SoundPtr sound) return stream->getStreamDelay(); } -double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) +double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return 0.0; @@ -914,7 +914,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundPtr sound) return stream->getStreamOffset(); } -bool OpenAL_Output::isStreamPlaying(MWBase::SoundPtr sound) +bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return false; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index b7c3603c6c..0c074b126a 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -26,7 +26,7 @@ namespace MWSound typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; Environment mLastEnvironment; @@ -45,13 +45,13 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); - virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags); - virtual void stopStream(MWBase::SoundPtr sound); - virtual double getStreamDelay(MWBase::SoundPtr sound); - virtual double getStreamOffset(MWBase::SoundPtr sound); - virtual bool isStreamPlaying(MWBase::SoundPtr sound); + virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); + virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags); + virtual void stopStream(MWBase::SoundStreamPtr sound); + virtual double getStreamDelay(MWBase::SoundStreamPtr sound); + virtual double getStreamOffset(MWBase::SoundStreamPtr sound); + virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index f467ba1216..b76e4d6eb9 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -5,8 +5,7 @@ namespace MWSound { - class Sound - { + class Sound { Sound& operator=(const Sound &rhs); Sound(const Sound &rhs); @@ -51,7 +50,17 @@ namespace MWSound , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) , mFadeOutTime(0.0f), mHandle(0) { } - ~Sound() { } + }; + + // Same as above, but it's a different type since the output handles them differently + class Stream : public Sound { + Stream& operator=(const Stream &rhs); + Stream(const Stream &rhs); + + public: + Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) + { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index bdf40bf447..061fcdf077 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -38,13 +38,13 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; - virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; - virtual MWBase::SoundPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags) = 0; - virtual void stopStream(MWBase::SoundPtr sound) = 0; - virtual double getStreamDelay(MWBase::SoundPtr sound) = 0; - virtual double getStreamOffset(MWBase::SoundPtr sound) = 0; - virtual bool isStreamPlaying(MWBase::SoundPtr sound) = 0; + virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; + virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, + float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; + virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; + virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; + virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 82dd49f320..c40d2cd3ea 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -241,7 +241,7 @@ namespace MWSound return decoder; } - MWBase::SoundPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + MWBase::SoundStreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) { MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -392,7 +392,7 @@ namespace MWSound mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else { - MWBase::SoundPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } } @@ -407,7 +407,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - MWBase::SoundPtr sound = snditer->second.first; + MWBase::SoundStreamPtr sound = snditer->second.first; Sound_Loudness *loudness = snditer->second.second; float sec = mOutput->getStreamOffset(sound); return loudness->getLoudnessAtTime(sec); @@ -432,7 +432,7 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - MWBase::SoundPtr sound = playVoice(decoder, osg::Vec3f(), true); + MWBase::SoundStreamPtr sound = playVoice(decoder, osg::Vec3f(), true); mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); } } @@ -466,9 +466,9 @@ namespace MWSound } - MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + MWBase::SoundStreamPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) { - MWBase::SoundPtr track; + MWBase::SoundStreamPtr track; if(!mOutput->isInitialized()) return track; try @@ -482,14 +482,14 @@ namespace MWSound return track; } - void SoundManager::stopTrack(MWBase::SoundPtr sound) + void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { - mOutput->stopStream(sound); + mOutput->stopStream(stream); } - double SoundManager::getTrackTimeDelay(MWBase::SoundPtr sound) + double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) { - return mOutput->getStreamDelay(sound); + return mOutput->getStreamDelay(stream); } @@ -876,7 +876,7 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundPtr sound = playVoice(decoder, + MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer()) ); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); @@ -895,7 +895,7 @@ namespace MWSound while(sayiter != mActiveSaySounds.end()) { MWWorld::Ptr ptr = sayiter->first; - MWBase::SoundPtr sound = sayiter->second.first; + MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -963,7 +963,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) { - MWBase::SoundPtr sound = sayiter->second.first; + MWBase::SoundStreamPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); } if(mMusic) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5f4cf6ebca..e0214e0913 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -79,7 +79,7 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - boost::shared_ptr mMusic; + MWBase::SoundStreamPtr mMusic; std::string mCurrentPlaylist; typedef std::pair SoundBufferRefPair; @@ -87,7 +87,7 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::pair SoundLoudnessPair; + typedef std::pair SoundLoudnessPair; typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; @@ -113,7 +113,7 @@ namespace MWSound // to start streaming DecoderPtr loadVoice(const std::string &voicefile, Sound_Loudness **lipdata); - MWBase::SoundPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); void updateSounds(float duration); @@ -170,13 +170,13 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); + virtual MWBase::SoundStreamPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(MWBase::SoundPtr sound); + virtual void stopTrack(MWBase::SoundStreamPtr stream); ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(MWBase::SoundPtr sound); + virtual double getTrackTimeDelay(MWBase::SoundStreamPtr stream); ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. From 4bd235284b20c7dd7728ee31cb258391ddcc14e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 08:00:02 -0800 Subject: [PATCH 1549/1812] Rename a couple members to avoid confusion --- apps/openmw/mwsound/openal_output.cpp | 25 +++++++++++++------------ apps/openmw/mwsound/openal_output.hpp | 22 +++++++++------------- apps/openmw/mwsound/sound_output.hpp | 5 +---- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 5757e92cf3..3d5a97095e 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -666,7 +666,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); ALfloat gain = vol*basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -715,9 +715,9 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); ALfloat gain = vol*basevol; - if((pos - mPos).length2() > maxdist*maxdist) + if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -797,7 +797,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base alSourcei(source, AL_LOOPING, AL_FALSE); ALfloat gain = basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -847,9 +847,9 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os alSourcei(source, AL_LOOPING, AL_FALSE); ALfloat gain = volume*basevol; - if((pos - mPos).length2() > maxdist*maxdist) + if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -937,19 +937,19 @@ void OpenAL_Output::finishUpdate() void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env) { - mPos = pos; - mLastEnvironment = env; - if(mContext) { ALfloat orient[6] = { atdir.x(), atdir.y(), atdir.z(), updir.x(), updir.y(), updir.z() }; - alListener3f(AL_POSITION, mPos.x(), mPos.y(), mPos.z()); + alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); throwALerror(); } + + mListenerPos = pos; + mListenerEnv = env; } @@ -1011,8 +1011,9 @@ void OpenAL_Output::loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudne OpenAL_Output::OpenAL_Output(SoundManager &mgr) - : Sound_Output(mgr), mDevice(0), mContext(0), mLastEnvironment(Env_Normal), - mStreamThread(new StreamThread) + : Sound_Output(mgr), mDevice(0), mContext(0) + , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) + , mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 0c074b126a..c49bd3dbbf 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -29,8 +29,16 @@ namespace MWSound typedef std::vector StreamVec; StreamVec mActiveStreams; - Environment mLastEnvironment; + osg::Vec3f mListenerPos; + Environment mListenerEnv; + struct StreamThread; + std::auto_ptr mStreamThread; + + OpenAL_Output& operator=(const OpenAL_Output &rhs); + OpenAL_Output(const OpenAL_Output &rhs); + + public: virtual std::vector enumerate(); virtual void init(const std::string &devname=""); virtual void deinit(); @@ -63,20 +71,8 @@ namespace MWSound virtual void loadLoudnessAsync(DecoderPtr decoder, Sound_Loudness *loudness); - OpenAL_Output& operator=(const OpenAL_Output &rhs); - OpenAL_Output(const OpenAL_Output &rhs); - OpenAL_Output(SoundManager &mgr); virtual ~OpenAL_Output(); - - struct StreamThread; - std::auto_ptr mStreamThread; - - friend class OpenAL_Sound; - friend class OpenAL_Sound3D; - friend class OpenAL_SoundStream; - friend class OpenAL_SoundStream3D; - friend class SoundManager; }; #ifndef DEFAULT_OUTPUT #define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x)) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 061fcdf077..fcb992f589 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -64,12 +64,9 @@ namespace MWSound protected: bool mInitialized; - osg::Vec3f mPos; Sound_Output(SoundManager &mgr) - : mManager(mgr) - , mInitialized(false) - , mPos(0.0f, 0.0f, 0.0f) + : mManager(mgr), mInitialized(false) { } public: virtual ~Sound_Output() { } From a6db96b2d8defa2bd8c683438663625cd28058c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 14:34:14 -0800 Subject: [PATCH 1550/1812] Update sound and stream parameters --- apps/openmw/mwsound/openal_output.cpp | 55 +++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.hpp | 2 + apps/openmw/mwsound/sound.hpp | 6 +++ apps/openmw/mwsound/sound_output.hpp | 2 + apps/openmw/mwsound/soundmanagerimp.cpp | 5 +++ 5 files changed, 70 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3d5a97095e..f93829ae51 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -775,6 +775,33 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) return state == AL_PLAYING || state == AL_PAUSED; } +void OpenAL_Output::updateSound(MWBase::SoundPtr sound) +{ + if(!sound->mHandle) return; + ALuint source = GET_PTRID(sound->mHandle); + + const osg::Vec3f &pos = sound->getPosition(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getIs3D()) + { + ALfloat maxdist = sound->getMaxDistance(); + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) { @@ -923,6 +950,34 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) return stream->isPlaying(); } +void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) +{ + if(!sound->mHandle) return; + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + ALuint source = stream->mSource; + + const osg::Vec3f &pos = sound->getPosition(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getIs3D()) + { + ALfloat maxdist = sound->getMaxDistance(); + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + void OpenAL_Output::startUpdate() { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index c49bd3dbbf..24b9c855f2 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -52,6 +52,7 @@ namespace MWSound float vol, float basevol, float pitch, float min, float max, int flags, float offset); virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); + virtual void updateSound(MWBase::SoundPtr sound); virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, @@ -60,6 +61,7 @@ namespace MWSound virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); + virtual void updateStream(MWBase::SoundStreamPtr sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index b76e4d6eb9..ec55db5803 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -40,8 +40,14 @@ namespace MWSound } } + const osg::Vec3f &getPosition() const { return mPos; } + float getRealVolume() const { return mVolume * mBaseVolume; } + float getPitch() const { return mPitch; } + float getMaxDistance() const { return mMaxDistance; } + MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } + bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index fcb992f589..9cc02160b1 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,6 +37,7 @@ namespace MWSound float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; + virtual void updateSound(MWBase::SoundPtr sound) = 0; virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, @@ -45,6 +46,7 @@ namespace MWSound virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; + virtual void updateStream(MWBase::SoundStreamPtr sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c40d2cd3ea..0263c5751a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -853,6 +853,7 @@ namespace MWSound { sound->updateFade(duration); + mOutput->updateSound(sound); ++sndidx; } } @@ -918,6 +919,7 @@ namespace MWSound { sound->updateFade(duration); + mOutput->updateStream(sound); ++sayiter; } } @@ -958,6 +960,7 @@ namespace MWSound { MWBase::SoundPtr sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateSound(sound); } } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); @@ -965,10 +968,12 @@ namespace MWSound { MWBase::SoundStreamPtr sound = sayiter->second.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateStream(sound); } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); + mOutput->updateStream(mMusic); } mOutput->finishUpdate(); } From 2883cdba5c6b3b55e35ec0b127ce5098108ce591 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Nov 2015 14:51:41 -0800 Subject: [PATCH 1551/1812] Initialize the Sound object before modifying the pitch variable --- apps/openmw/mwsound/openal_output.cpp | 12 ++++++++---- apps/openmw/mwsound/sound.hpp | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index f93829ae51..552e5bc281 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -659,6 +659,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba mFreeSources.pop_front(); try { + sound.reset(new Sound(vol, basevol, pitch, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); @@ -684,7 +686,6 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSourcePlay(source); throwALerror(); - sound.reset(new Sound(osg::Vec3f(0.f, 0.f, 0.f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } @@ -708,6 +709,8 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f mFreeSources.pop_front(); try { + sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); alSourcef(source, AL_MAX_DISTANCE, maxdist); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); @@ -735,7 +738,6 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSourcePlay(source); throwALerror(); - sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } @@ -817,6 +819,8 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { + sound.reset(new Stream(1.0f, basevol, pitch, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); @@ -837,7 +841,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Stream(osg::Vec3f(0.0f, 0.0f, 0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; @@ -867,6 +870,8 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { + sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); alSourcef(source, AL_MAX_DISTANCE, maxdist); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); @@ -889,7 +894,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); throwALerror(); - sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); sound->mHandle = stream; diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index ec55db5803..0ae465cfbe 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -56,6 +56,11 @@ namespace MWSound , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) , mFadeOutTime(0.0f), mHandle(0) { } + Sound(float vol, float basevol, float pitch, int flags) + : mPos(0.0f, 0.0f, 0.0f), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) + , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(flags) + , mFadeOutTime(0.0f), mHandle(0) + { } }; // Same as above, but it's a different type since the output handles them differently @@ -67,6 +72,9 @@ namespace MWSound Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) { } + Stream(float vol, float basevol, float pitch, int flags) + : Sound(vol, basevol, pitch, flags) + { } }; } From 3a39a92b93e2ab3989d6e835c581f05b5fc7c4f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Dec 2015 11:28:37 -0800 Subject: [PATCH 1552/1812] Keep track of audio tracks --- apps/openmw/mwsound/soundmanagerimp.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 11 +++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0263c5751a..157426564c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -474,6 +474,8 @@ namespace MWSound try { track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); + mActiveTracks.insert(iter, track); } catch(std::exception &e) { @@ -485,6 +487,9 @@ namespace MWSound void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { mOutput->stopStream(stream); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); + if(iter != mActiveTracks.end() && *iter == stream) + mActiveTracks.erase(iter); } double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) @@ -923,6 +928,24 @@ namespace MWSound ++sayiter; } } + + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + { + MWBase::SoundStreamPtr sound = *trkiter; + if(!mOutput->isStreamPlaying(sound)) + { + mOutput->stopStream(sound); + trkiter = mActiveTracks.erase(trkiter); + } + else + { + sound->updateFade(duration); + + mOutput->updateStream(sound); + ++trkiter; + } + } mOutput->finishUpdate(); } @@ -970,6 +993,13 @@ namespace MWSound sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + { + MWBase::SoundStreamPtr sound = *trkiter; + sound->setBaseVolume(volumeFromType(sound->getPlayType())); + mOutput->updateStream(sound); + } if(mMusic) { mMusic->setBaseVolume(volumeFromType(mMusic->getPlayType())); @@ -1099,6 +1129,10 @@ namespace MWSound for(;sayiter != mActiveSaySounds.end();++sayiter) mOutput->stopStream(sayiter->second.first); mActiveSaySounds.clear(); + TrackList::iterator trkiter = mActiveTracks.begin(); + for(;trkiter != mActiveTracks.end();++trkiter) + mOutput->stopStream(*trkiter); + mActiveTracks.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); stopMusic(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e0214e0913..8ec46bd73a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -79,9 +79,6 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - MWBase::SoundStreamPtr mMusic; - std::string mCurrentPlaylist; - typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; typedef std::map SoundMap; @@ -95,7 +92,11 @@ namespace MWSound typedef std::map SayDecoderMap; SayDecoderMap mPendingSaySounds; - MWBase::SoundPtr mUnderwaterSound; + typedef std::vector TrackList; + TrackList mActiveTracks; + + MWBase::SoundStreamPtr mMusic; + std::string mCurrentPlaylist; bool mListenerUnderwater; osg::Vec3f mListenerPos; @@ -104,6 +105,8 @@ namespace MWSound int mPausedSoundTypes; + MWBase::SoundPtr mUnderwaterSound; + Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); Sound_Buffer *lookupSound(const std::string &soundId) const; From 53718a5ca00f95150f1c0700efa949d19d83410a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 05:18:43 -0800 Subject: [PATCH 1553/1812] Use a typedef for the sound instance handle --- apps/openmw/mwsound/sound.hpp | 4 ++-- apps/openmw/mwsound/sound_output.hpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 0ae465cfbe..878384b43f 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -1,7 +1,7 @@ #ifndef GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H -#include "soundmanagerimp.hpp" +#include "sound_output.hpp" namespace MWSound { @@ -20,7 +20,7 @@ namespace MWSound float mFadeOutTime; protected: - void *mHandle; + Sound_Instance mHandle; friend class Sound_Output; friend class OpenAL_Output; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 9cc02160b1..d879dbf443 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -3,11 +3,10 @@ #include #include +#include #include "soundmanagerimp.hpp" -#include "../mwworld/ptr.hpp" - namespace MWSound { class SoundManager; @@ -17,6 +16,8 @@ namespace MWSound // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; + // An opaque handle for the implementation's sound instances. + typedef void *Sound_Instance; class Sound_Output { From 2ee3265b66466786d81d6c7c124dc1cc2421d359 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 06:35:35 -0800 Subject: [PATCH 1554/1812] Use a premade Sound object for the output's playSound functions --- apps/openmw/mwsound/openal_output.cpp | 62 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 +- apps/openmw/mwsound/sound.hpp | 3 +- apps/openmw/mwsound/sound_output.hpp | 7 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 31 +++++++------ 5 files changed, 49 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 552e5bc281..8932c1b555 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -648,9 +648,8 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } -MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) +void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) { - boost::shared_ptr sound; ALuint source; if(mFreeSources.empty()) @@ -659,16 +658,15 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba mFreeSources.pop_front(); try { - sound.reset(new Sound(vol, basevol, pitch, flags)); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - ALfloat gain = vol*basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -681,12 +679,12 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcef(source, AL_SEC_OFFSET, offset/pitch); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); + throwALerror(); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); throwALerror(); - sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } catch(std::exception&) { @@ -694,13 +692,11 @@ MWBase::SoundPtr OpenAL_Output::playSound(Sound_Handle data, float vol, float ba throw; } - return sound; + sound->mHandle = MAKE_PTRID(source); } -MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f &pos, float vol, float basevol, float pitch, - float mindist, float maxdist, int flags, float offset) +void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) { - boost::shared_ptr sound; ALuint source; if(mFreeSources.empty()) @@ -709,18 +705,19 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f mFreeSources.pop_front(); try { - sound.reset(new Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)); - - alSourcef(source, AL_REFERENCE_DISTANCE, mindist); - alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); + alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); - ALfloat gain = vol*basevol; + const osg::Vec3f &pos = sound->getPosition(); + ALfloat maxdist = sound->getMaxDistance(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -733,12 +730,12 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcef(source, AL_SEC_OFFSET, offset/pitch); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); + throwALerror(); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); throwALerror(); - sound->mHandle = MAKE_PTRID(source); mActiveSounds.push_back(sound); } catch(std::exception&) { @@ -746,14 +743,12 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(Sound_Handle data, const osg::Vec3f throw; } - return sound; + sound->mHandle = MAKE_PTRID(source); } void OpenAL_Output::stopSound(MWBase::SoundPtr sound) { - if(!sound->mHandle) - return; - + if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); sound->mHandle = 0; @@ -766,8 +761,7 @@ void OpenAL_Output::stopSound(MWBase::SoundPtr sound) bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) { - if(!sound->mHandle) - return false; + if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); ALint state; @@ -911,8 +905,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return; + if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); ALuint source = stream->mSource; @@ -930,16 +923,14 @@ void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return 0.0; + if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); return stream->getStreamDelay(); } double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return 0.0; + if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); boost::lock_guard lock(mStreamThread->mMutex); return stream->getStreamOffset(); @@ -947,8 +938,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) { - if(!sound->mHandle) - return false; + if(!sound->mHandle) return false; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); boost::lock_guard lock(mStreamThread->mMutex); return stream->isPlaying(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 24b9c855f2..934cb2d9d3 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -47,9 +47,8 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset); - virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset); + virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); + virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); virtual void stopSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 878384b43f..a59027fc12 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -22,7 +22,6 @@ namespace MWSound protected: Sound_Instance mHandle; - friend class Sound_Output; friend class OpenAL_Output; public: @@ -43,11 +42,13 @@ namespace MWSound const osg::Vec3f &getPosition() const { return mPos; } float getRealVolume() const { return mVolume * mBaseVolume; } float getPitch() const { return mPitch; } + float getMinDistance() const { return mMinDistance; } float getMaxDistance() const { return mMaxDistance; } MWBase::SoundManager::PlayType getPlayType() const { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } + bool getIsLooping() const { return mFlags&MWBase::SoundManager::Play_Loop; } bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index d879dbf443..01009c5a33 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -31,11 +31,8 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - /// @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound(Sound_Handle data, float vol, float basevol, float pitch, int flags, float offset) = 0; - /// @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(Sound_Handle data, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags, float offset) = 0; + virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; + virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; virtual void stopSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 157426564c..9ab86ef577 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -508,9 +508,8 @@ namespace MWSound Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound = mOutput->playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset - ); + sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + mOutput->playSound(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -522,6 +521,7 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<playSound(sfx->mHandle, - volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D, offset - ); + { + sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + mOutput->playSound(sound, sfx->mHandle, offset); + } else - sound = mOutput->playSound3D(sfx->mHandle, - objpos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + { + sound.reset(new Sound(objpos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + mOutput->playSound3D(sound, sfx->mHandle, offset); + } if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -563,6 +565,7 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<playSound3D(sfx->mHandle, - initialPos, volume * sfx->mVolume, basevol, pitch, sfx->mMinDist, sfx->mMaxDist, - mode|type|Play_3D, offset - ); + sound.reset(new Sound(initialPos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + mOutput->playSound3D(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); @@ -594,6 +596,7 @@ namespace MWSound catch(std::exception &) { //std::cout <<"Sound Error: "< Date: Wed, 2 Dec 2015 08:04:30 -0800 Subject: [PATCH 1555/1812] Use a premade SoundStream object for the output's streamSound functions --- apps/openmw/mwsound/openal_output.cpp | 36 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 ++-- apps/openmw/mwsound/sound_output.hpp | 5 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 29 +++++++++++++------- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 8932c1b555..839ae45adc 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -799,9 +799,8 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) } -MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) +void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) { - MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -810,19 +809,18 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base source = mFreeSources.front(); mFreeSources.pop_front(); - if((flags&MWBase::SoundManager::Play_Loop)) + if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new Stream(1.0f, basevol, pitch, flags)); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); alSourcef(source, AL_MAX_DISTANCE, 1000.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(source, AL_LOOPING, AL_FALSE); - ALfloat gain = basevol; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -837,7 +835,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); - sound->mHandle = stream; mActiveStreams.push_back(sound); } catch(std::exception&) { @@ -847,12 +844,11 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound(DecoderPtr decoder, float base throw; } - return sound; + sound->mHandle = stream; } -MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, float volume, float basevol, float pitch, float mindist, float maxdist, int flags) +void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) { - MWBase::SoundStreamPtr sound; OpenAL_SoundStream *stream = 0; ALuint source; @@ -861,21 +857,22 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os source = mFreeSources.front(); mFreeSources.pop_front(); - if((flags&MWBase::SoundManager::Play_Loop)) + if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new Stream(pos, volume, basevol, pitch, mindist, maxdist, flags)); - - alSourcef(source, AL_REFERENCE_DISTANCE, mindist); - alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); + alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(source, AL_LOOPING, AL_FALSE); - ALfloat gain = volume*basevol; + const osg::Vec3f &pos = sound->getPosition(); + ALfloat maxdist = sound->getMaxDistance(); + ALfloat gain = sound->getRealVolume(); + ALfloat pitch = sound->getPitch(); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mListenerEnv == Env_Underwater) + if(sound->getUseEnv() && mListenerEnv == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -890,7 +887,6 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os stream = new OpenAL_SoundStream(source, decoder); mStreamThread->add(stream); - sound->mHandle = stream; mActiveStreams.push_back(sound); } catch(std::exception&) { @@ -900,7 +896,7 @@ MWBase::SoundStreamPtr OpenAL_Output::streamSound3D(DecoderPtr decoder, const os throw; } - return sound; + sound->mHandle = stream; } void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 934cb2d9d3..1c2a991cf3 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -53,9 +53,8 @@ namespace MWSound virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); - virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags); - virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags); + virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); + virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void stopStream(MWBase::SoundStreamPtr sound); virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 01009c5a33..2f459d09b0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,9 +37,8 @@ namespace MWSound virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; - virtual MWBase::SoundStreamPtr streamSound(DecoderPtr decoder, float basevol, float pitch, int flags) = 0; - virtual MWBase::SoundStreamPtr streamSound3D(DecoderPtr decoder, const osg::Vec3f &pos, - float vol, float basevol, float pitch, float min, float max, int flags) = 0; + virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; + virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9ab86ef577..f814e4d197 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -251,15 +251,20 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + MWBase::SoundStreamPtr sound; float basevol = volumeFromType(Play_TypeVoice); if(playlocal) - return mOutput->streamSound(decoder, - basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D - ); - return mOutput->streamSound3D(decoder, - pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D - ); + { + sound.reset(new Stream(1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice|Play_2D)); + mOutput->streamSound(decoder, sound); + } + else + { + sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D)); + mOutput->streamSound3D(decoder, sound); + } + return sound; } @@ -309,11 +314,13 @@ namespace MWSound DecoderPtr decoder = getDecoder(); decoder->open(filename); - mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), - 1.0f, Play_NoEnv|Play_TypeMusic|Play_2D); + mMusic.reset(new Stream(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D)); + mOutput->streamSound(decoder, mMusic); } catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; + mMusic.reset(); } } @@ -473,7 +480,9 @@ namespace MWSound return track; try { - track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); + track.reset(new Stream(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D)); + mOutput->streamSound(decoder, track); + TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); mActiveTracks.insert(iter, track); } From 2face3d0a9ca6d9a81ec62936820aff6a5bc2408 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 09:55:51 -0800 Subject: [PATCH 1556/1812] Combine duplicate code --- apps/openmw/mwsound/openal_output.cpp | 206 ++++++++++---------------- apps/openmw/mwsound/openal_output.hpp | 5 + 2 files changed, 85 insertions(+), 126 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 839ae45adc..54a5efb68b 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -648,6 +648,71 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const } +void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv) +{ + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + +void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv) +{ + alSourcef(source, AL_REFERENCE_DISTANCE, mindist); + alSourcef(source, AL_MAX_DISTANCE, maxdist); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + +void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d) +{ + if(is3d) + { + if((pos - mListenerPos).length2() > maxdist*maxdist) + gain = 0.0f; + } + if(useenv && mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(source, AL_GAIN, gain); + alSourcef(source, AL_PITCH, pitch); + alSourcefv(source, AL_POSITION, pos.ptr()); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); +} + + void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) { ALuint source; @@ -658,27 +723,10 @@ void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float o mFreeSources.pop_front(); try { - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(source, AL_MAX_DISTANCE, 1000.0f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + sound->getIsLooping(), sound->getUseEnv()); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcef(source, AL_SEC_OFFSET, offset); throwALerror(); alSourcei(source, AL_BUFFER, GET_PTRID(data)); @@ -705,31 +753,11 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float mFreeSources.pop_front(); try { - alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); - alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, sound->getIsLooping() ? AL_TRUE : AL_FALSE); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), + sound->getUseEnv()); - const osg::Vec3f &pos = sound->getPosition(); - ALfloat maxdist = sound->getMaxDistance(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alSourcef(source, AL_SEC_OFFSET, offset/pitch); + alSourcef(source, AL_SEC_OFFSET, offset); throwALerror(); alSourcei(source, AL_BUFFER, GET_PTRID(data)); @@ -776,26 +804,8 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); - const osg::Vec3f &pos = sound->getPosition(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getIs3D()) - { - ALfloat maxdist = sound->getMaxDistance(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - } - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), + sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); } @@ -812,25 +822,8 @@ void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(source, AL_MAX_DISTANCE, 1000.0f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, AL_FALSE); - - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + false, sound->getUseEnv()); throwALerror(); stream = new OpenAL_SoundStream(source, decoder); @@ -860,29 +853,8 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - alSourcef(source, AL_REFERENCE_DISTANCE, sound->getMinDistance()); - alSourcef(source, AL_MAX_DISTANCE, sound->getMaxDistance()); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, AL_FALSE); - - const osg::Vec3f &pos = sound->getPosition(); - ALfloat maxdist = sound->getMaxDistance(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); throwALerror(); stream = new OpenAL_SoundStream(source, decoder); @@ -946,26 +918,8 @@ void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); ALuint source = stream->mSource; - const osg::Vec3f &pos = sound->getPosition(); - ALfloat gain = sound->getRealVolume(); - ALfloat pitch = sound->getPitch(); - if(sound->getIs3D()) - { - ALfloat maxdist = sound->getMaxDistance(); - if((pos - mListenerPos).length2() > maxdist*maxdist) - gain = 0.0f; - } - if(sound->getUseEnv() && mListenerEnv == Env_Underwater) - { - gain *= 0.9f; - pitch *= 0.7f; - } - - alSourcef(source, AL_GAIN, gain); - alSourcef(source, AL_PITCH, pitch); - alSourcefv(source, AL_POSITION, pos.ptr()); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), + sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 1c2a991cf3..d00e8cd67c 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -35,6 +35,11 @@ namespace MWSound struct StreamThread; std::auto_ptr mStreamThread; + void initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv); + void initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv); + + void updateCommon(ALuint source, const osg::Vec3f &pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d); + OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); From f19f1c47c8f0895e6d56234fd3551cb0f3cc321d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Dec 2015 16:07:19 -0800 Subject: [PATCH 1557/1812] Fix playing pending voices without a Ptr --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f814e4d197..044a8ba488 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -890,13 +890,17 @@ namespace MWSound DecoderPtr decoder = penditer->second.first; decoder->rewind(); + MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); + if(ptr == MWWorld::Ptr()) + sound = playVoice(decoder, osg::Vec3f(), true); + else + { + const ESM::Position &pos = ptr.getRefData().getPosition(); + const osg::Vec3f objpos(pos.asVec3()); - MWBase::SoundStreamPtr sound = playVoice(decoder, - objpos, (ptr == MWMechanics::getPlayer()) - ); + sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + } mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } catch(std::exception &e) { From 238a5824be1d1dd65d7118f4c09a5fe407766589 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 08:54:14 +0300 Subject: [PATCH 1558/1812] add custom new variable fot Qt --- CMakeLists.txt | 17 +++++-- apps/openmw/CMakeLists.txt | 22 +------- components/CMakeLists.txt | 68 ++++++++++--------------- components/sdlutil/sdlcursormanager.cpp | 3 -- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61a44b758d..b41f0773f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,14 +168,23 @@ endif (ANDROID) option(OPENGL_ES "enable opengl es support" FALSE ) +option(USE_QT "Use Qt in building" TRUE ) + +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS) + set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) +else() + set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) +endif() + +add_definitions (-DUSE_QT) + if (OPENGL_ES) - INCLUDE(cmake/FindOpenGLES.cmake) + find_package(OpenGLES) add_definitions (-DOPENGL_ES) - INCLUDE_DIRECTORIES(${OPENGLES_INCLUDE_DIR}) endif (OPENGLES) # Dependencies -if (NOT ANDROID) +if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") message(STATUS "Using Qt${DESIRED_QT_VERSION}") @@ -220,7 +229,7 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -if (NOT ANDROID) +if (USE_QT) find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) else() find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4512e004d2..03ce71f5c5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -155,35 +155,15 @@ if (ANDROID) android log dl - MyGUIEngineStatic - BulletCollision - LinearMath z - osg - osgDB - osgAnimation - osgText - osgUtil - osgShadow ${OPENSCENEGRAPH_LIBRARIES} ${OSG_PLUGINS} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} jpeg gif - png + png ) endif (ANDROID) - -if (OPENGL_ES) - target_link_libraries(openmw - ${OPENGLES_gl_LIBRARY} - ) -endif (OPENGL_ES) - if (USE_SYSTEM_TINYXML) target_link_libraries(openmw ${TINYXML_LIBRARIES}) endif() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 92e11c51c3..edc7b7c25a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -139,7 +139,7 @@ add_component_dir (version set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) -if (NOT ANDROID) +if (USE_QT) add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel @@ -176,55 +176,39 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -if (NOT ANDROID) - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${OPENGL_gl_LIBRARY} - ${MYGUI_LIBRARIES} - ) +if (OPENGL_ES) + set(GL_LIB ${OPENGLES_gl_LIBRARY}) else() - target_link_libraries(components - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${OSG_LIBRARIES} - ${OPENTHREADS_LIBRARIES} - ${OSGPARTICLE_LIBRARIES} - ${OSGUTIL_LIBRARIES} - ${OSGDB_LIBRARIES} - ${OSGVIEWER_LIBRARIES} - ${OSGGA_LIBRARIES} - ${OSGFX_LIBRARIES} - ${OSGANIMATION_LIBRARIES} - ${BULLET_LIBRARIES} - ${SDL2_LIBRARY} - # For MyGUI platform - ${MYGUI_LIBRARIES} - ) + set(GL_LIB ${OPENGL_gl_LIBRARY}) endif() +target_link_libraries(components + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${OSG_LIBRARIES} + ${OPENTHREADS_LIBRARIES} + ${OSGPARTICLE_LIBRARIES} + ${OSGUTIL_LIBRARIES} + ${OSGDB_LIBRARIES} + ${OSGVIEWER_LIBRARIES} + ${OSGGA_LIBRARIES} + ${OSGFX_LIBRARIES} + ${OSGANIMATION_LIBRARIES} + ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} + # For MyGUI platform + ${GL_LIB} + ${MYGUI_LIBRARIES} + ) + if (WIN32) target_link_libraries(components ${Boost_LOCALE_LIBRARY}) endif() -if (NOT ANDROID) +if (USE_QT) if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(components ${QT_QTCORE_LIBRARY} diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index c131621a8f..0eb161a64d 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -221,9 +221,6 @@ namespace SDLUtil return; #endif - if (mCursorMap.find(name) != mCursorMap.end()) - return; - if (mCursorMap.find(name) != mCursorMap.end()) return; From 06efd72a89117658351870c3d01b5b32b6f62f73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Dec 2015 11:14:58 +0100 Subject: [PATCH 1559/1812] allow keywords as strings in messagebox instruction (Fixes #2991) --- components/compiler/lineparser.cpp | 7 ++++++- components/compiler/scanner.cpp | 16 +++++++++++++--- components/compiler/scanner.hpp | 10 ++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index c1622c3e04..ce1e1e463c 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -411,7 +411,12 @@ namespace Compiler } case Scanner::K_set: mState = SetState; return true; - case Scanner::K_messagebox: mState = MessageState; return true; + + case Scanner::K_messagebox: + + mState = MessageState; + scanner.enableStrictKeywords(); + return true; case Scanner::K_return: diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 3c5bb77475..b370f74a17 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -26,6 +26,7 @@ namespace Compiler if (c=='\n') { + mStrictKeywords = false; mLoc.mColumn = 0; ++mLoc.mLine; mLoc.mLiteral.clear(); @@ -294,8 +295,11 @@ namespace Compiler name = name.substr (1, name.size()-2); // allow keywords enclosed in "" /// \todo optionally disable -// cont = parser.parseName (name, loc, *this); -// return true; + if (mStrictKeywords) + { + cont = parser.parseName (name, loc, *this); + return true; + } } int i = 0; @@ -567,7 +571,8 @@ namespace Compiler Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream, const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), - mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0) + mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), + mStrictKeywords (false) { } @@ -619,4 +624,9 @@ namespace Compiler if (mExtensions) mExtensions->listKeywords (keywords); } + + void Scanner::enableStrictKeywords() + { + mStrictKeywords = true; + } } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index fe867febae..270782c744 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -37,6 +37,7 @@ namespace Compiler float mPutbackFloat; std::string mPutbackName; TokenLoc mPutbackLoc; + bool mStrictKeywords; public: @@ -116,13 +117,18 @@ namespace Compiler ///< put back a float token void putbackName (const std::string& name, const TokenLoc& loc); - ///< put back a name toekn + ///< put back a name token void putbackKeyword (int keyword, const TokenLoc& loc); ///< put back a keyword token void listKeywords (std::vector& keywords); - ///< Append all known keywords to \a kaywords. + ///< Append all known keywords to \a keywords. + + /// Do not accept keywords in quotation marks anymore. + /// + /// \attention This mode lasts only until the next newline is reached. + void enableStrictKeywords(); }; } From 86881bcf398d004f1b7e9437acf07bdfd73b6c1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:16:20 +0100 Subject: [PATCH 1560/1812] In first person mode, attach sound listener to the camera --- apps/openmw/mwbase/soundmanager.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 6 ++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 7 ++----- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++------ 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a91149777d..b313839363 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -153,7 +153,7 @@ namespace MWBase virtual void update(float duration) = 0; - virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) = 0; + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0; virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f6403a9259..c0a907f70d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -387,6 +387,7 @@ namespace MWRender osg::Vec3f focal, cameraPos; mCamera->getPosition(focal, cameraPos); + mCurrentCameraPos = cameraPos; if (mWater->isUnderwater(cameraPos)) { setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); @@ -865,6 +866,11 @@ namespace MWRender return mCamera.get(); } + const osg::Vec3f &RenderingManager::getCameraPosition() const + { + return mCurrentCameraPos; + } + void RenderingManager::togglePOV() { mCamera->toggleViewMode(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 203df22699..a0ea14cb4a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -159,6 +159,7 @@ namespace MWRender void resetCamera(); float getCameraDistance() const; Camera* getCamera(); + const osg::Vec3f& getCameraPosition() const; void togglePOV(); void togglePreviewMode(bool enable); bool toggleVanityMode(bool enable); @@ -188,6 +189,7 @@ namespace MWRender std::auto_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::auto_ptr mCamera; + osg::Vec3f mCurrentCameraPos; osg::ref_ptr mStateUpdater; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ceff1a6191..3b24e26ab4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -946,16 +946,13 @@ namespace MWSound mOutput->finishUpdate(); } - void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up) + void SoundManager::setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) { mListenerPos = pos; mListenerDir = dir; mListenerUp = up; - MWWorld::Ptr player = MWMechanics::getPlayer(); - const MWWorld::CellStore *cell = player.getCell(); - - mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); + mListenerUnderwater = underwater; } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 9c090585b9..1f1a5cd6b1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -218,7 +218,7 @@ namespace MWSound virtual void update(float duration); - virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up); + virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater); virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6bced30c45..22485ed92e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1601,18 +1601,23 @@ namespace MWWorld void World::updateSoundListener() { const ESM::Position& refpos = getPlayerPtr().getRefData().getPosition(); - osg::Vec3f playerPos = refpos.asVec3(); + osg::Vec3f listenerPos; - playerPos.z() += 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z(); + if (isFirstPerson()) + listenerPos = mRendering->getCameraPosition(); + else + listenerPos = refpos.asVec3() + osg::Vec3f(0, 0, 1.85f * mPhysics->getHalfExtents(getPlayerPtr()).z()); - osg::Quat playerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * + osg::Quat listenerOrient = osg::Quat(refpos.rot[1], osg::Vec3f(0,-1,0)) * osg::Quat(refpos.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f forward = playerOrient * osg::Vec3f(0,1,0); - osg::Vec3f up = playerOrient * osg::Vec3f(0,0,1); + osg::Vec3f forward = listenerOrient * osg::Vec3f(0,1,0); + osg::Vec3f up = listenerOrient * osg::Vec3f(0,0,1); - MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, forward, up); + bool underwater = isUnderwater(getPlayerPtr().getCell(), listenerPos); + + MWBase::Environment::get().getSoundManager()->setListenerPosDir(listenerPos, forward, up, underwater); } void World::updateWindowManager () From d0c6b407b47daaee8ded5fc7bf56a7b41c526d63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:16:50 +0100 Subject: [PATCH 1561/1812] Fix isUnderwater checks being off by one for exterior cells --- apps/openmw/mwworld/cellstore.cpp | 2 ++ apps/openmw/mwworld/scene.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e9f9c5cd1b..5832a6727f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -296,6 +296,8 @@ namespace MWWorld float CellStore::getWaterLevel() const { + if (isExterior()) + return -1; return mWaterLevel; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c6b50aae3e..45c94b6d9a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -265,7 +265,7 @@ namespace MWWorld mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); - float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); + float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { From 389b168d5fac7719d5f8781792743232ad247714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 15:48:27 +0100 Subject: [PATCH 1562/1812] Restore OpGetWaterLevel to vanilla behaviour --- apps/openmw/mwscript/cellextensions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 5dd3cf4119..b6f7229e03 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -144,7 +144,9 @@ namespace MWScript return; } MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); - if (cell->getCell()->hasWater()) + if (cell->isExterior()) + runtime.push(0.f); // vanilla oddity, return 0 even though water is actually at -1 + else if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); else runtime.push (-std::numeric_limits::max()); From d9b1b7c516c1cd49c276985b3404cb9778f42ae5 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 19:56:38 +0300 Subject: [PATCH 1563/1812] addd forgotten line --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b41f0773f7..58aac20ae5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,7 @@ option(OPENGL_ES "enable opengl es support" FALSE ) option(USE_QT "Use Qt in building" TRUE ) -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS) +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) else() set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) From 7d374b36fdbe9411f7dfb6373db30bbf4a5a46b4 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 21:29:50 +0300 Subject: [PATCH 1564/1812] change cmake variables --- CMakeLists.txt | 29 +++++++++++------------------ components/CMakeLists.txt | 4 +++- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58aac20ae5..02a05cb3a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,10 +45,6 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) # Macros include(OpenMWMacros) -if (ANDROID) - set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") -endif (ANDROID) - # doxygen main page configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp") @@ -161,28 +157,24 @@ endif() if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - set(OSG_PLUGINS_DIR ${OSG_PLUGINS_DIR}) - add_definitions (-DOSG_PLUGINS_DIR) + add_definitions (-DOSG_PLUGINS_DIR=${OSG_PLUGINS_DIR}) set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) option(OPENGL_ES "enable opengl es support" FALSE ) -option(USE_QT "Use Qt in building" TRUE ) +if (OPENGL_ES) + add_definitions(-DOPENGL_ES) +endif(OPENGL_ES) if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE CACHE BOOL "disable Qt" FORCE ) + set(USE_QT FALSE) else() - set(USE_QT TRUE CACHE BOOL "enable Qt" FORCE ) + set(USE_QT TRUE) endif() -add_definitions (-DUSE_QT) +add_definitions(-DUSE_QT) -if (OPENGL_ES) - find_package(OpenGLES) - add_definitions (-DOPENGL_ES) -endif (OPENGLES) - # Dependencies if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") @@ -230,10 +222,11 @@ IF(BOOST_STATIC) endif() if (USE_QT) - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) -else() - find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) + set (OSG_QT osgQt) endif() + +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX) + include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) if(OSG_STATIC) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index edc7b7c25a..a1ac53d1b1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,7 +20,9 @@ else (GIT_CHECKOUT) configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) -if (NOT OPENGL_ES) +if (OPENGL_ES) + find_package(OpenGLES REQUIRED) +else() find_package(OpenGL REQUIRED) endif() From eb458bf9c884813c4e0da7c302390bea5e67b6c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 19:49:45 +0100 Subject: [PATCH 1565/1812] Fix inactive RigGeometry not rendering correctly --- components/sceneutil/riggeometry.cpp | 4 +++- components/sceneutil/skeleton.cpp | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 0006c947e2..88b907fafa 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -82,7 +82,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mLastFrameNumber(0) - , mBoundsFirstFrame(copy.mBoundsFirstFrame) + , mBoundsFirstFrame(true) { setSourceGeometry(copy.mSourceGeometry); } @@ -211,6 +211,8 @@ void RigGeometry::update(osg::NodeVisitor* nv) { if (!mSkeleton) { + std::cerr << "RigGeometry rendering with no skeleton, should have been initialized by UpdateVisitor" << std::endl; + // try to recover anyway, though rendering is likely to be incorrect. if (!initFromParentSkeleton(nv)) return; } diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index d66131b4e9..83f7d65378 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -135,7 +135,10 @@ bool Skeleton::getActive() const void Skeleton::traverse(osg::NodeVisitor& nv) { - if (!mActive && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) + if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR + // need to process at least 2 frames before shutting off update, since we need to have both frame-alternating RigGeometries initialized + // this would be more naturally handled if the double-buffering was implemented in RigGeometry itself rather than in a FrameSwitch decorator node + && mLastFrameNumber != 0 && mLastFrameNumber+2 <= nv.getTraversalNumber()) return; osg::Group::traverse(nv); } From 795f6d77f2a2ebf510955468a8fca7ee7903c425 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 20:06:00 +0100 Subject: [PATCH 1566/1812] Cache the Animation's Skeleton --- apps/openmw/mwrender/animation.cpp | 12 +++++++----- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d530c2c929..bc417dae23 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -311,6 +311,7 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mInsert(parentNode) + , mSkeleton(NULL) , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) @@ -338,10 +339,8 @@ namespace MWRender void Animation::setActive(bool active) { - if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) - { - skel->setActive(active); - } + if (mSkeleton) + mSkeleton->setActive(active); } void Animation::updatePtr(const MWWorld::Ptr &ptr) @@ -965,6 +964,7 @@ namespace MWRender mObjectRoot->getParent(0)->removeChild(mObjectRoot); } mObjectRoot = NULL; + mSkeleton = NULL; mNodeMap.clear(); mActiveControllers.clear(); @@ -976,9 +976,11 @@ namespace MWRender else { osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); - if (!dynamic_cast(newObjectRoot.get())) + mSkeleton = dynamic_cast(newObjectRoot.get()); + if (!mSkeleton) { osg::ref_ptr skel = new SceneUtil::Skeleton; + mSkeleton = skel.get(); skel->addChild(newObjectRoot); newObjectRoot = skel; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b1c34576bd..04df10a380 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -24,6 +24,7 @@ namespace NifOsg namespace SceneUtil { class LightSource; + class Skeleton; } namespace MWRender @@ -208,6 +209,7 @@ protected: osg::ref_ptr mInsert; osg::ref_ptr mObjectRoot; + SceneUtil::Skeleton* mSkeleton; // The node expected to accumulate movement during movement animations. osg::ref_ptr mAccumRoot; From 1ec338f19d86bcf316d9199e7483057426358008 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 20:11:28 +0100 Subject: [PATCH 1567/1812] Don't attempt to load external keyframes for non-NIF files --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index bc417dae23..7a2cce7c92 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -394,6 +394,8 @@ namespace MWRender if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); + else + return; if(!mResourceSystem->getVFS()->exists(kfname)) return; From 7db307e028e95418f7642ab02813c9d105250002 Mon Sep 17 00:00:00 2001 From: sandstranger Date: Thu, 3 Dec 2015 22:37:42 +0300 Subject: [PATCH 1568/1812] delete unused variables --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02a05cb3a2..db8bcc4f75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,6 @@ endif() if (ANDROID) set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}") - add_definitions (-DOSG_PLUGINS_DIR=${OSG_PLUGINS_DIR}) set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE) endif (ANDROID) @@ -172,8 +171,6 @@ if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) else() set(USE_QT TRUE) endif() - -add_definitions(-DUSE_QT) # Dependencies if (USE_QT) From 5f349b9a6ebe355e14d389d6f2e5a94a13731fc5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 21:12:58 +0100 Subject: [PATCH 1569/1812] Support effects with attribute/skill argument in OpGetEffect --- apps/openmw/mwscript/miscextensions.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 63f3ea1901..68a30de4a6 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -422,9 +422,17 @@ namespace MWScript if(key < 0 || key > 32767 || *end != '\0') key = ESM::MagicEffect::effectStringToId(effect); - runtime.push(ptr.getClass().getCreatureStats(ptr).getMagicEffects().get( - MWMechanics::EffectKey(key)).getMagnitude() > 0); - } + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + for (MWMechanics::MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + if (it->first.mId == key) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } }; template From 1f8ee9b8d1e86faed9172e61143e339b732790aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Dec 2015 23:44:15 +0100 Subject: [PATCH 1570/1812] StateSetUpdater: use the frameNumber More robust in case a node is updated twice in the same frame (e.g. because it has multiple parents). --- components/sceneutil/statesetupdater.cpp | 7 +++---- components/sceneutil/statesetupdater.hpp | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 36aa683dbe..0e325082e1 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -20,11 +20,10 @@ namespace SceneUtil } } - // Swap to make the StateSet in [0] writable, [1] is now the StateSet that was queued by the last frame - std::swap(mStateSets[0], mStateSets[1]); - node->setStateSet(mStateSets[0]); + osg::StateSet* stateset = mStateSets[nv->getTraversalNumber()%2]; + node->setStateSet(stateset); - apply(mStateSets[0], nv); + apply(stateset, nv); traverse(node, nv); } diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 34b8da848a..51398844cf 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -12,8 +12,7 @@ namespace SceneUtil /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw /// traversals run in parallel can yield up to 200% framerates. /// @par Race conditions are prevented using a "double buffering" scheme - we have two StateSets that take turns, - /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. - /// After a frame is completed the places are swapped. + /// one StateSet we can write to, the second one is currently in use by the draw traversal of the last frame. /// @par Must be set as UpdateCallback on a Node. /// @note Do not add the same StateSetUpdater to multiple nodes. /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. From 8e9571d155893a20b09adea1dae1e0d684fe65b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:06:22 +0100 Subject: [PATCH 1571/1812] Double buffer the light StateAttributes and StateSets Fixes a race condition where the position of a light could jump a frame ahead. --- apps/openmw/mwrender/animation.cpp | 32 ++++++++++++++++-------- components/sceneutil/lightcontroller.cpp | 2 +- components/sceneutil/lightmanager.cpp | 29 ++++++++++++--------- components/sceneutil/lightmanager.hpp | 23 +++++++++++------ 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7a2cce7c92..ecfb2df147 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1091,8 +1091,7 @@ namespace MWRender } osg::ref_ptr lightSource = new SceneUtil::LightSource; - osg::Light* light = new osg::Light; - lightSource->setLight(light); + osg::ref_ptr light (new osg::Light); lightSource->setNodeMask(Mask_Lighting); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); @@ -1123,6 +1122,8 @@ namespace MWRender light->setAmbient(osg::Vec4f(0,0,0,1)); light->setSpecular(osg::Vec4f(0,0,0,0)); + lightSource->setLight(light); + osg::ref_ptr ctrl (new SceneUtil::LightController); ctrl->setDiffuse(light->getDiffuse()); if (esmLight->mData.mFlags & ESM::Light::Flicker) @@ -1318,22 +1319,31 @@ namespace MWRender } else { - if (!mGlowLight) + effect += 3; + float radius = effect * 66.f; + float linearAttenuation = 0.5f / effect; + + if (!mGlowLight || linearAttenuation != mGlowLight->getLight(0)->getLinearAttenuation()) { - mGlowLight = new SceneUtil::LightSource; - mGlowLight->setLight(new osg::Light); - mGlowLight->setNodeMask(Mask_Lighting); - osg::Light* light = mGlowLight->getLight(); + if (mGlowLight) + { + mInsert->removeChild(mGlowLight); + mGlowLight = NULL; + } + + osg::ref_ptr light (new osg::Light); light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0)); light->setAmbient(osg::Vec4f(1.5f,1.5f,1.5f,1.f)); + light->setLinearAttenuation(linearAttenuation); + + mGlowLight = new SceneUtil::LightSource; + mGlowLight->setNodeMask(Mask_Lighting); mInsert->addChild(mGlowLight); + mGlowLight->setLight(light); } - effect += 3; - osg::Light* light = mGlowLight->getLight(); - mGlowLight->setRadius(effect * 66.f); - light->setLinearAttenuation(0.5f/effect); + mGlowLight->setRadius(radius); } } diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index ccfd836f72..d44a1a94ae 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -118,7 +118,7 @@ namespace SceneUtil else if(mType == LT_PulseSlow) brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; - static_cast(node)->getLight()->setDiffuse(mDiffuseColor * brightness); + static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness); } void LightController::setDiffuse(osg::Vec4f color) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ba2f8c5105..6a992c5036 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -98,7 +98,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath()), nv->getTraversalNumber()); traverse(node, nv); } @@ -160,37 +160,42 @@ namespace SceneUtil mLightsInViewSpace.clear(); // do an occasional cleanup for orphaned lights - if (mStateSetCache.size() > 5000) - mStateSetCache.clear(); + for (int i=0; i<2; ++i) + { + if (mStateSetCache[i].size() > 5000) + mStateSetCache[i].clear(); + } } - void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat) + void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum) { LightSourceTransform l; l.mLightSource = lightSource; l.mWorldMatrix = worldMat; - lightSource->getLight()->setPosition(osg::Vec4f(worldMat.getTrans().x(), + lightSource->getLight(frameNum)->setPosition(osg::Vec4f(worldMat.getTrans().x(), worldMat.getTrans().y(), worldMat.getTrans().z(), 1.f)); mLights.push_back(l); } - osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList) + osg::ref_ptr LightManager::getLightListStateSet(const LightList &lightList, unsigned int frameNum) { // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists) size_t hash = 0; for (unsigned int i=0; imLightSource->getId()); - LightStateSetMap::iterator found = mStateSetCache.find(hash); - if (found != mStateSetCache.end()) + LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2]; + + LightStateSetMap::iterator found = stateSetCache.find(hash); + if (found != stateSetCache.end()) return found->second; else { std::vector > lights; for (unsigned int i=0; imLightSource->getLight()); + lights.push_back(lightList[i]->mLightSource->getLight(frameNum)); osg::ref_ptr attr = new LightStateAttribute(mStartLight, lights); @@ -200,7 +205,7 @@ namespace SceneUtil stateset->setAttribute(attr, osg::StateAttribute::ON); stateset->setAssociatedModes(attr, osg::StateAttribute::ON); - mStateSetCache.insert(std::make_pair(hash, stateset)); + stateSetCache.insert(std::make_pair(hash, stateset)); return stateset; } } @@ -348,10 +353,10 @@ namespace SceneUtil while (lightList.size() > maxLights) lightList.pop_back(); } - stateset = mLightManager->getLightListStateSet(lightList); + stateset = mLightManager->getLightListStateSet(lightList, nv->getTraversalNumber()); } else - stateset = mLightManager->getLightListStateSet(mLightList); + stateset = mLightManager->getLightListStateSet(mLightList, nv->getTraversalNumber()); cv->pushStateSet(stateset); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 89ffc13058..78703dfca3 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -12,7 +12,7 @@ namespace SceneUtil /// LightSource managed by a LightManager. class LightSource : public osg::Node { - osg::ref_ptr mLight; + osg::ref_ptr mLight[2]; // The activation radius float mRadius; @@ -37,17 +37,24 @@ namespace SceneUtil mRadius = radius; } - osg::Light* getLight() + /// Get the osg::Light safe for modification in the given frame. + osg::Light* getLight(unsigned int frame) { - return mLight; + return mLight[frame % 2]; } + /// @warning It is recommended not to replace an existing osg::Light, because there might still be + /// references to it in the light StateSet cache that are associated with this LightSource's ID. + /// These references will stay valid due to ref_ptr but will point to the old object. + /// @warning Do not modify the \a light after you've called this function. void setLight(osg::Light* light) { - mLight = light; + mLight[0] = light; + mLight[1] = osg::clone(light); } - int getId() + /// Get the unique ID for this light source. + int getId() const { return mId; } @@ -77,7 +84,7 @@ namespace SceneUtil void update(); // Called automatically by the LightSource's UpdateCallback - void addLight(LightSource* lightSource, const osg::Matrixf& worldMat); + void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum); struct LightSourceTransform { @@ -97,7 +104,7 @@ namespace SceneUtil typedef std::vector LightList; - osg::ref_ptr getLightListStateSet(const LightList& lightList); + osg::ref_ptr getLightListStateSet(const LightList& lightList, unsigned int frameNum); /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. void setStartLight(int start); @@ -113,7 +120,7 @@ namespace SceneUtil // < Light list hash , StateSet > typedef std::map > LightStateSetMap; - LightStateSetMap mStateSetCache; + LightStateSetMap mStateSetCache[2]; int mStartLight; From 462ef617ce2b6ced2924773abdc225881f84a23d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:18:54 +0100 Subject: [PATCH 1572/1812] Don't read forward/backward values for Quaternion key lists https://forum.openmw.org/viewtopic.php?f=8&t=3201&p=35867#p35867 --- components/nif/nifkey.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 682baed059..75353044d7 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -138,6 +138,11 @@ private: /*key.mBackwardValue = */(nif.*getValue)(); } + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readValue(nif, key); + } + static void readTBC(NIFStream &nif, KeyT &key) { readValue(nif, key); From c442af09c5b040222e365748c5640e5b0e6357b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 00:55:32 +0100 Subject: [PATCH 1573/1812] Write more documentation for the lighting system --- components/sceneutil/lightmanager.hpp | 37 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 78703dfca3..522455390a 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -10,11 +10,19 @@ namespace SceneUtil { /// LightSource managed by a LightManager. + /// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole scene + /// so do not need to be managed by a LightManager - so for directional lights use a plain osg::LightSource instead. + /// @note LightSources must be decorated by a LightManager node in order to have an effect. Typical use would + /// be one LightManager as the root of the scene graph. + /// @note One needs to attach LightListCallback's to the scene to have objects receive lighting from LightSources. + /// See the documentation of LightListCallback for more information. + /// @note The position of the contained osg::Light is automatically updated based on the LightSource's world position. class LightSource : public osg::Node { + // double buffered osg::Light's, since one of them may be in use by the draw thread at any given time osg::ref_ptr mLight[2]; - // The activation radius + // LightSource will affect objects within this radius float mRadius; int mId; @@ -32,12 +40,15 @@ namespace SceneUtil return mRadius; } + /// The LightSource will affect objects within this radius. void setRadius(float radius) { mRadius = radius; } /// Get the osg::Light safe for modification in the given frame. + /// @par May be used externally to animate the light's color/attenuation properties, + /// and is used internally to synchronize the light's position with the position of the LightSource. osg::Light* getLight(unsigned int frame) { return mLight[frame % 2]; @@ -60,8 +71,7 @@ namespace SceneUtil } }; - /// All light sources must be a child of the LightManager node. The LightManager can be anywhere in the scene graph, - /// but would be typically somewhere near the top. + /// @brief Decorator node implementing the rendering of any number of LightSources that can be anywhere in the subgraph. class LightManager : public osg::Group { public: @@ -80,10 +90,15 @@ namespace SceneUtil unsigned int getLightingMask() const; - // Called automatically by the UpdateCallback + /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. + void setStartLight(int start); + + int getStartLight() const; + + /// Internal use only, called automatically by the LightManager's UpdateCallback void update(); - // Called automatically by the LightSource's UpdateCallback + /// Internal use only, called automatically by the LightSource's UpdateCallback void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum); struct LightSourceTransform @@ -106,11 +121,6 @@ namespace SceneUtil osg::ref_ptr getLightListStateSet(const LightList& lightList, unsigned int frameNum); - /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene. - void setStartLight(int start); - - int getStartLight() const; - private: // Lights collected from the scene graph. Only valid during the cull traversal. std::vector mLights; @@ -127,6 +137,13 @@ namespace SceneUtil unsigned int mLightingMask; }; + /// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via + /// node->addCullCallback(new LightListCallback). Once a light list callback is added to a node, that node and all + /// its child nodes can receive lighting. + /// @par The placement of these LightListCallbacks affects the granularity of light lists. Having too fine grained + /// light lists can result in degraded performance. Too coarse grained light lists can result in lights no longer + /// rendering when the size of a light list exceeds the OpenGL limit on the number of concurrent lights (8). A good + /// starting point is to attach a LightListCallback to each game object's base node. /// @note Not thread safe for CullThreadPerCamera threading mode. class LightListCallback : public osg::NodeCallback { From 4a9b37aa53a896726618f689edca8055ac5c208a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 18:08:14 +0100 Subject: [PATCH 1574/1812] Fix copy constructor issue --- components/sceneutil/lightmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 6a992c5036..1706bb2b1e 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -260,10 +260,12 @@ namespace SceneUtil LightSource::LightSource(const LightSource ©, const osg::CopyOp ©op) : osg::Node(copy, copyop) - , mLight(copy.mLight) , mRadius(copy.mRadius) { mId = sLightId++; + + for (int i=0; i<2; ++i) + mLight[i] = osg::clone(copy.mLight[i].get(), copyop); } From 0975f60d594e8bfa906875bd2952d1493d784cd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 16:59:25 +0100 Subject: [PATCH 1575/1812] Stub out CellStore::get accessors in preparation of reference movement between cells --- apps/openmw/mwclass/activator.cpp | 3 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/container.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 3 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 2 + apps/openmw/mwclass/npc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/static.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwmechanics/obstacle.cpp | 2 + apps/openmw/mwworld/cellstore.hpp | 159 +-------------------------- apps/openmw/mwworld/localscripts.cpp | 2 + apps/openmw/mwworld/worldimp.cpp | 20 +++- 22 files changed, 60 insertions(+), 176 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 3a0f1b951b..fdbff026fc 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -130,6 +130,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index f93556ef90..06eea2c24c 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -147,8 +147,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 324dd32eef..9ad28a537a 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -381,8 +381,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 2c20435b2f..cfa2508c48 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -186,8 +186,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index cea30d561f..8bd3fd2e66 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -275,8 +275,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 6c44c97e25..b82dff7063 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -292,8 +292,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2cd11d1136..7f43f86770 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -599,8 +599,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Creature::isBipedal(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6fee79ddf0..cb9f59e96d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -309,8 +309,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } void Door::ensureCustomData(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c9e6e70f21..0b6724c6cc 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -184,8 +184,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 34d93da678..0442fd2e06 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -216,8 +216,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 5cffdf13a7..bd17a527b7 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -165,8 +165,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 98b4faab9b..16d926f5ef 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -194,6 +194,7 @@ namespace MWClass { MWWorld::Ptr newPtr; + /* const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -223,6 +224,7 @@ namespace MWClass ptr.get(); newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); } + */ return newPtr; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6633b3490b..b5f2b52f3b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1129,8 +1129,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index cf6b0919b3..0f449fa927 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -177,8 +177,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ff717c5062..80825466a3 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -164,8 +164,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index e6baea2e0d..993c39aa2f 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -159,8 +159,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 9755df28e5..ae0b5d3dde 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -59,7 +59,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); + return MWWorld::Ptr(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index da4c7deb22..15c0039a48 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -417,7 +417,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(); + //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index dae5f84963..a2cbae2a0f 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -44,6 +44,7 @@ namespace MWMechanics return MWWorld::Ptr(); // check interior cells only // Check all the doors in this cell + /* MWWorld::CellRefList& doors = cell->get(); MWWorld::CellRefList::List& refList = doors.mList; MWWorld::CellRefList::List::iterator it = refList.begin(); @@ -66,6 +67,7 @@ namespace MWMechanics return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching } } + */ return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f88bf09587..89b2002622 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -73,6 +73,7 @@ namespace MWWorld MWWorld::TimeStamp mLastRespawn; + // List of refs owned by this cell CellRefList mActivators; CellRefList mPotions; CellRefList mAppas; @@ -179,6 +180,8 @@ namespace MWWorld forEachImp (functor, mNpcs); } + /// \todo add const version of forEach + bool isExterior() const; Ptr searchInContainer (const std::string& id); @@ -198,16 +201,6 @@ namespace MWWorld void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. - template - CellRefList& get() { - throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); - } - - template - const CellRefList& getReadOnly() { - throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); - } - bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; @@ -241,152 +234,6 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mActivators; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mPotions; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mAppas; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mArmors; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mBooks; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mClothes; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mContainers; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mCreatures; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mDoors; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mIngreds; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mCreatureLists; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mItemLists; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mLights; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mLockpicks; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mMiscItems; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mNpcs; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mProbes; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mRepairs; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mStatics; - } - - template<> - inline CellRefList& CellStore::get() - { - mHasState = true; - return mWeapons; - } - - template<> - inline const CellRefList& CellStore::getReadOnly() - { - return mDoors; - } - bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index e30246f7cb..aa5abc076f 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -116,6 +116,7 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) void MWWorld::LocalScripts::addCell (CellStore *cell) { + /* listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); @@ -136,6 +137,7 @@ void MWWorld::LocalScripts::addCell (CellStore *cell) listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); listCellScripts (*this, cell->get(), cell); + */ } void MWWorld::LocalScripts::clear() diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 22485ed92e..950c38e769 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1693,6 +1693,7 @@ namespace MWWorld osg::Vec2f World::getNorthVector (CellStore* cell) { + /* MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) @@ -1702,10 +1703,13 @@ namespace MWWorld osg::Vec3f dir = orient * osg::Vec3f(0,1,0); osg::Vec2f d (dir.x(), dir.y()); return d; + */ + return osg::Vec2f(); } void World::getDoorMarkers (CellStore* cell, std::vector& out) { + /* MWWorld::CellRefList& doors = cell->get(); CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) @@ -1744,6 +1748,7 @@ namespace MWWorld out.push_back(newMarker); } } + */ } void World::setWaterHeight(const float height) @@ -2240,6 +2245,7 @@ namespace MWWorld void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) { + /* const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { @@ -2254,6 +2260,7 @@ namespace MWWorld out.push_back(ptr); } } + */ } struct ListObjectsFunctor @@ -2316,6 +2323,8 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { + return false; + /* typedef MWWorld::CellRefList::List DoorList; typedef MWWorld::CellRefList::List StaticList; @@ -2368,6 +2377,7 @@ namespace MWWorld pos = statics.begin()->mRef.getPosition(); return true; } + */ return false; } @@ -2715,6 +2725,8 @@ namespace MWWorld bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { + return false; + /* if (cell->isExterior()) return false; @@ -2732,7 +2744,7 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - const MWWorld::CellRefList& doors = next->getReadOnly(); + const MWWorld::CellRefList& doors = next->getReadOnlyDoors(); const CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2761,10 +2773,12 @@ namespace MWWorld // No luck :( return false; + */ } MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { + /* if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } @@ -2792,7 +2806,7 @@ namespace MWWorld return closestMarker; } - const MWWorld::CellRefList& doors = next->getReadOnly(); + const MWWorld::CellRefList& doors = next->getReadOnlyDoors(); const CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2816,7 +2830,7 @@ namespace MWWorld } } } - + */ return MWWorld::Ptr(); } From fc449233bebb6c6864ca284a6c8cd0d307d8a3c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:12:05 +0100 Subject: [PATCH 1576/1812] Restore support for inserting objects into a cell --- apps/openmw/mwclass/activator.cpp | 3 +- apps/openmw/mwclass/apparatus.cpp | 3 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/book.cpp | 3 +- apps/openmw/mwclass/clothing.cpp | 3 +- apps/openmw/mwclass/container.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 3 +- apps/openmw/mwclass/ingredient.cpp | 3 +- apps/openmw/mwclass/light.cpp | 3 +- apps/openmw/mwclass/lockpick.cpp | 3 +- apps/openmw/mwclass/misc.cpp | 7 +- apps/openmw/mwclass/npc.cpp | 3 +- apps/openmw/mwclass/potion.cpp | 3 +- apps/openmw/mwclass/probe.cpp | 3 +- apps/openmw/mwclass/repair.cpp | 3 +- apps/openmw/mwclass/static.cpp | 3 +- apps/openmw/mwclass/weapon.cpp | 3 +- apps/openmw/mwworld/cellstore.hpp | 125 +++++++++++++++++++++++++++++ 19 files changed, 145 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index fdbff026fc..17757cb6b7 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -130,7 +130,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 06eea2c24c..07bf250860 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -147,9 +147,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 9ad28a537a..631ddd9129 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -381,9 +381,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index cfa2508c48..9ea9e659b6 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -186,9 +186,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8bd3fd2e66..7250e1837e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -275,9 +275,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b82dff7063..9e8c018cd9 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -292,9 +292,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7f43f86770..e5a98c8893 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -599,9 +599,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Creature::isBipedal(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index cb9f59e96d..d0448f7ec7 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -309,9 +309,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } void Door::ensureCustomData(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 0b6724c6cc..db2f2410b6 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -184,9 +184,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 0442fd2e06..fe51490775 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -216,9 +216,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index bd17a527b7..63f75a845c 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -165,9 +165,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 16d926f5ef..a14ab33302 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -194,7 +194,6 @@ namespace MWClass { MWWorld::Ptr newPtr; - /* const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -216,15 +215,15 @@ namespace MWClass MWWorld::ManualRef newRef(store, base); MWWorld::LiveCellRef *ref = newRef.getPtr().get(); - newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); + + newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getRefData().setCount(1); } else { MWWorld::LiveCellRef *ref = ptr.get(); - newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); + newPtr = MWWorld::Ptr(cell.insert(ref), &cell); } - */ return newPtr; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b5f2b52f3b..7ab95bffaf 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1129,9 +1129,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 0f449fa927..20a849019f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -177,9 +177,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 80825466a3..79f423b30d 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -164,9 +164,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 993c39aa2f..78ec2adcca 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -159,9 +159,8 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index ae0b5d3dde..86019a5ad6 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -59,8 +59,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 15c0039a48..5665bf1c45 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -417,8 +417,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(); - //return MWWorld::Ptr(&cell.get().insert(*ref), &cell); + return MWWorld::Ptr(cell.insert(ref), &cell); } int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 89b2002622..8bf4d0ae93 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -97,6 +97,9 @@ namespace MWWorld public: + template + LiveCellRefBase* insert(const LiveCellRef* ref); + CellStore (const ESM::Cell *cell_); const ESM::Cell *getCell() const; @@ -234,6 +237,128 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; + + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mActivators.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mPotions.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mAppas.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mArmors.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mBooks.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mClothes.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mContainers.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mCreatures.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mDoors.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mIngreds.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mCreatureLists.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mItemLists.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mLights.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mLockpicks.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mMiscItems.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mNpcs.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mProbes.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mRepairs.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mStatics.insert(*ref); + } + template<> + inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + { + mHasState = true; + return &mWeapons.insert(*ref); + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } From 7a983340bfd3502e500c6fe76e4b1005adc480cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:25:00 +0100 Subject: [PATCH 1577/1812] Add comment --- apps/openmw/mwworld/cellstore.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8bf4d0ae93..979316efc2 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -97,6 +97,9 @@ namespace MWWorld public: + /// Make a copy of the given object and insert it into this cell. + /// @note If you get a linker error here, this means the given type can not be inserted into a cell. + /// The supported types are defined at the bottom of this file. template LiveCellRefBase* insert(const LiveCellRef* ref); From 64b4926127a7b7780213fa0feaac7b1c47a69487 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Nov 2015 17:44:16 +0100 Subject: [PATCH 1578/1812] Add reference moving logic - untested --- apps/openmw/mwworld/cellstore.cpp | 48 ++++++++++++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 21 ++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5832a6727f..e3ee7d249e 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -179,8 +179,54 @@ namespace MWWorld return (ref.mRef.mRefnum == pRefnum); } + void CellStore::moveFrom(const Ptr &object, CellStore *from) + { + MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); + if (found != mMovedToAnotherCell.end()) + { + // A cell we had previously moved an object to is returning it to us. + assert (found->second == from); + mMovedToAnotherCell.erase(found); + } + else + { + mMovedHere.insert(std::make_pair(object.getBase(), from)); + } + } + + void CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) + { + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); + if (found != mMovedHere.end()) + { + // Special case - object didn't originate in this cell + // Move it back to its original cell first + CellStore* originalCell = found->second; + assert (originalCell != this); + originalCell->moveFrom(object, this); + + mMovedHere.erase(found); + + // Now that object is back to its rightful owner, we can move it + originalCell->moveTo(object, cellToMoveTo); + + updateMergedRefs(); + return; + } + + cellToMoveTo->moveFrom(object, this); + mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo)); + + updateMergedRefs(); + } + + void CellStore::updateMergedRefs() + { + + } + CellStore::CellStore (const ESM::Cell *cell) - : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) + : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) { mWaterLevel = cell->mWater; } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 979316efc2..ef1192277c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -95,8 +95,29 @@ namespace MWWorld CellRefList mStatics; CellRefList mWeapons; + typedef std::map MovedRefTracker; + // References owned by a different cell that have been moved here. + // + MovedRefTracker mMovedHere; + // References owned by this cell that have been moved to another cell. + // + MovedRefTracker mMovedToAnotherCell; + + // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell + std::vector mMergedRefs; + + /// Moves object from the given cell to this cell. + void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); + + /// Repopulate mMergedRefs. + void updateMergedRefs(); + public: + /// Moves object from this cell to the given cell. + /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) + void moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. From 3aa53f3cb4cacbe9f88fe71dec800b6177c84ed3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 19:46:02 +0100 Subject: [PATCH 1579/1812] Object cell movement tracker works. Savegame handling is still missing and some game functionality is still stubbed out. --- apps/openmw/mwworld/cellstore.cpp | 178 ++++++++++++++++++------------ apps/openmw/mwworld/cellstore.hpp | 175 +++++++++++++++-------------- apps/openmw/mwworld/scene.cpp | 16 ++- apps/openmw/mwworld/worldimp.cpp | 11 +- 4 files changed, 214 insertions(+), 166 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e3ee7d249e..d56baf231f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -47,13 +47,16 @@ namespace template MWWorld::Ptr searchViaActorId (MWWorld::CellRefList& actorList, int actorId, - MWWorld::CellStore *cell) + MWWorld::CellStore *cell, const std::map& toIgnore) { for (typename MWWorld::CellRefList::List::iterator iter (actorList.mList.begin()); iter!=actorList.mList.end(); ++iter) { MWWorld::Ptr actor (&*iter, cell); + if (toIgnore.find(&*iter) != toIgnore.end()) + continue; + if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0) return actor; } @@ -181,6 +184,7 @@ namespace MWWorld void CellStore::moveFrom(const Ptr &object, CellStore *from) { + mHasState = true; MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); if (found != mMovedToAnotherCell.end()) { @@ -192,10 +196,27 @@ namespace MWWorld { mMovedHere.insert(std::make_pair(object.getBase(), from)); } + + if (mState == State_Loaded) + updateMergedRefs(); + else if (mState == State_Preloaded) + { + mIds.push_back(object.getCellRef().getRefId()); + std::sort(mIds.begin(), mIds.end()); + } } - void CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) + MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) { + if (cellToMoveTo == this) + throw std::runtime_error("object is already in this cell"); + + // We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise. + if (mState != State_Loaded) + throw std::runtime_error("can't move object from a non-loaded cell (how did you get this object anyway?)"); + + // TODO: ensure that the object actually exists in the cell + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) { @@ -208,21 +229,59 @@ namespace MWWorld mMovedHere.erase(found); // Now that object is back to its rightful owner, we can move it - originalCell->moveTo(object, cellToMoveTo); + if (cellToMoveTo != originalCell) + { + originalCell->moveTo(object, cellToMoveTo); + } updateMergedRefs(); - return; + return MWWorld::Ptr(object.getBase(), cellToMoveTo); } cellToMoveTo->moveFrom(object, this); mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo)); updateMergedRefs(); + return MWWorld::Ptr(object.getBase(), cellToMoveTo); } + struct MergeFunctor + { + MergeFunctor(std::vector& mergeTo, const std::map& movedHere, + const std::map& movedToAnotherCell) + : mMergeTo(mergeTo) + , mMovedHere(movedHere) + , mMovedToAnotherCell(movedToAnotherCell) + { + } + + bool operator() (const MWWorld::Ptr& ptr) + { + if (mMovedToAnotherCell.find(ptr.getBase()) != mMovedToAnotherCell.end()) + return true; + mMergeTo.push_back(ptr.getBase()); + return true; + } + + void merge() + { + for (std::map::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + mMergeTo.push_back(it->first); + } + + private: + std::vector& mMergeTo; + + const std::map& mMovedHere; + const std::map& mMovedToAnotherCell; + }; + void CellStore::updateMergedRefs() { - + mMergedRefs.clear(); + MergeFunctor functor(mMergedRefs, mMovedHere, mMovedToAnotherCell); + forEachInternal(functor); + functor.merge(); } CellStore::CellStore (const ESM::Cell *cell) @@ -258,85 +317,50 @@ namespace MWWorld return const_cast (this)->search (id).isEmpty(); } + struct SearchFunctor + { + MWWorld::Ptr mFound; + std::string mIdToFind; + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefId() == mIdToFind) + { + mFound = ptr; + return false; + } + return true; + } + }; + Ptr CellStore::search (const std::string& id) { bool oldState = mHasState; - mHasState = true; - - if (LiveCellRef *ref = mActivators.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mPotions.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mAppas.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mArmors.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mBooks.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mClothes.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mContainers.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatures.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mDoors.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mIngreds.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mCreatureLists.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mItemLists.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLights.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mLockpicks.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mMiscItems.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mNpcs.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mProbes.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mRepairs.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mStatics.find (id)) - return Ptr (ref, this); - - if (LiveCellRef *ref = mWeapons.find (id)) - return Ptr (ref, this); + SearchFunctor searchFunctor; + searchFunctor.mIdToFind = id; + forEach(searchFunctor); mHasState = oldState; - - return Ptr(); + return searchFunctor.mFound; } Ptr CellStore::searchViaActorId (int id) { - if (Ptr ptr = ::searchViaActorId (mNpcs, id, this)) + if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell)) return ptr; - if (Ptr ptr = ::searchViaActorId (mCreatures, id, this)) + if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell)) return ptr; + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + MWWorld::Ptr actor (it->first, this); + if (!actor.getClass().isActor()) + continue; + if (actor.getClass().getCreatureStats (actor).matchesActorId (id) && actor.getRefData().getCount() > 0) + return actor; + } + return Ptr(); } @@ -435,6 +459,8 @@ namespace MWWorld continue; } + // We don't need to check mMovedToAnotherCell because listRefs isn't used for loaded cells. + mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID)); } } @@ -447,6 +473,12 @@ namespace MWWorld mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } + // List runtime moved references + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + mIds.push_back(Misc::StringUtils::lowerCase(it->first->mRef.getRefId())); + } + std::sort (mIds.begin(), mIds.end()); } @@ -489,6 +521,8 @@ namespace MWWorld loadRef (ref, false, store); } + + updateMergedRefs(); } bool CellStore::isExterior() const @@ -610,11 +644,15 @@ namespace MWWorld writeReferenceCollection (writer, mRepairs); writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); + + // TODO: write moved references } void CellStore::readReferences (ESM::ESMReader& reader, const std::map& contentFileMap) { + // TODO: read moved references + mHasState = true; while (reader.isNextSub ("OBJE")) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ef1192277c..2ef03e2c41 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -112,11 +112,64 @@ namespace MWWorld /// Repopulate mMergedRefs. void updateMergedRefs(); + template + LiveCellRefBase* insertBase(CellRefList& list, const LiveCellRef* ref) + { + mHasState = true; + LiveCellRefBase* ret = &list.insert(*ref); + updateMergedRefs(); + return ret; + } + + // helper function for forEachInternal + template + bool forEachImp (Functor& functor, List& list) + { + for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); + ++iter) + { + if (iter->mData.isDeletedByContentFile()) + continue; + if (!functor (MWWorld::Ptr(&*iter, this))) + return false; + } + return true; + } + + // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for. + template + bool forEachInternal (Functor& functor) + { + return + forEachImp (functor, mActivators) && + forEachImp (functor, mPotions) && + forEachImp (functor, mAppas) && + forEachImp (functor, mArmors) && + forEachImp (functor, mBooks) && + forEachImp (functor, mClothes) && + forEachImp (functor, mContainers) && + forEachImp (functor, mDoors) && + forEachImp (functor, mIngreds) && + forEachImp (functor, mItemLists) && + forEachImp (functor, mLights) && + forEachImp (functor, mLockpicks) && + forEachImp (functor, mMiscItems) && + forEachImp (functor, mProbes) && + forEachImp (functor, mRepairs) && + forEachImp (functor, mStatics) && + forEachImp (functor, mWeapons) && + forEachImp (functor, mCreatures) && + forEachImp (functor, mNpcs) && + forEachImp (functor, mCreatureLists); + } + public: /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) - void moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + /// @note throws exception if cellToMoveTo == this + /// @return updated MWWorld::Ptr with the new CellStore pointer set. + MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. @@ -136,6 +189,7 @@ namespace MWWorld bool hasId (const std::string& id) const; ///< May return true for deleted IDs when in preload state. Will return false, if cell is /// unloaded. + /// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded. Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in @@ -166,45 +220,23 @@ namespace MWWorld /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? - /// - /// \note Creatures and NPCs are handled last. template bool forEach (Functor& functor) { + if (mState != State_Loaded) + return false; + mHasState = true; - return - forEachImp (functor, mActivators) && - forEachImp (functor, mPotions) && - forEachImp (functor, mAppas) && - forEachImp (functor, mArmors) && - forEachImp (functor, mBooks) && - forEachImp (functor, mClothes) && - forEachImp (functor, mContainers) && - forEachImp (functor, mDoors) && - forEachImp (functor, mIngreds) && - forEachImp (functor, mItemLists) && - forEachImp (functor, mLights) && - forEachImp (functor, mLockpicks) && - forEachImp (functor, mMiscItems) && - forEachImp (functor, mProbes) && - forEachImp (functor, mRepairs) && - forEachImp (functor, mStatics) && - forEachImp (functor, mWeapons) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs) && - forEachImp (functor, mCreatureLists); - } + for (unsigned int i=0; imData.isDeletedByContentFile()) + continue; - template - bool forEachContainer (Functor& functor) - { - mHasState = true; - - return - forEachImp (functor, mContainers) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs); + if (!functor(MWWorld::Ptr(mMergedRefs[i], this))) + return false; + } + return true; } /// \todo add const version of forEach @@ -234,20 +266,6 @@ namespace MWWorld private: - template - bool forEachImp (Functor& functor, List& list) - { - for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); - ++iter) - { - if (iter->mData.isDeletedByContentFile()) - continue; - if (!functor (MWWorld::Ptr(&*iter, this))) - return false; - } - return true; - } - /// Run through references and store IDs void listRefs(const MWWorld::ESMStore &store, std::vector &esm); @@ -261,126 +279,105 @@ namespace MWWorld MWMechanics::PathgridGraph mPathgridGraph; }; - template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mActivators.insert(*ref); + return insertBase(mActivators, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mPotions.insert(*ref); + return insertBase(mPotions, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mAppas.insert(*ref); + return insertBase(mAppas, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mArmors.insert(*ref); + return insertBase(mArmors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mBooks.insert(*ref); + return insertBase(mBooks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mClothes.insert(*ref); + return insertBase(mClothes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mContainers.insert(*ref); + return insertBase(mContainers, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mCreatures.insert(*ref); + return insertBase(mCreatures, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mDoors.insert(*ref); + return insertBase(mDoors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mIngreds.insert(*ref); + return insertBase(mIngreds, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mCreatureLists.insert(*ref); + return insertBase(mCreatureLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mItemLists.insert(*ref); + return insertBase(mItemLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mLights.insert(*ref); + return insertBase(mLights, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mLockpicks.insert(*ref); + return insertBase(mLockpicks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mMiscItems.insert(*ref); + return insertBase(mMiscItems, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mNpcs.insert(*ref); + return insertBase(mNpcs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mProbes.insert(*ref); + return insertBase(mProbes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mRepairs.insert(*ref); + return insertBase(mRepairs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mStatics.insert(*ref); + return insertBase(mStatics, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { - mHasState = true; - return &mWeapons.insert(*ref); + return insertBase(mWeapons, ref); } bool operator== (const CellStore& left, const CellStore& right); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 45c94b6d9a..896d5f8ebd 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -116,7 +116,6 @@ namespace { addObject(ptr, mPhysics, mRendering); updateObjectRotation(ptr, mPhysics, mRendering, false); - ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) { @@ -129,6 +128,17 @@ namespace return true; } + + struct AdjustPositionFunctor + { + bool operator() (const MWWorld::Ptr& ptr) + { + if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) + ptr.getClass().adjustPosition (ptr, false); + return true; + } + }; + } @@ -553,6 +563,10 @@ namespace MWWorld { InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); cell.forEach (functor); + + // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order + AdjustPositionFunctor adjustPosFunctor; + cell.forEach (adjustPosFunctor); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 950c38e769..bb2ca2aae2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -722,7 +722,7 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { FindContainerFunctor functor(ptr); - (*cellIt)->forEachContainer(functor); + //(*cellIt)->forEachContainer(functor); if (!functor.mResult.isEmpty()) return functor.mResult; @@ -1146,7 +1146,7 @@ namespace MWWorld bool newCellActive = mWorldScene->isCellActive(*newCell); if (!currCellActive && newCellActive) { - newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = currCell->moveTo(ptr, newCell); mWorldScene->addObjectToScene(newPtr); std::string script = newPtr.getClass().getScript(newPtr); @@ -1162,14 +1162,14 @@ namespace MWWorld removeContainerScripts (ptr); haveToMove = false; - newPtr = ptr.getClass().copyToCell(ptr, *newCell); + newPtr = currCell->moveTo(ptr, newCell); newPtr.getRefData().setBaseNode(0); } else if (!currCellActive && !newCellActive) - newPtr = ptr.getClass().copyToCell(ptr, *newCell); + newPtr = currCell->moveTo(ptr, newCell); else // both cells active { - newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); + newPtr = currCell->moveTo(ptr, newCell); mRendering->updatePtr(ptr, newPtr); ptr.getRefData().setBaseNode(NULL); @@ -1189,7 +1189,6 @@ namespace MWWorld addContainerScripts (newPtr, newCell); } } - ptr.getRefData().setCount(0); } } if (haveToMove && newPtr.getRefData().getBaseNode()) From 3dcefd17fc94bc970a8d8b6b3eb90245f78d781f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 20:03:14 +0100 Subject: [PATCH 1580/1812] Fix CellStore::count() --- apps/openmw/mwworld/cellstore.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index d56baf231f..1a1802a051 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -379,27 +379,7 @@ namespace MWWorld int CellStore::count() const { - return - mActivators.mList.size() - + mPotions.mList.size() - + mAppas.mList.size() - + mArmors.mList.size() - + mBooks.mList.size() - + mClothes.mList.size() - + mContainers.mList.size() - + mDoors.mList.size() - + mIngreds.mList.size() - + mCreatureLists.mList.size() - + mItemLists.mList.size() - + mLights.mList.size() - + mLockpicks.mList.size() - + mMiscItems.mList.size() - + mProbes.mList.size() - + mRepairs.mList.size() - + mStatics.mList.size() - + mWeapons.mList.size() - + mCreatures.mList.size() - + mNpcs.mList.size(); + return mMergedRefs.size(); } void CellStore::load (const MWWorld::ESMStore &store, std::vector &esm) From 3f93af4181914cbf0691e38e25e68888c7cf374b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Dec 2015 23:28:11 +0100 Subject: [PATCH 1581/1812] Projectiles interact with the water surface (Fixes #2986) --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/ripplesimulation.cpp | 14 +++++-- apps/openmw/mwrender/ripplesimulation.hpp | 2 + apps/openmw/mwrender/water.cpp | 5 +++ apps/openmw/mwrender/water.hpp | 2 + apps/openmw/mwworld/projectilemanager.cpp | 45 ++++++++++++++--------- apps/openmw/mwworld/projectilemanager.hpp | 7 +++- apps/openmw/mwworld/worldimp.cpp | 2 +- 9 files changed, 60 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c0a907f70d..6e97905b82 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -756,6 +756,11 @@ namespace MWRender mWater->removeEmitter(ptr); } + void RenderingManager::emitWaterRipple(const osg::Vec3f &pos) + { + mWater->emitRipple(pos); + } + void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a0ea14cb4a..4d223aeb84 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -138,6 +138,7 @@ namespace MWRender void addWaterRippleEmitter(const MWWorld::Ptr& ptr); void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); + void emitWaterRipple(const osg::Vec3f& pos); void updatePlayerPtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 55b732613f..766e20fc4e 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -139,9 +139,7 @@ void RippleSimulation::update(float dt) if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) continue; // TODO: remove the oldest particle to make room? - osgParticle::Particle* p = mParticleSystem->createParticle(NULL); - p->setPosition(currentPos); - p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + emitRipple(currentPos); } } } @@ -194,6 +192,16 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) } } +void RippleSimulation::emitRipple(const osg::Vec3f &pos) +{ + if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20) + { + osgParticle::Particle* p = mParticleSystem->createParticle(NULL); + p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f)); + p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); + } +} + void RippleSimulation::setWaterHeight(float height) { mParticleNode->setPosition(osg::Vec3f(0,0,height)); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 17d5fea15f..7d412f4542 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -52,6 +52,8 @@ namespace MWRender void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void removeCell(const MWWorld::CellStore* store); + void emitRipple(const osg::Vec3f& pos); + /// Change the height of the water surface, thus moving all ripples with it void setWaterHeight(float height); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1afb74bd73..9823d79dfa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -731,6 +731,11 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) mSimulation->updateEmitterPtr(old, ptr); } +void Water::emitRipple(const osg::Vec3f &pos) +{ + mSimulation->emitRipple(pos); +} + void Water::removeCell(const MWWorld::CellStore *store) { mSimulation->removeCell(store); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 551184c11c..b26782873f 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -91,6 +91,8 @@ namespace MWRender void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void emitRipple(const osg::Vec3f& pos); + void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell void clearRipples(); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 08ae6f2b0c..e188afc5d5 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -25,6 +25,7 @@ #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" #include "../mwrender/vismask.hpp" +#include "../mwrender/renderingmanager.hpp" #include "../mwsound/sound.hpp" @@ -34,9 +35,11 @@ namespace MWWorld { - ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, MWPhysics::PhysicsSystem* physics) + ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, + MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics) : mParent(parent) , mResourceSystem(resourceSystem) + , mRendering(rendering) , mPhysics(physics) { @@ -225,32 +228,38 @@ namespace MWWorld // TODO: use a proper btRigidBody / btGhostObject? MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); - if (result.mHit) + bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos); + if (result.mHit || underwater) { - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); - - // Try to get a Ptr to the bow that was used. It might no longer exist. - MWWorld::Ptr bow = projectileRef.getPtr(); - if (!caster.isEmpty()) + if (result.mHit) { - MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); - MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) - bow = *invIt; + MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); + + // Try to get a Ptr to the bow that was used. It might no longer exist. + MWWorld::Ptr bow = projectileRef.getPtr(); + if (!caster.isEmpty()) + { + MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); + MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) + bow = *invIt; + } + + if (caster.isEmpty()) + caster = result.mHitObject; + + MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); } - if (caster.isEmpty()) - caster = result.mHitObject; - - MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength); + if (underwater) + mRendering->emitWaterRipple(newPos); mParent->removeChild(it->mNode); - it = mProjectiles.erase(it); continue; } - else - ++it; + + ++it; } } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 22fc4784cd..87878ef2af 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -36,6 +36,7 @@ namespace Resource namespace MWRender { class EffectAnimationTime; + class RenderingManager; } namespace MWWorld @@ -45,7 +46,7 @@ namespace MWWorld { public: ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem, - MWPhysics::PhysicsSystem* physics); + MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, @@ -67,6 +68,7 @@ namespace MWWorld private: osg::ref_ptr mParent; Resource::ResourceSystem* mResourceSystem; + MWRender::RenderingManager* mRendering; MWPhysics::PhysicsSystem* mPhysics; struct State @@ -120,6 +122,9 @@ namespace MWWorld void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); void update (State& state, float duration); + + void operator=(const ProjectileManager&); + ProjectileManager(const ProjectileManager&); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 22485ed92e..a2c8b6bd9f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,8 +163,8 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); + mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mRendering, mPhysics)); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From a8938589f6520cc5d62f587878f3316524db38bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:03:25 +0100 Subject: [PATCH 1582/1812] Magic projectiles rotate during flight --- apps/openmw/mwworld/projectilemanager.cpp | 53 ++++++++++++++++++++--- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e188afc5d5..80eab27cd9 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -45,15 +45,54 @@ namespace MWWorld } - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient) + /// Rotates an osg::PositionAttitudeTransform over time. + class RotateCallback : public osg::NodeCallback + { + public: + RotateCallback(const osg::Vec3f& axis = osg::Vec3f(0,-1,0), float rotateSpeed = osg::PI*2) + : mAxis(axis) + , mRotateSpeed(rotateSpeed) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::PositionAttitudeTransform* transform = static_cast(node); + + double time = nv->getFrameStamp()->getSimulationTime(); + + osg::Quat orient = osg::Quat(time * mRotateSpeed, mAxis); + transform->setAttitude(orient); + + traverse(node, nv); + } + + private: + osg::Vec3f mAxis; + float mRotateSpeed; + }; + + + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - mParent->addChild(state.mNode); - mResourceSystem->getSceneManager()->createInstance(model, state.mNode); + osg::Group* attachTo = state.mNode; + + if (rotate) + { + osg::ref_ptr rotateNode (new osg::PositionAttitudeTransform); + rotateNode->addUpdateCallback(new RotateCallback()); + state.mNode->addChild(rotateNode); + attachTo = rotateNode; + } + + mResourceSystem->getSceneManager()->createInstance(model, attachTo); + + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); @@ -107,7 +146,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); @@ -128,7 +167,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false); mProjectiles.push_back(state); } @@ -348,7 +387,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); mProjectiles.push_back(state); return true; @@ -379,7 +418,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation)); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 87878ef2af..f58e266b38 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -120,7 +120,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate); void update (State& state, float duration); void operator=(const ProjectileManager&); From 618159425170dd0e19b75a401733796e039f813e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:04:23 +0100 Subject: [PATCH 1583/1812] Disable freezeOnCull for magic projectile particles --- apps/openmw/mwworld/projectilemanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 80eab27cd9..e087478b3b 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -92,6 +93,9 @@ namespace MWWorld mResourceSystem->getSceneManager()->createInstance(model, attachTo); + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + state.mNode->accept(disableFreezeOnCullVisitor); + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); From 258f7a2b42c6b2083aabe196eaa43e7c5d9854d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:38:06 +0100 Subject: [PATCH 1584/1812] LightController fixes --- components/sceneutil/lightcontroller.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index d44a1a94ae..511937a282 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -61,8 +61,10 @@ namespace SceneUtil void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv) { double time = nv->getFrameStamp()->getSimulationTime(); - if (time == mLastTime) - return; + + // disabled early out, light state needs to be set every frame regardless of change, due to the double buffering + //if (time == mLastTime) + // return; float dt = static_cast(time - mLastTime); mLastTime = time; @@ -119,6 +121,8 @@ namespace SceneUtil brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f; static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness); + + traverse(node, nv); } void LightController::setDiffuse(osg::Vec4f color) From 67a6a8f5d437e24bd58d59f6cd82dd3a717eac7c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 00:44:04 +0100 Subject: [PATCH 1585/1812] Make projectiles receive lighting --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/projectilemanager.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6e97905b82..f4e7ca6840 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -227,6 +227,11 @@ namespace MWRender return mResourceSystem; } + osg::Group* RenderingManager::getLightRoot() + { + return mLightRoot.get(); + } + void RenderingManager::setNightEyeFactor(float factor) { if (factor != mNightEyeFactor) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4d223aeb84..936f7cb994 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -65,6 +65,8 @@ namespace MWRender Resource::ResourceSystem* getResourceSystem(); + osg::Group* getLightRoot(); + void setNightEyeFactor(float factor); void setAmbientColour(const osg::Vec4f& colour); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e087478b3b..5728fe1d73 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -96,6 +97,8 @@ namespace MWWorld SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); + state.mNode->addCullCallback(new SceneUtil::LightListCallback); + mParent->addChild(state.mNode); state.mEffectAnimationTime.reset(new MWRender::EffectAnimationTime); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a2c8b6bd9f..0cb2e980da 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -164,7 +164,7 @@ namespace MWWorld { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); - mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mRendering, mPhysics)); + mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering, mPhysics)); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); From 66bcd2fd685b0421dd4884755c260703b64e9049 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 01:05:24 +0100 Subject: [PATCH 1586/1812] Write save games to a memory stream first Two motivations for doing this: - If the user chooses to overwrite existing save file, and there is an exception during the save process, the existing file will not be lost. - Many small writes to a file are slow. Very slow. Writing to memory first then writing the completed file to disk appears to be ~500% faster. --- apps/openmw/mwstate/statemanagerimp.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index b76d9eae55..b5426bc77b 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -207,7 +207,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot else slot = getCurrentCharacter()->updateSlot (slot, profile); - boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); + // Write to a memory stream first. If there is an exception during the save process, we don't want to trash the + // existing save file we are overwriting. + std::stringstream stream; ESM::ESMWriter writer; @@ -262,7 +264,14 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.close(); if (stream.fail()) - throw std::runtime_error("Write operation failed"); + throw std::runtime_error("Write operation failed (memory stream)"); + + // All good, write to file + boost::filesystem::ofstream filestream (slot->mPath, std::ios::binary); + filestream << stream.rdbuf(); + + if (filestream.fail()) + throw std::runtime_error("Write operation failed (file stream)"); Settings::Manager::setString ("character", "Saves", slot->mPath.parent_path().filename().string()); From 53158d29b17a96ff3a3c9474d636221b383039d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 01:54:16 +0100 Subject: [PATCH 1587/1812] stopSound crash fix --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 ++- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index fd38a0ce56..1b7e912858 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -612,7 +612,8 @@ namespace MWSound void SoundManager::stopSound(MWBase::SoundPtr sound) { - mOutput->stopSound(sound); + if (sound.get()) + mOutput->stopSound(sound); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index c1d8eeb219..7058c55b64 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -201,6 +201,7 @@ namespace MWSound virtual void stopSound(MWBase::SoundPtr sound); ///< Stop the given sound from playing + /// @note no-op if \a sound is null virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, From c60f4ba7bdd948b58842e82a4b31d29984359b74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Dec 2015 15:02:35 +0100 Subject: [PATCH 1588/1812] Make RigGeometry bone references case-insensitive (Fixes #3058) --- components/sceneutil/skeleton.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 83f7d65378..332dc3b071 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include namespace SceneUtil @@ -23,7 +25,7 @@ public: if (!bone) return; - mCache[bone->getName()] = std::make_pair(getNodePath(), bone); + mCache[Misc::StringUtils::lowerCase(bone->getName())] = std::make_pair(getNodePath(), bone); traverse(node); } @@ -59,7 +61,7 @@ Bone* Skeleton::getBone(const std::string &name) mBoneCacheInit = true; } - BoneCache::iterator found = mBoneCache.find(name); + BoneCache::iterator found = mBoneCache.find(Misc::StringUtils::lowerCase(name)); if (found == mBoneCache.end()) return NULL; From c75303b652ee705ba4748afe6a2fd92014da72bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 12:54:41 -0800 Subject: [PATCH 1589/1812] Add an option to select and enable HRTF --- apps/openmw/mwsound/openal_output.cpp | 129 ++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.hpp | 6 +- apps/openmw/mwsound/sound_output.hpp | 6 +- apps/openmw/mwsound/soundmanagerimp.cpp | 43 ++++---- files/settings-default.cfg | 7 ++ 5 files changed, 172 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 54a5efb68b..407a24ce10 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -19,6 +19,28 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) @@ -571,6 +593,113 @@ void OpenAL_Output::deinit() } +std::vector OpenAL_Output::enumerateHrtf() +{ + if(!mDevice) + fail("Device not initialized"); + + std::vector ret; + if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + return ret; + + LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( + alcGetProcAddress(mDevice, "alcGetStringiSOFT") + ); + + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + ret.reserve(num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + ret.push_back(entry); + } + + return ret; +} + +void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) +{ + if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + { + std::cerr<< "HRTF extension not present" <( + alcGetProcAddress(mDevice, "alcGetStringiSOFT") + ); + LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( + alcGetProcAddress(mDevice, "alcResetDeviceSOFT") + ); + + std::vector attrs; + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(auto_enable ? ALC_DONT_CARE_SOFT : ALC_TRUE); + if(!hrtfname.empty()) + { + ALCint index = -1; + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + if(hrtfname == entry) + { + index = i; + break; + } + } + + if(index < 0) + std::cerr<< "Failed to find HRTF name \""<( + alcGetProcAddress(mDevice, "alcResetDeviceSOFT") + ); + + std::vector attrs; + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(ALC_FALSE); + attrs.push_back(0); + alcResetDeviceSOFT(mDevice, &attrs[0]); + + ALCint hrtf_state; + alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); + if(hrtf_state) + std::cerr<< "Failed to disable HRTF" < enumerate(); - virtual void init(const std::string &devname=""); + virtual void init(const std::string &devname=std::string()); virtual void deinit(); + virtual std::vector enumerateHrtf(); + virtual void enableHrtf(const std::string &hrtfname, bool auto_enable); + virtual void disableHrtf(); + virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2f459d09b0..79025abb00 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,9 +24,13 @@ namespace MWSound SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual void init(const std::string &devname="") = 0; + virtual void init(const std::string &devname=std::string()) = 0; virtual void deinit() = 0; + virtual std::vector enumerateHrtf() = 0; + virtual void enableHrtf(const std::string &hrtfname, bool auto_enable) = 0; + virtual void disableHrtf() = 0; + virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b7e912858..a13acf3e2f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -67,32 +67,44 @@ namespace MWSound mBufferCacheMax *= 1024*1024; mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); + int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; - try - { + try { std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:"<< std::endl; for(size_t i = 0;i < names.size();i++) std::cout <<" "<init(devname); } - catch(std::exception &e) - { + catch(std::exception &e) { if(devname.empty()) throw; std::cerr <<"Failed to open device \""<init(); Settings::Manager::setString("device", "Sound", ""); } + + names = mOutput->enumerateHrtf(); + if(!names.empty()) + { + std::cout <<"Enumerated HRTF names:"<< std::endl; + for(size_t i = 0;i < names.size();i++) + std::cout <<" "<disableHrtf(); + else if(!hrtfname.empty()) + mOutput->enableHrtf(hrtfname, hrtfstate<0); } - catch(std::exception &e) - { + catch(std::exception &e) { std::cout <<"Sound init failed: "<isInitialized()) + SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); + for(;sfxiter != mSoundBuffers->end();++sfxiter) { - SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin(); - for(;sfxiter != mSoundBuffers->end();++sfxiter) - { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; - } - mUnusedBuffers.clear(); + if(sfxiter->mHandle) + mOutput->unloadSound(sfxiter->mHandle); + sfxiter->mHandle = 0; } + mUnusedBuffers.clear(); mOutput.reset(); } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7d0292c5ba..47c3898109 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -174,6 +174,13 @@ buffer cache min = 14 # to this much memory until old buffers get purged. buffer cache max = 16 +# Specifies whether to enable HRTF processing. Valid values are: -1 = auto, +# 0 = off, 1 = on. +hrtf enable = -1 + +# Specifies which HRTF to use when HRTF is used. Blank means use the default. +hrtf = + [Video] # Resolution of the OpenMW window or screen. From 91cd6be11b4e23d4e9c9e6a97a33adafcee9999f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Dec 2015 18:00:28 -0800 Subject: [PATCH 1590/1812] Use the correct SoundId for NPC "land" sounds --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6633b3490b..ec37588d9b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1103,7 +1103,7 @@ namespace MWClass if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return "DefaultLandWater"; if(world->isOnGround(ptr)) - return "Body Fall Medium"; + return "DefaultLand"; return ""; } if(name == "swimleft") From 36ce8f97d7dbbda073576439673e2cee1160ae87 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 6 Dec 2015 11:18:31 +0100 Subject: [PATCH 1591/1812] basic framework for new user settings system --- apps/opencs/CMakeLists.txt | 8 ++++ apps/opencs/editor.cpp | 4 +- apps/opencs/editor.hpp | 7 ++- apps/opencs/model/prefs/state.cpp | 68 +++++++++++++++++++++++++++ apps/opencs/model/prefs/state.hpp | 49 ++++++++++++++++++++ apps/opencs/view/prefs/dialogue.cpp | 72 +++++++++++++++++++++++++++++ apps/opencs/view/prefs/dialogue.hpp | 39 ++++++++++++++++ 7 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/prefs/state.cpp create mode 100644 apps/opencs/model/prefs/state.hpp create mode 100644 apps/opencs/view/prefs/dialogue.cpp create mode 100644 apps/opencs/view/prefs/dialogue.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc90072fa4..628b97433b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -123,6 +123,10 @@ opencs_units_noqt (view/settings frame ) +opencs_units (view/prefs + dialogue + ) + opencs_units (model/settings usersettings setting @@ -133,6 +137,10 @@ opencs_hdrs_noqt (model/settings support ) +opencs_units (model/prefs + state + ) + opencs_units_noqt (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e3ecdce05b..78959fe095 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -18,7 +18,7 @@ #endif CS::Editor::Editor () -: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), +: mSettingsState (mCfgMgr), mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), mLock(), mMerge (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) @@ -28,7 +28,7 @@ CS::Editor::Editor () setupDataFiles (config.first); CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); - mSettings.setModel (CSMSettings::UserSettings::instance()); +// mSettings.setModel (CSMSettings::UserSettings::instance()); NifOsg::Loader::setShowMarkers(true); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index ac403b1eee..d7fc0b7156 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -20,6 +20,8 @@ #include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" +#include "model/prefs/state.hpp" + #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" #include "view/doc/filedialog.hpp" @@ -27,6 +29,8 @@ #include "view/settings/dialog.hpp" +#include "view/prefs/dialogue.hpp" + #include "view/tools/merge.hpp" namespace VFS @@ -49,12 +53,13 @@ namespace CS std::auto_ptr mVFS; Files::ConfigurationManager mCfgMgr; + CSMPrefs::State mSettingsState; CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; CSVDoc::NewGameDialogue mNewGame; - CSVSettings::Dialog mSettings; + CSVPrefs::Dialogue mSettings; CSVDoc::FileDialog mFileDialog; boost::filesystem::path mLocal; boost::filesystem::path mResources; diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp new file mode 100644 index 0000000000..9b183f66a7 --- /dev/null +++ b/apps/opencs/model/prefs/state.cpp @@ -0,0 +1,68 @@ + +#include "state.hpp" + +#include + +CSMPrefs::State *CSMPrefs::State::sThis = 0; + +void CSMPrefs::State::load() +{ + // default settings file + boost::filesystem::path local = mConfigurationManager.getLocalPath() / mConfigFile; + boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mConfigFile; + + if (boost::filesystem::exists (local)) + mSettings.loadDefault (local.string()); + else if (boost::filesystem::exists (global)) + mSettings.loadDefault (global.string()); + else + throw std::runtime_error ("No default settings file found! Make sure the file \"opencs.ini\" was properly installed."); + + // user settings file + boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; + + if (boost::filesystem::exists (user)) + mSettings.loadUser (user.string()); +} + +void CSMPrefs::State::declare() +{ + +} + +CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) +: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager) +{ + if (sThis) + throw std::logic_error ("An instance of CSMPRefs::State already exists"); + + load(); + declare(); + + sThis = this; +} + +CSMPrefs::State::~State() +{ + sThis = 0; +} + +void CSMPrefs::State::save() +{ + boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; + mSettings.saveUser (user.string()); +} + +CSMPrefs::State& CSMPrefs::State::get() +{ + if (!sThis) + throw std::logic_error ("No instance of CSMPrefs::State"); + + return *sThis; +} + + +CSMPrefs::State& CSMPrefs::get() +{ + return State::get(); +} diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp new file mode 100644 index 0000000000..d2ed8061e8 --- /dev/null +++ b/apps/opencs/model/prefs/state.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_PREFS_STATE_H +#define CSM_PREFS_STATE_H + +#include + +#ifndef Q_MOC_RUN +#include +#endif + +#include + +namespace CSMPrefs +{ + class State : public QObject + { + Q_OBJECT + + static State *sThis; + + const std::string mConfigFile; + const Files::ConfigurationManager& mConfigurationManager; + Settings::Manager mSettings; + + // not implemented + State (const State&); + State& operator= (const State&); + + private: + + void load(); + + void declare(); + + public: + + State (const Files::ConfigurationManager& configurationManager); + + ~State(); + + void save(); + + static State& get(); + }; + + // convenience function + State& get(); +} + +#endif diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp new file mode 100644 index 0000000000..5f5ceaada1 --- /dev/null +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -0,0 +1,72 @@ + +#include "dialogue.hpp" + +#include +#include +#include +#include +#include + +#include "../../model/prefs/state.hpp" + +void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) +{ + mList = new QListWidget (main); + mList->setMinimumWidth (50); + mList->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); + + mList->setSelectionBehavior (QAbstractItemView::SelectItems); + + main->addWidget (mList); + + /// \todo connect to selection signal +} + +void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) +{ + mContent = new QStackedWidget (main); + mContent->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); + + main->addWidget (mContent); +} + +CSVPrefs::Dialogue::Dialogue() +{ + setWindowTitle ("User Settings"); + + setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + setMinimumSize (600, 400); + + QSplitter *main = new QSplitter (this); + + setCentralWidget (main); + buildCategorySelector (main); + buildContentArea (main); +} + +void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event) +{ + QMainWindow::closeEvent (event); + + CSMPrefs::State::get().save(); +} + +void CSVPrefs::Dialogue::show() +{ + if (QWidget *active = QApplication::activeWindow()) + { + // place at the centre of the window with focus + QSize size = active->size(); + move (active->geometry().x()+(size.width() - frameGeometry().width())/2, + active->geometry().y()+(size.height() - frameGeometry().height())/2); + } + else + { + // otherwise place at the centre of the screen + QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); + move (screenCenter - QPoint(frameGeometry().width()/2, frameGeometry().height()/2)); + } + + QWidget::show(); +} diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp new file mode 100644 index 0000000000..78c832c9f5 --- /dev/null +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -0,0 +1,39 @@ +#ifndef CSV_PREFS_DIALOGUE_H +#define CSV_PREFS_DIALOGUE_H + +#include + +class QSplitter; +class QListWidget; +class QStackedWidget; + +namespace CSVPrefs +{ + class Dialogue : public QMainWindow + { + Q_OBJECT + + QListWidget *mList; + QStackedWidget *mContent; + + private: + + void buildCategorySelector (QSplitter *main); + + void buildContentArea (QSplitter *main); + + public: + + Dialogue(); + + protected: + + void closeEvent (QCloseEvent *event); + + public slots: + + void show(); + }; +} + +#endif From b37a2ac09c6f3047514d87c23bf2aed42e0221bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 6 Dec 2015 12:06:28 +0100 Subject: [PATCH 1592/1812] user settings categories --- apps/opencs/CMakeLists.txt | 4 +++ apps/opencs/model/prefs/category.cpp | 16 +++++++++ apps/opencs/model/prefs/category.hpp | 26 +++++++++++++++ apps/opencs/model/prefs/state.cpp | 50 +++++++++++++++++++++++++++- apps/opencs/model/prefs/state.hpp | 12 +++++++ apps/opencs/view/prefs/dialogue.cpp | 18 +++++++++- apps/opencs/view/prefs/dialogue.hpp | 1 + 7 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/model/prefs/category.cpp create mode 100644 apps/opencs/model/prefs/category.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 628b97433b..b58000b565 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -141,6 +141,10 @@ opencs_units (model/prefs state ) +opencs_units_noqt (model/prefs + category + ) + opencs_units_noqt (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp new file mode 100644 index 0000000000..2f94c729bf --- /dev/null +++ b/apps/opencs/model/prefs/category.cpp @@ -0,0 +1,16 @@ + +#include "category.hpp" + +CSMPrefs::Category::Category (State *parent, const std::string& key, const std::string& name) +: mParent (parent), mKey (key), mName (name) +{} + +const std::string& CSMPrefs::Category::getKey() const +{ + return mKey; +} + +const std::string& CSMPrefs::Category::getName() const +{ + return mName; +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp new file mode 100644 index 0000000000..d80d5416fb --- /dev/null +++ b/apps/opencs/model/prefs/category.hpp @@ -0,0 +1,26 @@ +#ifndef CSV_PREFS_CATEGORY_H +#define CSM_PREFS_CATEGORY_H + +#include + +namespace CSMPrefs +{ + class State; + + class Category + { + State *mParent; + std::string mKey; + std::string mName; + + public: + + Category (State *parent, const std::string& key, const std::string& name); + + const std::string& getKey() const; + + const std::string& getName() const; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 9b183f66a7..70e4c86c5e 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -2,6 +2,7 @@ #include "state.hpp" #include +#include CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -27,11 +28,45 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { + declareCategory ("window", "Windows"); + declareCategory ("records", "Records"); + + declareCategory ("table-input", "ID Tables"); + + declareCategory ("dialogues", "ID Dialogues"); + + declareCategory ("report-input", "Reports"); + + declareCategory ("search", "Search & Replace"); + + declareCategory ("script-editor", "Scripts"); + + declareCategory ("general-input", "General Input"); + + declareCategory ("scene-input", "3D Scene Input"); + + declareCategory ("tooltips", "Tooltips"); +} + +void CSMPrefs::State::declareCategory (const std::string& key, const std::string& name) +{ + std::map::iterator iter = mCategories.find (key); + + if (iter!=mCategories.end()) + { + mCurrentCategory = iter; + } + else + { + mCurrentCategory = + mCategories.insert (std::make_pair (key, Category (this, key, name))).first; + } } CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) -: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager) +: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), + mCurrentCategory (mCategories.end()) { if (sThis) throw std::logic_error ("An instance of CSMPRefs::State already exists"); @@ -53,6 +88,19 @@ void CSMPrefs::State::save() mSettings.saveUser (user.string()); } +std::vector > CSMPrefs::State::listCategories() const +{ + std::vector > list; + + for (std::map::const_iterator iter (mCategories.begin()); + iter!=mCategories.end(); ++iter) + list.push_back (std::make_pair (iter->second.getName(), iter->first)); + + std::sort (list.begin(), list.end()); + + return list; +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index d2ed8061e8..fd49db3ef5 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -1,6 +1,9 @@ #ifndef CSV_PREFS_STATE_H #define CSM_PREFS_STATE_H +#include +#include + #include #ifndef Q_MOC_RUN @@ -9,6 +12,8 @@ #include +#include "category.hpp" + namespace CSMPrefs { class State : public QObject @@ -20,6 +25,8 @@ namespace CSMPrefs const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; Settings::Manager mSettings; + std::map mCategories; + std::map::iterator mCurrentCategory; // not implemented State (const State&); @@ -31,6 +38,8 @@ namespace CSMPrefs void declare(); + void declareCategory (const std::string& key, const std::string& name); + public: State (const Files::ConfigurationManager& configurationManager); @@ -39,6 +48,9 @@ namespace CSMPrefs void save(); + /// \return collection of name, key pairs (sorted) + std::vector > listCategories() const; + static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 5f5ceaada1..cc794c286f 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../../model/prefs/state.hpp" @@ -19,6 +20,21 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) main->addWidget (mList); + QFontMetrics metrics (QApplication::font()); + + int maxWidth = 1; + + for (std::vector >::const_iterator iter (mCategories.begin()); + iter!=mCategories.end(); ++iter) + { + QString label = QString::fromUtf8 (iter->first.c_str()); + maxWidth = std::max (maxWidth, metrics.width (label)); + + mList->addItem (label); + } + + mList->setMaximumWidth (maxWidth + 10); + /// \todo connect to selection signal } @@ -30,7 +46,7 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } -CSVPrefs::Dialogue::Dialogue() +CSVPrefs::Dialogue::Dialogue() : mCategories (CSMPrefs::get().listCategories()) { setWindowTitle ("User Settings"); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 78c832c9f5..2773bccccb 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -15,6 +15,7 @@ namespace CSVPrefs QListWidget *mList; QStackedWidget *mContent; + std::vector > mCategories; private: From e39f49a88f1e8408a3b035739a8210f514b7037e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 15:27:43 +0100 Subject: [PATCH 1593/1812] OSG extensions namespace fixes --- components/nifosg/particle.hpp | 4 ++-- components/sceneutil/lightmanager.hpp | 2 +- components/sceneutil/riggeometry.hpp | 2 +- components/sceneutil/skeleton.hpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index ff4c66758f..d86408254b 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -30,7 +30,7 @@ namespace NifOsg ParticleSystem(); ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, NifOsg::ParticleSystem) + META_Object(NifOsg, ParticleSystem) virtual osgParticle::Particle* createParticle(const osgParticle::Particle *ptemplate); @@ -194,7 +194,7 @@ namespace NifOsg Emitter(); Emitter(const Emitter& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, NifOsg::Emitter) + META_Object(NifOsg, Emitter) virtual void emitParticles(double dt); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 522455390a..3e6d3251bb 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -158,7 +158,7 @@ namespace SceneUtil , mLastFrameNumber(0) {} - META_Object(NifOsg, LightListCallback) + META_Object(SceneUtil, LightListCallback) void operator()(osg::Node* node, osg::NodeVisitor* nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index f61fe62e7c..03c287b812 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -19,7 +19,7 @@ namespace SceneUtil RigGeometry(); RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop); - META_Object(NifOsg, RigGeometry) + META_Object(SceneUtil, RigGeometry) struct BoneInfluence { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d4418fa272..d98d367518 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -39,7 +39,7 @@ namespace SceneUtil Skeleton(); Skeleton(const Skeleton& copy, const osg::CopyOp& copyop); - META_Node(NifOsg, Skeleton) + META_Node(SceneUtil, Skeleton) /// Retrieve a bone by name. Bone* getBone(const std::string& name); From 1d5af3c9c8415ad376a792bd4deae3d9a7e43b82 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 15:44:27 +0100 Subject: [PATCH 1594/1812] Remove unneeded cast --- components/nifosg/nifloader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 18ece51016..c2629194d8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,7 +113,7 @@ namespace } }; - // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale + // NodeCallback used to have a node always oriented towards the camera. The node can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. // Must be set as a cull callback. class BillboardCallback : public osg::NodeCallback @@ -132,8 +132,7 @@ namespace virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = dynamic_cast(nv); - osg::MatrixTransform* billboardNode = dynamic_cast(node); - if (billboardNode && cv) + if (node && cv) { osg::Matrix modelView = *cv->getModelViewMatrix(); From 46f45773ca9655817fe1312bb6cd01bda41facba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 19 Aug 2015 11:09:38 +0200 Subject: [PATCH 1595/1812] CMake: Add the list of possible values for some config options Signed-off-by: Paul Cercueil --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db8bcc4f75..43b1e496db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,9 @@ project(OpenMW) # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel) ENDIF() if (APPLE) @@ -175,6 +176,7 @@ endif() # Dependencies if (USE_QT) set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) message(STATUS "Using Qt${DESIRED_QT_VERSION}") if (DESIRED_QT_VERSION MATCHES 4) From 0765ff3ba23d625f772b6cc703e68a8270efb00e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 6 Dec 2015 15:56:30 +0100 Subject: [PATCH 1596/1812] mwrender: Add missing includes Those missing includes were causing the build to fail when compiled with USE_GLES set. Signed-off-by: Paul Cercueil --- apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/sky.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 14ec770e84..9d5950a90e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 68ee17e6b3..20e3dc07c7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include #include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9823d79dfa..cd1f4c5113 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include From b320a01cee8847b9fa19c4e6e68f9fe8cc3cd345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 17:46:28 +0100 Subject: [PATCH 1597/1812] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index e968d1d01a..0672c14669 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) + Paul Cercueil (pcercuei) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) pkubik From 811df1e97ba2011b517c8fb16a60b7f920d174a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:03:55 +0100 Subject: [PATCH 1598/1812] Pass the ESM reader list to CellStore constructor --- apps/openmw/mwworld/cells.cpp | 20 ++++++++++---------- apps/openmw/mwworld/cellstore.cpp | 28 +++++++++++++++++----------- apps/openmw/mwworld/cellstore.hpp | 18 ++++++++++++------ 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b096301fd6..127e43fc07 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -23,7 +23,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) if (result==mInteriors.end()) { - result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first; } return &result->second; @@ -36,7 +36,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) if (result==mExteriors.end()) { result = mExteriors.insert (std::make_pair ( - std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell))).first; + std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell, mStore, mReader))).first; } @@ -70,7 +70,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore& void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const { if (cell.getState()!=CellStore::State_Loaded) - cell.load (mStore, mReader); + cell.load (); ESM::CellState cellState; @@ -114,13 +114,13 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y) } result = mExteriors.insert (std::make_pair ( - std::make_pair (x, y), CellStore (cell))).first; + std::make_pair (x, y), CellStore (cell, mStore, mReader))).first; } if (result->second.getState()!=CellStore::State_Loaded) { // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. - result->second.load (mStore, mReader); + result->second.load (); } return &result->second; @@ -135,12 +135,12 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) { const ESM::Cell *cell = mStore.get().find(lowerName); - result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first; } if (result->second.getState()!=CellStore::State_Loaded) { - result->second.load (mStore, mReader); + result->second.load (); } return &result->second; @@ -158,13 +158,13 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, bool searchInContainers) { if (cell.getState()==CellStore::State_Unloaded) - cell.preload (mStore, mReader); + cell.preload (); if (cell.getState()==CellStore::State_Preloaded) { if (cell.hasId (name)) { - cell.load (mStore, mReader); + cell.load (); } else return Ptr(); @@ -333,7 +333,7 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, cellStore->readFog(reader); if (cellStore->getState()!=CellStore::State_Loaded) - cellStore->load (mStore, mReader); + cellStore->load (); cellStore->readReferences (reader, contentFileMap); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1a1802a051..c435b0478f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -284,8 +284,8 @@ namespace MWWorld functor.merge(); } - CellStore::CellStore (const ESM::Cell *cell) - : mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) + CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector& readerList) + : mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) { mWaterLevel = cell->mWater; } @@ -382,14 +382,14 @@ namespace MWWorld return mMergedRefs.size(); } - void CellStore::load (const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::load () { if (mState!=State_Loaded) { if (mState==State_Preloaded) mIds.clear(); - loadRefs (store, esm); + loadRefs (); mState = State_Loaded; @@ -399,18 +399,20 @@ namespace MWWorld } } - void CellStore::preload (const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::preload () { if (mState==State_Unloaded) { - listRefs (store, esm); + listRefs (); mState = State_Preloaded; } } - void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::listRefs() { + std::vector& esm = mReader; + assert (mCell); if (mCell->mContextList.empty()) @@ -462,8 +464,10 @@ namespace MWWorld std::sort (mIds.begin(), mIds.end()); } - void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector &esm) + void CellStore::loadRefs() { + std::vector& esm = mReader; + assert (mCell); if (mCell->mContextList.empty()) @@ -490,7 +494,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted, store); + loadRef (ref, deleted); } } @@ -499,7 +503,7 @@ namespace MWWorld { ESM::CellRef &ref = const_cast(*it); - loadRef (ref, false, store); + loadRef (ref, false); } updateMergedRefs(); @@ -530,10 +534,12 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted) { Misc::StringUtils::toLower (ref.mRefID); + const MWWorld::ESMStore& store = mStore; + switch (store.find (ref.mRefID)) { case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2ef03e2c41..80fcaf48aa 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -60,6 +60,9 @@ namespace MWWorld private: + const MWWorld::ESMStore& mStore; + std::vector& mReader; + // Even though fog actually belongs to the player and not cells, // it makes sense to store it here since we need it once for each cell. // Note this is NULL until the cell is explored to save some memory @@ -177,7 +180,10 @@ namespace MWWorld template LiveCellRefBase* insert(const LiveCellRef* ref); - CellStore (const ESM::Cell *cell_); + /// @param readerList The readers to use for loading of the cell on-demand. + CellStore (const ESM::Cell *cell_, + const MWWorld::ESMStore& store, + std::vector& readerList); const ESM::Cell *getCell() const; @@ -210,10 +216,10 @@ namespace MWWorld int count() const; ///< Return total number of references, including deleted ones. - void load (const MWWorld::ESMStore &store, std::vector &esm); + void load (); ///< Load references from content file. - void preload (const MWWorld::ESMStore &store, std::vector &esm); + void preload (); ///< Build ID list from content file. /// Call functor (ref) for each reference. functor must return a bool. Returning @@ -267,11 +273,11 @@ namespace MWWorld private: /// Run through references and store IDs - void listRefs(const MWWorld::ESMStore &store, std::vector &esm); + void listRefs(); - void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); + void loadRefs(); - void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); + void loadRef (ESM::CellRef& ref, bool deleted); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. From 2301080c63dee1947ffe04bbb447077087da8dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:04:48 +0100 Subject: [PATCH 1599/1812] Load CellStore when an object is moved there --- apps/openmw/mwworld/cellstore.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c435b0478f..10315b126a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -184,6 +184,9 @@ namespace MWWorld void CellStore::moveFrom(const Ptr &object, CellStore *from) { + if (mState != State_Loaded) + load(); + mHasState = true; MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase()); if (found != mMovedToAnotherCell.end()) @@ -196,14 +199,7 @@ namespace MWWorld { mMovedHere.insert(std::make_pair(object.getBase(), from)); } - - if (mState == State_Loaded) - updateMergedRefs(); - else if (mState == State_Preloaded) - { - mIds.push_back(object.getCellRef().getRefId()); - std::sort(mIds.begin(), mIds.end()); - } + updateMergedRefs(); } MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) From 5e99a3eda6400aa4be945acef3473152375e600c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:13:04 +0100 Subject: [PATCH 1600/1812] Rename CellStore Functor to Visitor --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwworld/cellstore.cpp | 20 +++---- apps/openmw/mwworld/cellstore.hpp | 58 +++++++++---------- .../{cellfunctors.hpp => cellvisitors.hpp} | 6 +- apps/openmw/mwworld/scene.cpp | 28 ++++----- apps/openmw/mwworld/worldimp.cpp | 35 ++++++----- 6 files changed, 74 insertions(+), 75 deletions(-) rename apps/openmw/mwworld/{cellfunctors.hpp => cellvisitors.hpp} (78%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 03ce71f5c5..0113fed022 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata worldimp scene globals class action nullaction actionteleport - containerstore actiontalk actiontake manualref player cellfunctors failedaction + containerstore actiontalk actiontake manualref player cellvisitors failedaction cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 10315b126a..507e3fd7fe 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -241,9 +241,9 @@ namespace MWWorld return MWWorld::Ptr(object.getBase(), cellToMoveTo); } - struct MergeFunctor + struct MergeVisitor { - MergeFunctor(std::vector& mergeTo, const std::map& movedHere, + MergeVisitor(std::vector& mergeTo, const std::map& movedHere, const std::map& movedToAnotherCell) : mMergeTo(mergeTo) , mMovedHere(movedHere) @@ -275,9 +275,9 @@ namespace MWWorld void CellStore::updateMergedRefs() { mMergedRefs.clear(); - MergeFunctor functor(mMergedRefs, mMovedHere, mMovedToAnotherCell); - forEachInternal(functor); - functor.merge(); + MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell); + forEachInternal(visitor); + visitor.merge(); } CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector& readerList) @@ -313,7 +313,7 @@ namespace MWWorld return const_cast (this)->search (id).isEmpty(); } - struct SearchFunctor + struct SearchVisitor { MWWorld::Ptr mFound; std::string mIdToFind; @@ -332,12 +332,12 @@ namespace MWWorld { bool oldState = mHasState; - SearchFunctor searchFunctor; - searchFunctor.mIdToFind = id; - forEach(searchFunctor); + SearchVisitor searchVisitor; + searchVisitor.mIdToFind = id; + forEach(searchVisitor); mHasState = oldState; - return searchFunctor.mFound; + return searchVisitor.mFound; } Ptr CellStore::searchViaActorId (int id) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 80fcaf48aa..cedf2eeb0c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -125,45 +125,45 @@ namespace MWWorld } // helper function for forEachInternal - template - bool forEachImp (Functor& functor, List& list) + template + bool forEachImp (Visitor& visitor, List& list) { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { if (iter->mData.isDeletedByContentFile()) continue; - if (!functor (MWWorld::Ptr(&*iter, this))) + if (!visitor (MWWorld::Ptr(&*iter, this))) return false; } return true; } // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for. - template - bool forEachInternal (Functor& functor) + template + bool forEachInternal (Visitor& visitor) { return - forEachImp (functor, mActivators) && - forEachImp (functor, mPotions) && - forEachImp (functor, mAppas) && - forEachImp (functor, mArmors) && - forEachImp (functor, mBooks) && - forEachImp (functor, mClothes) && - forEachImp (functor, mContainers) && - forEachImp (functor, mDoors) && - forEachImp (functor, mIngreds) && - forEachImp (functor, mItemLists) && - forEachImp (functor, mLights) && - forEachImp (functor, mLockpicks) && - forEachImp (functor, mMiscItems) && - forEachImp (functor, mProbes) && - forEachImp (functor, mRepairs) && - forEachImp (functor, mStatics) && - forEachImp (functor, mWeapons) && - forEachImp (functor, mCreatures) && - forEachImp (functor, mNpcs) && - forEachImp (functor, mCreatureLists); + forEachImp (visitor, mActivators) && + forEachImp (visitor, mPotions) && + forEachImp (visitor, mAppas) && + forEachImp (visitor, mArmors) && + forEachImp (visitor, mBooks) && + forEachImp (visitor, mClothes) && + forEachImp (visitor, mContainers) && + forEachImp (visitor, mDoors) && + forEachImp (visitor, mIngreds) && + forEachImp (visitor, mItemLists) && + forEachImp (visitor, mLights) && + forEachImp (visitor, mLockpicks) && + forEachImp (visitor, mMiscItems) && + forEachImp (visitor, mProbes) && + forEachImp (visitor, mRepairs) && + forEachImp (visitor, mStatics) && + forEachImp (visitor, mWeapons) && + forEachImp (visitor, mCreatures) && + forEachImp (visitor, mNpcs) && + forEachImp (visitor, mCreatureLists); } public: @@ -222,12 +222,12 @@ namespace MWWorld void preload (); ///< Build ID list from content file. - /// Call functor (ref) for each reference. functor must return a bool. Returning + /// Call visitor (ref) for each reference. visitor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? - template - bool forEach (Functor& functor) + template + bool forEach (Visitor& visitor) { if (mState != State_Loaded) return false; @@ -239,7 +239,7 @@ namespace MWWorld if (mMergedRefs[i]->mData.isDeletedByContentFile()) continue; - if (!functor(MWWorld::Ptr(mMergedRefs[i], this))) + if (!visitor(MWWorld::Ptr(mMergedRefs[i], this))) return false; } return true; diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellvisitors.hpp similarity index 78% rename from apps/openmw/mwworld/cellfunctors.hpp rename to apps/openmw/mwworld/cellvisitors.hpp index c7fdc793cc..cfb07f7492 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellvisitors.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWWORLD_CELLFUNCTORS_H -#define GAME_MWWORLD_CELLFUNCTORS_H +#ifndef GAME_MWWORLD_CELLVISITORS_H +#define GAME_MWWORLD_CELLVISITORS_H #include #include @@ -9,7 +9,7 @@ namespace MWWorld { - struct ListAndResetObjects + struct ListAndResetObjectsVisitor { std::vector mObjects; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 896d5f8ebd..00cb8a810a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -22,7 +22,7 @@ #include "localscripts.hpp" #include "esmstore.hpp" #include "class.hpp" -#include "cellfunctors.hpp" +#include "cellvisitors.hpp" #include "cellstore.hpp" namespace @@ -78,7 +78,7 @@ namespace } } - struct InsertFunctor + struct InsertVisitor { MWWorld::CellStore& mCell; bool mRescale; @@ -86,13 +86,13 @@ namespace MWPhysics::PhysicsSystem& mPhysics; MWRender::RenderingManager& mRendering; - InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, + InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); bool operator() (const MWWorld::Ptr& ptr); }; - InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, + InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), @@ -100,7 +100,7 @@ namespace mRendering (rendering) {} - bool InsertFunctor::operator() (const MWWorld::Ptr& ptr) + bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) { if (mRescale) { @@ -129,7 +129,7 @@ namespace return true; } - struct AdjustPositionFunctor + struct AdjustPositionVisitor { bool operator() (const MWWorld::Ptr& ptr) { @@ -206,11 +206,11 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListAndResetObjects functor; + ListAndResetObjectsVisitor visitor; - (*iter)->forEach(functor); - for (std::vector::const_iterator iter2 (functor.mObjects.begin()); - iter2!=functor.mObjects.end(); ++iter2) + (*iter)->forEach(visitor); + for (std::vector::const_iterator iter2 (visitor.mObjects.begin()); + iter2!=visitor.mObjects.end(); ++iter2) { mPhysics->remove(*iter2); } @@ -561,12 +561,12 @@ namespace MWWorld void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { - InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); - cell.forEach (functor); + InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering); + cell.forEach (insertVisitor); // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order - AdjustPositionFunctor adjustPosFunctor; - cell.forEach (adjustPosFunctor); + AdjustPositionVisitor adjustPosVisitor; + cell.forEach (adjustPosVisitor); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bb2ca2aae2..3efce5c9e1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -54,7 +54,6 @@ #include "player.hpp" #include "manualref.hpp" #include "cellstore.hpp" -#include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" #include "actionteleport.hpp" @@ -690,12 +689,12 @@ namespace MWWorld return mWorldScene->searchPtrViaActorId (actorId); } - struct FindContainerFunctor + struct FindContainerVisitor { Ptr mContainedPtr; Ptr mResult; - FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} bool operator() (Ptr ptr) { @@ -721,11 +720,11 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - FindContainerFunctor functor(ptr); - //(*cellIt)->forEachContainer(functor); + FindContainerVisitor visitor(ptr); + //(*cellIt)->forEachContainer(visitor); - if (!functor.mResult.isEmpty()) - return functor.mResult; + if (!visitor.mResult.isEmpty()) + return visitor.mResult; } return Ptr(); @@ -2262,7 +2261,7 @@ namespace MWWorld */ } - struct ListObjectsFunctor + struct ListObjectsVisitor { std::vector mObjects; @@ -2279,10 +2278,10 @@ namespace MWWorld const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - ListObjectsFunctor functor; - (*cellIt)->forEach(functor); + ListObjectsVisitor visitor; + (*cellIt)->forEach(visitor); - for (std::vector::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it) + for (std::vector::iterator it = visitor.mObjects.begin(); it != visitor.mObjects.end(); ++it) if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId())) out.push_back(*it); } @@ -2886,9 +2885,9 @@ namespace MWWorld mWeatherManager->update(duration, paused); } - struct AddDetectedReference + struct AddDetectedReferenceVisitor { - AddDetectedReference(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) + AddDetectedReferenceVisitor(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) : mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type) { } @@ -2968,13 +2967,13 @@ namespace MWWorld dist = feetToGameUnits(dist); - AddDetectedReference functor (out, ptr, type, dist*dist); + AddDetectedReferenceVisitor visitor (out, ptr, type, dist*dist); const Scene::CellStoreCollection& active = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it) { MWWorld::CellStore* cellStore = *it; - cellStore->forEach(functor); + cellStore->forEach(visitor); } } @@ -3230,7 +3229,7 @@ namespace MWWorld interpreterContext.executeActivation(object, actor); } - struct ResetActorsFunctor + struct ResetActorsVisitor { bool operator() (Ptr ptr) { @@ -3252,8 +3251,8 @@ namespace MWWorld iter!=mWorldScene->getActiveCells().end(); ++iter) { CellStore* cellstore = *iter; - ResetActorsFunctor functor; - cellstore->forEach(functor); + ResetActorsVisitor visitor; + cellstore->forEach(visitor); } } From 138957c49aaa892e199c58371c7b3961b252945c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:43:52 +0100 Subject: [PATCH 1601/1812] Special case objects with no refnum --- apps/openmw/mwworld/cellstore.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 507e3fd7fe..edeb4f08db 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -213,6 +213,15 @@ namespace MWWorld // TODO: ensure that the object actually exists in the cell + // Objects with no refnum can't be handled correctly in the merging process that happens + // on a save/load, so do a simple copy & delete for these objects. + if (!object.getCellRef().getRefNum().hasContentFile()) + { + MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); + object.getRefData().setCount(0); + return copied; + } + MovedRefTracker::iterator found = mMovedHere.find(object.getBase()); if (found != mMovedHere.end()) { From 2219231230b31c2024300d11cbd48293794c678d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 18:46:49 +0100 Subject: [PATCH 1602/1812] Missing updateMergedRefs() --- apps/openmw/mwworld/cellstore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index edeb4f08db..47677064e8 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -770,6 +770,7 @@ namespace MWWorld throw std::runtime_error ("unknown type in cell reference section"); } } + updateMergedRefs(); } bool operator== (const CellStore& left, const CellStore& right) From 671561ea37dc8e3c172030ca150cbe1527a448a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 19:11:25 +0100 Subject: [PATCH 1603/1812] Write moved references to the save game file (not resolved on loading yet) --- apps/openmw/mwworld/cells.cpp | 1 - apps/openmw/mwworld/cellstore.cpp | 22 +++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 2 ++ components/esm/cellref.cpp | 6 +++--- components/esm/cellref.hpp | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 127e43fc07..b410e64887 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -119,7 +119,6 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result->second.getState()!=CellStore::State_Loaded) { - // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. result->second.load (); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 47677064e8..578e5ed558 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -636,7 +636,15 @@ namespace MWWorld writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); - // TODO: write moved references + for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it) + { + LiveCellRefBase* base = it->first; + ESM::RefNum refNum = base->mRef.getRefNum(); + ESM::CellId movedTo = it->second->getCell()->getCellId(); + + refNum.save(writer, true, "MVRF"); + movedTo.save(writer); + } } void CellStore::readReferences (ESM::ESMReader& reader, @@ -770,6 +778,18 @@ namespace MWWorld throw std::runtime_error ("unknown type in cell reference section"); } } + + while (reader.isNextSub("MVRF")) + { + reader.cacheSubName(); + ESM::RefNum refnum; + ESM::CellId movedTo; + refnum.load(reader, true, "MVRF"); + movedTo.load(reader); + + std::cout << "moved to " << movedTo.mWorldspace << " " << movedTo.mIndex.mX << " " << movedTo.mIndex.mY << std::endl; + } + updateMergedRefs(); } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cedf2eeb0c..892a5c06b3 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -12,6 +12,8 @@ #include "livecellref.hpp" #include "cellreflist.hpp" +#include + #include #include #include diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 76a82fe232..7acaed86d5 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -3,12 +3,12 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -void ESM::RefNum::load (ESMReader& esm, bool wide) +void ESM::RefNum::load (ESMReader& esm, bool wide, const std::string& tag) { if (wide) - esm.getHNT (*this, "FRMR", 8); + esm.getHNT (*this, tag.c_str(), 8); else - esm.getHNT (mIndex, "FRMR"); + esm.getHNT (mIndex, tag.c_str()); } void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index c371a4f015..3c646cc616 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -16,7 +16,7 @@ namespace ESM unsigned int mIndex; int mContentFile; - void load (ESMReader& esm, bool wide = false); + void load (ESMReader& esm, bool wide = false, const std::string& tag = "FRMR"); void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const; From 176a3c16f4d595c28b3b5f0fab8192bfa0bcdf33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 19:53:06 +0100 Subject: [PATCH 1604/1812] Resolve moved references loaded from a save game --- apps/openmw/mwworld/cells.cpp | 31 +++++++++++++++-- apps/openmw/mwworld/cellstore.cpp | 57 ++++++++++++++++++++++++++++--- apps/openmw/mwworld/cellstore.hpp | 13 +++++-- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b410e64887..1094479599 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -1,5 +1,7 @@ #include "cells.hpp" +#include + #include #include #include @@ -303,6 +305,29 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) } } +struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback +{ +public: + GetCellStoreCallback(MWWorld::Cells& cells) + : mCells(cells) + { + } + + MWWorld::Cells& mCells; + + virtual MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) + { + try + { + return mCells.getCell(cellId); + } + catch (...) + { + return NULL; + } + } +}; + bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { @@ -320,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, catch (...) { // silently drop cells that don't exist anymore + std::cerr << "Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)" << std::endl; reader.skipRecord(); return true; - /// \todo log } state.load (reader); @@ -334,7 +359,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, if (cellStore->getState()!=CellStore::State_Loaded) cellStore->load (); - cellStore->readReferences (reader, contentFileMap); + GetCellStoreCallback callback(*this); + + cellStore->readReferences (reader, contentFileMap, &callback); return true; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 578e5ed558..cf9c4d8306 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -613,6 +613,28 @@ namespace MWWorld mFogState->load(reader); } + struct SearchByRefNumVisitor + { + LiveCellRefBase* mFound; + ESM::RefNum mRefNumToFind; + + SearchByRefNumVisitor(const ESM::RefNum& toFind) + : mFound(NULL) + , mRefNumToFind(toFind) + { + } + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefNum() == mRefNumToFind) + { + mFound = ptr.getBase(); + return false; + } + return true; + } + }; + void CellStore::writeReferences (ESM::ESMWriter& writer) const { writeReferenceCollection (writer, mActivators); @@ -647,11 +669,8 @@ namespace MWWorld } } - void CellStore::readReferences (ESM::ESMReader& reader, - const std::map& contentFileMap) + void CellStore::readReferences (ESM::ESMReader& reader, const std::map& contentFileMap, GetCellStoreCallback* callback) { - // TODO: read moved references - mHasState = true; while (reader.isNextSub ("OBJE")) @@ -787,7 +806,35 @@ namespace MWWorld refnum.load(reader, true, "MVRF"); movedTo.load(reader); - std::cout << "moved to " << movedTo.mWorldspace << " " << movedTo.mIndex.mX << " " << movedTo.mIndex.mY << std::endl; + // Search for the reference. It might no longer exist if its content file was removed. + SearchByRefNumVisitor visitor(refnum); + forEachInternal(visitor); + + if (!visitor.mFound) + { + std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl; + continue; + } + + CellStore* otherCell = callback->getCellStore(movedTo); + + if (otherCell == NULL) + { + std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() + << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl; + // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. + // Restore original coordinates: + visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition()); + continue; + } + + if (otherCell == this) + { + std::cerr << "Found invalid moved ref, ignoring" << std::endl; + continue; + } + + moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell); } updateMergedRefs(); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 892a5c06b3..542d4700ef 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -12,8 +12,6 @@ #include "livecellref.hpp" #include "cellreflist.hpp" -#include - #include #include #include @@ -42,6 +40,7 @@ namespace ESM { struct CellState; struct FogState; + struct CellId; } namespace MWWorld @@ -263,7 +262,15 @@ namespace MWWorld void writeReferences (ESM::ESMWriter& writer) const; - void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); + struct GetCellStoreCallback + { + public: + ///@note must return NULL if the cell is not found + virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0; + }; + + /// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references) + void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap, GetCellStoreCallback* callback); void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. From 0af33b5abd71878d7c7e1b78e247375634fcf9ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:05:13 +0100 Subject: [PATCH 1605/1812] Throw exception if moveTo() is passed an object not part of *this --- apps/openmw/mwworld/cellstore.cpp | 56 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cf9c4d8306..4f28fcfdfe 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -144,6 +144,28 @@ namespace ref.load (state); collection.mList.push_back (ref); } + + struct SearchByRefNumVisitor + { + MWWorld::LiveCellRefBase* mFound; + ESM::RefNum mRefNumToFind; + + SearchByRefNumVisitor(const ESM::RefNum& toFind) + : mFound(NULL) + , mRefNumToFind(toFind) + { + } + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getCellRef().getRefNum() == mRefNumToFind) + { + mFound = ptr.getBase(); + return false; + } + return true; + } + }; } namespace MWWorld @@ -205,13 +227,18 @@ namespace MWWorld MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo) { if (cellToMoveTo == this) - throw std::runtime_error("object is already in this cell"); + throw std::runtime_error("moveTo: object is already in this cell"); // We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise. if (mState != State_Loaded) - throw std::runtime_error("can't move object from a non-loaded cell (how did you get this object anyway?)"); + throw std::runtime_error("moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)"); + + // Ensure that the object actually exists in the cell + SearchByRefNumVisitor searchVisitor(object.getCellRef().getRefNum()); + forEach(searchVisitor); + if (!searchVisitor.mFound) + throw std::runtime_error("moveTo: object is not in this cell"); - // TODO: ensure that the object actually exists in the cell // Objects with no refnum can't be handled correctly in the merging process that happens // on a save/load, so do a simple copy & delete for these objects. @@ -613,28 +640,6 @@ namespace MWWorld mFogState->load(reader); } - struct SearchByRefNumVisitor - { - LiveCellRefBase* mFound; - ESM::RefNum mRefNumToFind; - - SearchByRefNumVisitor(const ESM::RefNum& toFind) - : mFound(NULL) - , mRefNumToFind(toFind) - { - } - - bool operator()(const MWWorld::Ptr& ptr) - { - if (ptr.getCellRef().getRefNum() == mRefNumToFind) - { - mFound = ptr.getBase(); - return false; - } - return true; - } - }; - void CellStore::writeReferences (ESM::ESMWriter& writer) const { writeReferenceCollection (writer, mActivators); @@ -830,6 +835,7 @@ namespace MWWorld if (otherCell == this) { + // Should never happen unless someone's tampering with files. std::cerr << "Found invalid moved ref, ignoring" << std::endl; continue; } From a517f4f9bad647489c654429285aef2770d08b9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:19:07 +0100 Subject: [PATCH 1606/1812] Add CellStore::forEachType to help with porting over game logic to the new interfaces --- apps/openmw/mwworld/cellstore.hpp | 177 +++++++++++++++++++++--------- 1 file changed, 127 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 542d4700ef..ae8ac8ae58 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -116,15 +116,6 @@ namespace MWWorld /// Repopulate mMergedRefs. void updateMergedRefs(); - template - LiveCellRefBase* insertBase(CellRefList& list, const LiveCellRef* ref) - { - mHasState = true; - LiveCellRefBase* ret = &list.insert(*ref); - updateMergedRefs(); - return ret; - } - // helper function for forEachInternal template bool forEachImp (Visitor& visitor, List& list) @@ -167,6 +158,11 @@ namespace MWWorld forEachImp (visitor, mCreatureLists); } + /// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are + /// defined at the bottom of this file. + template + CellRefList& get(); + public: /// Moves object from this cell to the given cell. @@ -179,7 +175,14 @@ namespace MWWorld /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. template - LiveCellRefBase* insert(const LiveCellRef* ref); + LiveCellRefBase* insert(const LiveCellRef* ref) + { + mHasState = true; + CellRefList& list = get(); + LiveCellRefBase* ret = &list.insert(*ref); + updateMergedRefs(); + return ret; + } /// @param readerList The readers to use for loading of the cell on-demand. CellStore (const ESM::Cell *cell_, @@ -246,6 +249,41 @@ namespace MWWorld return true; } + /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning + /// false will abort the iteration. + /// \attention This function also lists deleted (count 0) objects! + /// \return Iteration completed? + template + bool forEachType(Visitor& visitor) + { + if (mState != State_Loaded) + return false; + + mHasState = true; + + CellRefList& list = get(); + + for (typename CellRefList::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it) + { + LiveCellRefBase* base = &*it; + if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end()) + continue; + if (base->mData.isDeletedByContentFile()) + continue; + if (!visitor(MWWorld::Ptr(base, this))) + return false; + } + + for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) + { + LiveCellRefBase* base = it->first; + if (dynamic_cast*>(base)) + if (!visitor(MWWorld::Ptr(base, this))) + return false; + } + return true; + } + /// \todo add const version of forEach bool isExterior() const; @@ -295,104 +333,143 @@ namespace MWWorld }; template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mActivators, ref); + mHasState = true; + return mActivators; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mPotions, ref); + mHasState = true; + return mPotions; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mAppas, ref); + mHasState = true; + return mAppas; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mArmors, ref); + mHasState = true; + return mArmors; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mBooks, ref); + mHasState = true; + return mBooks; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mClothes, ref); + mHasState = true; + return mClothes; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mContainers, ref); + mHasState = true; + return mContainers; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mCreatures, ref); + mHasState = true; + return mCreatures; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mDoors, ref); + mHasState = true; + return mDoors; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mIngreds, ref); + mHasState = true; + return mIngreds; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mCreatureLists, ref); + mHasState = true; + return mCreatureLists; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mItemLists, ref); + mHasState = true; + return mItemLists; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mLights, ref); + mHasState = true; + return mLights; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mLockpicks, ref); + mHasState = true; + return mLockpicks; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mMiscItems, ref); + mHasState = true; + return mMiscItems; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mNpcs, ref); + mHasState = true; + return mNpcs; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mProbes, ref); + mHasState = true; + return mProbes; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mRepairs, ref); + mHasState = true; + return mRepairs; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mStatics, ref); + mHasState = true; + return mStatics; } + template<> - inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) + inline CellRefList& CellStore::get() { - return insertBase(mWeapons, ref); + mHasState = true; + return mWeapons; } bool operator== (const CellStore& left, const CellStore& right); From 9ea475d00cd85f179e4eec10dd788a78e8435bd5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:30:52 +0100 Subject: [PATCH 1607/1812] Port LocalScripts::addCell to new CellStore interfaces --- apps/openmw/mwworld/localscripts.cpp | 89 +++++++++++++--------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index aa5abc076f..030a418915 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -11,46 +11,54 @@ namespace { - template - void listCellScripts (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) + + struct AddScriptsVisitor { - for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.mList.begin()); - iter!=cellRefList.mList.end(); ++iter) + AddScriptsVisitor(MWWorld::LocalScripts& scripts) + : mScripts(scripts) { - if (!iter->mBase->mScript.empty() && !iter->mData.isDeleted()) - { - localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); - } } - } + MWWorld::LocalScripts& mScripts; - // Adds scripts for items in containers (containers/npcs/creatures) - template - void listCellScriptsCont (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) - { - for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.mList.begin()); - iter!=cellRefList.mList.end(); ++iter) + bool operator()(const MWWorld::Ptr& ptr) { + if (ptr.getRefData().isDeleted()) + return true; - MWWorld::Ptr containerPtr (&*iter, cell); + std::string script = ptr.getClass().getScript(ptr); + if (!script.empty()) + mScripts.add(script, ptr); + + return true; + } + }; + + struct AddContainerItemScriptsVisitor + { + AddContainerItemScriptsVisitor(MWWorld::LocalScripts& scripts) + : mScripts(scripts) + { + } + MWWorld::LocalScripts& mScripts; + + bool operator()(const MWWorld::Ptr& containerPtr) + { MWWorld::ContainerStore& container = containerPtr.getClass().getContainerStore(containerPtr); - for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) { - std::string script = it3->getClass().getScript(*it3); + std::string script = it->getClass().getScript(*it); if(script != "") { - MWWorld::Ptr item = *it3; - item.mCell = cell; - localScripts.add (script, item); + MWWorld::Ptr item = *it; + item.mCell = containerPtr.getCell(); + mScripts.add (script, item); } } + return true; } - } + }; + } MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} @@ -116,28 +124,13 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) void MWWorld::LocalScripts::addCell (CellStore *cell) { - /* - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScriptsCont (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - listCellScripts (*this, cell->get(), cell); - */ + AddScriptsVisitor addScriptsVisitor(*this); + cell->forEach(addScriptsVisitor); + + AddContainerItemScriptsVisitor addContainerItemScriptsVisitor(*this); + cell->forEachType(addContainerItemScriptsVisitor); + cell->forEachType(addContainerItemScriptsVisitor); + cell->forEachType(addContainerItemScriptsVisitor); } void MWWorld::LocalScripts::clear() From abcf91be5b0312a60dfbaa3b4c31f006d4b1fec3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 20:43:50 +0100 Subject: [PATCH 1608/1812] Port over more game logic to the visitor pattern --- apps/openmw/mwworld/worldimp.cpp | 84 ++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3efce5c9e1..cfb7b5c822 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1691,31 +1691,32 @@ namespace MWWorld osg::Vec2f World::getNorthVector (CellStore* cell) { - /* - MWWorld::CellRefList& statics = cell->get(); - MWWorld::LiveCellRef* ref = statics.find("northmarker"); - if (!ref) + MWWorld::Ptr northmarker = cell->search("northmarker"); + + if (northmarker.isEmpty()) return osg::Vec2f(0, 1); - osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); + osg::Quat orient (-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0,0,1)); osg::Vec3f dir = orient * osg::Vec3f(0,1,0); osg::Vec2f d (dir.x(), dir.y()); return d; - */ - return osg::Vec2f(); } - void World::getDoorMarkers (CellStore* cell, std::vector& out) + struct GetDoorMarkerVisitor { - /* - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + GetDoorMarkerVisitor(std::vector& out) + : mOut(out) { - MWWorld::LiveCellRef& ref = *it; + } - if (!ref.mData.isEnabled()) - continue; + std::vector& mOut; + + bool operator()(const MWWorld::Ptr& ptr) + { + MWWorld::LiveCellRef& ref = *static_cast* >(ptr.getBase()); + + if (!ref.mData.isEnabled() || ref.mData.isDeleted()) + return true; if (ref.mRef.getTeleport()) { @@ -1731,7 +1732,7 @@ namespace MWWorld else { cellid.mPaged = true; - positionToIndex( + MWBase::Environment::get().getWorld()->positionToIndex( ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1], cellid.mIndex.mX, @@ -1743,10 +1744,16 @@ namespace MWWorld newMarker.x = pos.pos[0]; newMarker.y = pos.pos[1]; - out.push_back(newMarker); + mOut.push_back(newMarker); } + return true; } - */ + }; + + void World::getDoorMarkers (CellStore* cell, std::vector& out) + { + GetDoorMarkerVisitor visitor(out); + cell->forEachType(visitor); } void World::setWaterHeight(const float height) @@ -2241,24 +2248,37 @@ namespace MWWorld return osg::Vec3f(0,1,0); } - void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + struct GetContainersOwnedByVisitor + { + GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector& out) + : mOwner(owner) + , mOut(out) + { + } + + MWWorld::Ptr mOwner; + std::vector& mOut; + + bool operator()(const MWWorld::Ptr& ptr) + { + if (ptr.getRefData().isDeleted()) + return true; + + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId())) + mOut.push_back(ptr); + + return true; + } + }; + + void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector& out) { - /* const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { - MWWorld::CellRefList& containers = (*cellIt)->get(); - CellRefList::List& refList = containers.mList; - for (CellRefList::List::iterator container = refList.begin(); container != refList.end(); ++container) - { - MWWorld::Ptr ptr (&*container, *cellIt); - if (ptr.getRefData().isDeleted()) - continue; - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId())) - out.push_back(ptr); - } + GetContainersOwnedByVisitor visitor (owner, out); + (*cellIt)->forEachType(visitor); } - */ } struct ListObjectsVisitor @@ -2776,11 +2796,11 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - /* if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } + /* // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. From 51b892195b329b2e7a1ce5604f904bf53fa24c0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 21:58:25 +0100 Subject: [PATCH 1609/1812] Restore getReadOnlyDoors() --- apps/openmw/mwworld/cellstore.hpp | 12 ++++++++++++ apps/openmw/mwworld/worldimp.cpp | 19 ++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ae8ac8ae58..b08349293f 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -286,6 +286,18 @@ namespace MWWorld /// \todo add const version of forEach + + // NOTE: does not account for moved references + // Should be phased out when we have const version of forEach + inline const CellRefList& getReadOnlyDoors() const + { + return mDoors; + } + inline const CellRefList& getReadOnlyStatics() const + { + return mStatics; + } + bool isExterior() const; Ptr searchInContainer (const std::string& id); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cfb7b5c822..c64d90811b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2341,8 +2341,6 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { - return false; - /* typedef MWWorld::CellRefList::List DoorList; typedef MWWorld::CellRefList::List StaticList; @@ -2354,7 +2352,8 @@ namespace MWWorld if (0 == cellStore) { return false; } - const DoorList &doors = cellStore->get().mList; + + const DoorList &doors = cellStore->getReadOnlyDoors().mList; for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { if (!it->mRef.getTeleport()) { continue; @@ -2376,7 +2375,7 @@ namespace MWWorld if (0 != source) { // Find door leading to our current teleport door // and use it destination to position inside cell. - const DoorList &doors = source->get().mList; + const DoorList &doors = source->getReadOnlyDoors().mList; for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) { if (it->mRef.getTeleport() && Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell())) @@ -2390,12 +2389,11 @@ namespace MWWorld } } // Fall back to the first static location. - const StaticList &statics = cellStore->get().mList; + const StaticList &statics = cellStore->getReadOnlyStatics().mList; if ( statics.begin() != statics.end() ) { pos = statics.begin()->mRef.getPosition(); return true; } - */ return false; } @@ -2743,8 +2741,6 @@ namespace MWWorld bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, osg::Vec3f& result) { - return false; - /* if (cell->isExterior()) return false; @@ -2791,7 +2787,6 @@ namespace MWWorld // No luck :( return false; - */ } MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) @@ -2800,7 +2795,6 @@ namespace MWWorld return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); } - /* // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. @@ -2848,7 +2842,6 @@ namespace MWWorld } } } - */ return MWWorld::Ptr(); } @@ -2916,7 +2909,7 @@ namespace MWWorld Ptr mDetector; float mSquaredDist; World::DetectionType mType; - bool operator() (MWWorld::Ptr ptr) + bool operator() (const MWWorld::Ptr& ptr) { if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist) return true; @@ -2947,7 +2940,7 @@ namespace MWWorld return true; } - bool needToAdd (MWWorld::Ptr ptr, MWWorld::Ptr detector) + bool needToAdd (const MWWorld::Ptr& ptr, const MWWorld::Ptr& detector) { if (mType == World::Detect_Creature) { From 4b0ecaa0a0afdc35b33d8b789130443be580433a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 22:10:01 +0100 Subject: [PATCH 1610/1812] Fix physics bug --- apps/openmw/mwworld/cellstore.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4f28fcfdfe..68ea2de000 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -246,6 +246,7 @@ namespace MWWorld { MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); object.getRefData().setCount(0); + object.getRefData().setBaseNode(NULL); return copied; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c64d90811b..930fddd3e8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1171,7 +1171,6 @@ namespace MWWorld newPtr = currCell->moveTo(ptr, newCell); mRendering->updatePtr(ptr, newPtr); - ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr); mPhysics->updatePtr(ptr, newPtr); From 45a609bc54682f5afa0a897a1f073f84caf64fac Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 22:37:04 +0100 Subject: [PATCH 1611/1812] Improve PositionCell warning message --- apps/openmw/mwscript/transformationextensions.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 592168687a..61fafc40fe 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -300,14 +300,16 @@ namespace MWScript } catch(std::exception&) { + // cell not found, move to exterior instead (vanilla PositionCell compatibility) const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); int cx,cy; MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { - runtime.getContext().report ("unknown cell (" + cellID + ")"); - std::cerr << "unknown cell (" << cellID << ")\n"; + std::string error = "PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead"; + runtime.getContext().report (error); + std::cerr << error << std::endl; } } if(store) From 4e678ce6b30328ab343a91d41e59a775672ac3fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:32:20 +0100 Subject: [PATCH 1612/1812] Handle mCellId in AiEscort --- apps/openmw/mwmechanics/aiescort.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index f75fc22ad1..484eab6fe3 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -1,12 +1,14 @@ #include "aiescort.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -73,6 +75,9 @@ namespace MWMechanics return true; } + if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) + return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door + actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); From 965bea45c00d15aabc27982ff7179055b8ca5a06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:32:49 +0100 Subject: [PATCH 1613/1812] AiEscort makes the actor side with target in fights (Bug #2697) Also will follow the player through teleport doors. --- apps/openmw/mwbase/mechanicsmanager.hpp | 6 +-- apps/openmw/mwmechanics/actors.cpp | 45 ++++++++----------- apps/openmw/mwmechanics/actors.hpp | 6 +-- apps/openmw/mwmechanics/aiescort.cpp | 5 +++ apps/openmw/mwmechanics/aiescort.hpp | 3 ++ apps/openmw/mwmechanics/aifollow.hpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 10 +++++ apps/openmw/mwmechanics/aipackage.hpp | 6 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 ++-- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 2 +- 11 files changed, 56 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 63ad1d32fc..7cfc0861c7 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -184,9 +184,9 @@ namespace MWBase virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; - ///return the list of actors which are following the given actor - /**ie AiFollow is active and the target is the actor**/ - virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; + ///Returns the list of actors which are siding with the given actor in fights + /**ie AiFollow or AiEscort is active and the target is the actor **/ + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0; ///Returns a list of actors who are fighting the given actor within the fAlarmDistance diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2d794b3e00..eb837613b2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -303,7 +303,7 @@ namespace MWMechanics if (againstPlayer) { // followers with high fight should not engage in combat with the player (e.g. bm_bear_black_summon) - const std::list& followers = getActorsFollowing(actor2); + const std::list& followers = getActorsSidingWith(actor2); if (std::find(followers.begin(), followers.end(), actor1) != followers.end()) return; @@ -322,7 +322,7 @@ namespace MWMechanics } // start combat if target actor is in combat with one of our followers - const std::list& followers = getActorsFollowing(actor1); + const std::list& followers = getActorsSidingWith(actor1); const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2); for (std::list::const_iterator it = followers.begin(); it != followers.end(); ++it) { @@ -336,20 +336,21 @@ namespace MWMechanics // start combat if target actor is in combat with someone we are following for (std::list::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ++it) { - if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) - { - MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); - if (followTarget.isEmpty()) - continue; + if (!(*it)->sideWithTarget()) + continue; - if (creatureStats.getAiSequence().isInCombat(followTarget)) - continue; + MWWorld::Ptr followTarget = (*it)->getTarget(); - // need to check both ways since player doesn't use AI packages - if (creatureStats2.getAiSequence().isInCombat(followTarget) - || followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2)) - aggressive = true; - } + if (followTarget.isEmpty()) + continue; + + if (creatureStats.getAiSequence().isInCombat(followTarget)) + continue; + + // need to check both ways since player doesn't use AI packages + if (creatureStats2.getAiSequence().isInCombat(followTarget) + || followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2)) + aggressive = true; } if(aggressive) @@ -1290,7 +1291,7 @@ namespace MWMechanics } } - std::list Actors::getActorsFollowing(const MWWorld::Ptr& actor) + std::list Actors::getActorsSidingWith(const MWWorld::Ptr& actor) { std::list list; for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) @@ -1300,19 +1301,11 @@ namespace MWMechanics if (stats.isDead()) continue; - // An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package + // An actor counts as following if AiFollow or AiEscort is the current AiPackage, or there are only Combat packages before the AiFollow/AiEscort package for (std::list::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) { - if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) - { - MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); - if (followTarget.isEmpty()) - continue; - if (followTarget == actor) - list.push_back(iter->first); - else - break; - } + if ((*it)->sideWithTarget() && (*it)->getTarget() == actor) + list.push_back(iter->first); else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) break; } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index a16b808846..494216ba88 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -111,9 +111,9 @@ namespace MWMechanics void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); - ///Returns the list of actors which are following the given actor - /**ie AiFollow is active and the target is the actor **/ - std::list getActorsFollowing(const MWWorld::Ptr& actor); + ///Returns the list of actors which are siding with the given actor in fights + /**ie AiFollow or AiEscort is active and the target is the actor **/ + std::list getActorsSidingWith(const MWWorld::Ptr& actor); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 484eab6fe3..fffab8d77d 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -119,6 +119,11 @@ namespace MWMechanics return TypeIdEscort; } + MWWorld::Ptr AiEscort::getTarget() + { + return MWBase::Environment::get().getWorld()->getPtr(mActorId, false); + } + void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr escort(new ESM::AiSequence::AiEscort()); diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 9f6335b933..cdb0f79360 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -37,6 +37,9 @@ namespace MWMechanics virtual int getTypeId() const; + MWWorld::Ptr getTarget(); + virtual bool sideWithTarget() const { return true; } + void writeState(ESM::AiSequence::AiSequence &sequence) const; private: diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 8555f9bc4d..97140a63a2 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -32,6 +32,7 @@ namespace MWMechanics AiFollow(const ESM::AiSequence::AiFollow* follow); MWWorld::Ptr getTarget(); + virtual bool sideWithTarget() const { return true; } virtual AiFollow *clone() const; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index bedff8bcdc..fef10b7307 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -20,6 +20,16 @@ MWMechanics::AiPackage::~AiPackage() {} +MWWorld::Ptr MWMechanics::AiPackage::getTarget() +{ + return MWWorld::Ptr(); +} + +bool MWMechanics::AiPackage::sideWithTarget() const +{ + return false; +} + MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 3f227a49a2..f9460e2645 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,12 @@ namespace MWMechanics /// Simulates the passing of time virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + /// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr) + virtual MWWorld::Ptr getTarget(); + + /// Return true if having this AiPackage makes the actor side with the target in fights (default false) + virtual bool sideWithTarget() const; + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); protected: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e392b309b9..68bea02b0c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1053,7 +1053,7 @@ namespace MWMechanics void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) @@ -1310,7 +1310,7 @@ namespace MWMechanics if (ptr == getPlayer()) return false; - std::list followers = getActorsFollowing(attacker); + std::list followers = getActorsSidingWith(attacker); MWMechanics::CreatureStats& targetStats = ptr.getClass().getCreatureStats(ptr); if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) { @@ -1487,9 +1487,9 @@ namespace MWMechanics mActors.getObjectsInRange(position, radius, objects); } - std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) + std::list MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor) { - return mActors.getActorsFollowing(actor); + return mActors.getActorsSidingWith(actor); } std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f0d1cc2a02..279adeeede 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -150,7 +150,7 @@ namespace MWMechanics virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); - virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); virtual std::list getActorsFighting(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 031f07258c..bcb1fc6d42 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -13,7 +13,7 @@ namespace void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) From 65b5cbe3f7f56b682ecfc731b04f71d6b6676b38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 6 Dec 2015 23:40:03 +0100 Subject: [PATCH 1614/1812] AiEscortCell complains if no cell was given or cell does not exist --- apps/openmw/mwscript/aiextensions.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 22b6ac8d10..db60d14d18 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -1,5 +1,8 @@ #include "aiextensions.hpp" +#include +#include + #include #include @@ -8,6 +11,7 @@ #include #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/aiactivate.hpp" @@ -18,13 +22,11 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" -#include - -#include "../mwbase/mechanicsmanager.hpp" namespace MWScript { @@ -144,6 +146,11 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; igetStore().get().find(cellID); + MWMechanics::AiEscort escortPackage(actorID, cellID, static_cast(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); From 1f543b4d79744886aa9a03ad7fcff6d97dc5f70c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 00:25:03 +0100 Subject: [PATCH 1615/1812] Apply the AiTravel maxRange to AiEscort as well (Fixes #2697) --- apps/openmw/mwmechanics/aiescort.cpp | 3 +++ apps/openmw/mwmechanics/aipackage.hpp | 9 +++++++++ apps/openmw/mwmechanics/aitravel.cpp | 12 ------------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index fffab8d77d..baf4f1be77 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -75,6 +75,9 @@ namespace MWMechanics return true; } + if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) + return false; + if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index f9460e2645..4b760e4c95 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -94,10 +94,19 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; + bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) const + { + // Maximum travel distance for vanilla compatibility. + // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. + // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. + return (pos1 - pos2).length2() <= 7168*7168; + } + private: bool isNearInactiveCell(const ESM::Position& actorPos); }; + } #endif diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 1585a3007f..c29861f4ee 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,18 +13,6 @@ #include "movement.hpp" #include "creaturestats.hpp" -namespace -{ - -bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) -{ - // Maximum travel distance for vanilla compatibility. - // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. - // We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. - return (pos1 - pos2).length2() <= 7168*7168; -} - -} namespace MWMechanics { From f9dd549bffaf16bd4ffb6c6504625e0479196c27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:47:40 +0100 Subject: [PATCH 1616/1812] Restore FindContainerVisitor --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 930fddd3e8..36b3be01d8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -721,7 +721,11 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) { FindContainerVisitor visitor(ptr); - //(*cellIt)->forEachContainer(visitor); + (*cellIt)->forEachType(visitor); + if (visitor.mResult.isEmpty()) + (*cellIt)->forEachType(visitor); + if (visitor.mResult.isEmpty()) + (*cellIt)->forEachType(visitor); if (!visitor.mResult.isEmpty()) return visitor.mResult; From 1875aa4a18704ee6aeb9feb84aedb64baa74165c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:51:03 +0100 Subject: [PATCH 1617/1812] Restore getNearbyDoor --- apps/openmw/mwmechanics/obstacle.cpp | 13 ++++++------- apps/openmw/mwworld/refdata.cpp | 2 +- apps/openmw/mwworld/refdata.hpp | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index a2cbae2a0f..5815d8cbe3 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -44,10 +44,9 @@ namespace MWMechanics return MWWorld::Ptr(); // check interior cells only // Check all the doors in this cell - /* - MWWorld::CellRefList& doors = cell->get(); - MWWorld::CellRefList::List& refList = doors.mList; - MWWorld::CellRefList::List::iterator it = refList.begin(); + const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); + const MWWorld::CellRefList::List& refList = doors.mList; + MWWorld::CellRefList::List::const_iterator it = refList.begin(); osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); /// TODO: How to check whether the actor is facing a door? Below code is for @@ -60,14 +59,14 @@ namespace MWMechanics /// opposite of the code in World::activateDoor() ::confused:: for (; it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) { - return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching + // FIXME cast + return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching } } - */ return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 8acba43df7..997b3fc94b 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -182,7 +182,7 @@ namespace MWWorld mPosition = pos; } - const ESM::Position& RefData::getPosition() + const ESM::Position& RefData::getPosition() const { return mPosition; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 6713334d70..19c31a14b5 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -103,7 +103,7 @@ namespace MWWorld void disable(); void setPosition (const ESM::Position& pos); - const ESM::Position& getPosition(); + const ESM::Position& getPosition() const; void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \a data is From 621347b20fb7a8d778b3219dd3cd23a2232cf1a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 03:55:26 +0100 Subject: [PATCH 1618/1812] Remove moved ref handling from listRefs() Not needed since we now load cells when a reference is moved there. --- apps/openmw/mwworld/cellstore.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 68ea2de000..b5db42b005 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -474,8 +474,6 @@ namespace MWWorld continue; } - // We don't need to check mMovedToAnotherCell because listRefs isn't used for loaded cells. - mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID)); } } @@ -488,12 +486,6 @@ namespace MWWorld mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } - // List runtime moved references - for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it) - { - mIds.push_back(Misc::StringUtils::lowerCase(it->first->mRef.getRefId())); - } - std::sort (mIds.begin(), mIds.end()); } From 5981e1cbb3c18641cc09e4fc6da5f667c897770f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 14:41:33 +0100 Subject: [PATCH 1619/1812] Don't create the werewolf overlay if its texture is not available Avoiding a warning in the log when Bloodmoon is not installed --- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 114b8223d0..9d99c490b8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -324,7 +324,9 @@ namespace MWGui trackWindow(mCompanionWindow, "companion"); mJailScreen = new JailScreen(); - mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); + std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; + if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) + mWerewolfFader = new ScreenFader(werewolfFaderTex); mBlindnessFader = new ScreenFader("black"); std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available @@ -984,7 +986,8 @@ namespace MWGui mCompanionWindow->onFrame(); mJailScreen->onFrame(frameDuration); - mWerewolfFader->update(frameDuration); + if (mWerewolfFader) + mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); mHitFader->update(frameDuration); mScreenFader->update(frameDuration); @@ -1878,7 +1881,8 @@ namespace MWGui if (!mWerewolfOverlayEnabled) return; - mWerewolfFader->notifyAlphaChanged(set ? 1.0f : 0.0f); + if (mWerewolfFader) + mWerewolfFader->notifyAlphaChanged(set ? 1.0f : 0.0f); } void WindowManager::onClipboardChanged(const std::string &_type, const std::string &_data) From 9d4af598605473c69167b5bfd18ae2b6561e0bb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 15:32:00 +0100 Subject: [PATCH 1620/1812] Don't attempt to create quest log buttons if textures are unavailable (Fixes #3063) --- apps/openmw/mwgui/journalwindow.cpp | 38 ++++++++++++++++++-------- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++- components/resource/texturemanager.hpp | 1 + components/widgets/imagebutton.cpp | 19 +++++++++++-- components/widgets/imagebutton.hpp | 5 +++- files/mygui/openmw_journal.layout | 16 +++-------- 7 files changed, 56 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index b6f72a04cb..9af87c7ae3 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -96,7 +96,7 @@ namespace return getWidget (name); } - JournalWindowImpl (MWGui::JournalViewModel::Ptr Model) + JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) : WindowBase("openmw_journal.layout"), JournalBooks (Model) { mMainWidget->setVisible(false); @@ -142,17 +142,17 @@ namespace getPage (RightTopicIndex)->adviseLinkClicked (callback); } - adjustButton(OptionsBTN, true); adjustButton(PrevPageBTN); adjustButton(NextPageBTN); adjustButton(CloseBTN); adjustButton(CancelBTN); - adjustButton(ShowAllBTN, true); - adjustButton(ShowActiveBTN, true); adjustButton(JournalBTN); Gui::ImageButton* optionsButton = getWidget(OptionsBTN); - if (optionsButton->getWidth() == 0) + Gui::ImageButton* showActiveButton = getWidget(ShowActiveBTN); + Gui::ImageButton* showAllButton = getWidget(ShowAllBTN); + Gui::ImageButton* questsButton = getWidget(QuestsBTN); + if (!questList) { // If tribunal is not installed (-> no options button), we still want the Topics button available, // so place it where the options button would have been @@ -162,6 +162,23 @@ namespace topicsButton->setPosition(optionsButton->getPosition()); topicsButton->eventMouseButtonClick.clear(); topicsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &JournalWindowImpl::notifyOptions); + + optionsButton->setVisible(false); + showActiveButton->setVisible(false); + showAllButton->setVisible(false); + questsButton->setVisible(false); + } + else + { + optionsButton->setImage("textures/tx_menubook_options.dds"); + showActiveButton->setImage("textures/tx_menubook_quests_active.dds"); + showAllButton->setImage("textures/tx_menubook_quests_all.dds"); + questsButton->setImage("textures/tx_menubook_quests.dds"); + + adjustButton(ShowAllBTN); + adjustButton(ShowActiveBTN); + adjustButton(OptionsBTN); + adjustButton(QuestsBTN); } Gui::ImageButton* nextButton = getWidget(NextPageBTN); @@ -173,7 +190,6 @@ namespace } adjustButton(TopicsBTN); - adjustButton(QuestsBTN, true); int width = getWidget(TopicsBTN)->getSize().width + getWidget(QuestsBTN)->getSize().width; int topicsWidth = getWidget(TopicsBTN)->getSize().width; int pageWidth = getWidget(RightBookPage)->getSize().width; @@ -186,12 +202,12 @@ namespace mOptionsMode = false; } - void adjustButton (char const * name, bool optional = false) + void adjustButton (char const * name) { Gui::ImageButton* button = getWidget(name); - MyGUI::IntSize diff = button->getSize() - button->getRequestedSize(!optional); - button->setSize(button->getRequestedSize(!optional)); + MyGUI::IntSize diff = button->getSize() - button->getRequestedSize(); + button->setSize(button->getRequestedSize()); if (button->getAlign().isRight()) button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); @@ -551,7 +567,7 @@ namespace } // glue the implementation to the interface -MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model) +MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) { - return new JournalWindowImpl (Model); + return new JournalWindowImpl (Model, questList); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 5d2a5318ac..740284e203 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -12,7 +12,7 @@ namespace MWGui struct JournalWindow { /// construct a new instance of the one JournalWindow implementation - static JournalWindow * create (boost::shared_ptr Model); + static JournalWindow * create (boost::shared_ptr Model, bool questList); /// destroy this instance of the JournalWindow implementation virtual ~JournalWindow () {}; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9d99c490b8..ccbae3ef37 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -288,7 +288,9 @@ namespace MWGui trackWindow(mStatsWindow, "stats"); mConsole = new Console(w,h, mConsoleOnlyScripts); trackWindow(mConsole, "console"); - mJournal = JournalWindow::create(JournalViewModel::create ()); + + bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); + mJournal = JournalWindow::create(JournalViewModel::create (), questList); mMessageBoxManager = new MessageBoxManager( MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 1a7d41a7b1..0f40d7dfec 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -31,6 +31,7 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); /// Create or retrieve a Texture2D using the specified image filename, and wrap parameters. + /// Returns the dummy texture if the given texture is not found. osg::ref_ptr getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); /// Create or retrieve an Image diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 1cd8829751..8e3f8ed690 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -42,18 +42,31 @@ namespace Gui ImageBox::onMouseButtonPressed(_left, _top, _id); } - MyGUI::IntSize ImageButton::getRequestedSize(bool logError) + MyGUI::IntSize ImageButton::getRequestedSize() { MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture(mImageNormal); if (!texture) { - if (logError) - std::cerr << "ImageButton: can't find " << mImageNormal << std::endl; + std::cerr << "ImageButton: can't find " << mImageNormal << std::endl; return MyGUI::IntSize(0,0); } return MyGUI::IntSize (texture->getWidth(), texture->getHeight()); } + void ImageButton::setImage(const std::string &image) + { + size_t extpos = image.find_last_of("."); + std::string imageNoExt = image.substr(0, extpos); + + std::string ext = image.substr(extpos); + + mImageNormal = imageNoExt + "_idle" + ext; + mImageHighlighted = imageNoExt + "_over" + ext; + mImagePushed = imageNoExt + "_pressed" + ext; + + setImageTexture(mImageNormal); + } + void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index 10150c6b1e..a539f15c97 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -14,7 +14,10 @@ namespace Gui MYGUI_RTTI_DERIVED(ImageButton) public: - MyGUI::IntSize getRequestedSize(bool logError = true); + MyGUI::IntSize getRequestedSize(); + + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) + void setImage(const std::string& image); protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 9c40bd5623..9b530b3796 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -26,9 +26,7 @@ - - - + @@ -66,15 +64,11 @@ - - - + - - - + @@ -90,9 +84,7 @@ - - - + From 136a425cecec7925415bcdfb8981e2392c71c465 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:11:47 +0100 Subject: [PATCH 1621/1812] Use the Werewolf field of view override (Fixes #3064) Need to re-run the settings importer for the feature to work. --- apps/mwiniimporter/importer.cpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 26 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++++ apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 251889e281..7d1fd56a53 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -638,6 +638,9 @@ MwIniImporter::MwIniImporter() "Blood:Texture Name 1", "Blood:Texture Name 2", + // werewolf (Bloodmoon) + "General:Werewolf FOV", + 0 }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f4e7ca6840..e8da27dce6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -136,6 +136,8 @@ namespace MWRender , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) + , mFieldOfViewOverride(0.f) + , mFieldOfViewOverridden(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); @@ -769,7 +771,10 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); - mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); + float fov = mFieldOfView; + if (mFieldOfViewOverridden) + fov = mFieldOfViewOverride; + mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() @@ -912,4 +917,23 @@ namespace MWRender mCamera->setCameraDistance(-factor/120.f*10, true, true); } + void RenderingManager::overrideFieldOfView(float val) + { + if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) + { + mFieldOfViewOverridden = true; + mFieldOfViewOverride = val; + updateProjectionMatrix(); + } + } + + void RenderingManager::resetFieldOfView() + { + if (mFieldOfViewOverridden == true) + { + mFieldOfViewOverridden = false; + updateProjectionMatrix(); + } + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 936f7cb994..d510f52b56 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -170,6 +170,11 @@ namespace MWRender void togglePlayerLooking(bool enable); void changeVanityModeScale(float factor); + /// temporarily override the field of view with given value. + void overrideFieldOfView(float val); + /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. + void resetFieldOfView(); + private: void updateProjectionMatrix(); void updateTextureFiltering(); @@ -208,6 +213,8 @@ namespace MWRender float mNearClip; float mViewDistance; + float mFieldOfViewOverride; + bool mFieldOfViewOverridden; float mFieldOfView; void operator = (const RenderingManager&); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0cb2e980da..2436225b40 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1565,8 +1565,20 @@ namespace MWWorld mPlayer->setLastKnownExteriorPosition(pos.asVec3()); } - if (player.getClass().getNpcStats(player).isWerewolf()) - MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); + bool isWerewolf = player.getClass().getNpcStats(player).isWerewolf(); + bool isFirstPerson = mRendering->getCamera()->isFirstPerson(); + if (isWerewolf && isFirstPerson) + { + float werewolfFov = mFallback.getFallbackFloat("General_Werewolf_FOV"); + if (werewolfFov != 0) + mRendering->overrideFieldOfView(werewolfFov); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(true); + } + else + { + mRendering->resetFieldOfView(); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(false); + } // Sink the camera while sneaking bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); From 9621b66b786a546dd7d0f148904a6c789467f6c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:23:06 +0100 Subject: [PATCH 1622/1812] Move field of view setting to Camera section --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++--- files/mygui/openmw_settings_window.layout | 2 +- files/settings-default.cfg | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e8da27dce6..e12f2b0cbb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -207,7 +207,7 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); @@ -813,9 +813,9 @@ namespace MWRender { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { - if (it->first == "General" && it->second == "field of view") + if (it->first == "Camera" && it->second == "field of view") { - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); updateProjectionMatrix(); } else if (it->first == "Camera" && it->second == "viewing distance") diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 22d36de2b6..6d2424aa5b 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -280,7 +280,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7d0292c5ba..7ad2e7c1d5 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -23,6 +23,9 @@ small feature culling = true # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 +# Camera field of view in degrees (e.g. 30.0 to 110.0). +field of view = 55.0 + [Cells] # Adjacent exterior cells loaded (>0). Caution: this setting can @@ -99,9 +102,6 @@ show effect duration = false # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). anisotropy = 4 -# Camera field of view in degrees (e.g. 30.0 to 110.0). -field of view = 55.0 - # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png From e520d37c8715fc0da2c227254a2e3769b7501831 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 16:29:30 +0100 Subject: [PATCH 1623/1812] Override the field of view for first person meshes (Fixes #858, Fixes #3051) --- apps/openmw/mwrender/npcanimation.cpp | 37 ++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 4 ++- apps/openmw/mwrender/renderingmanager.cpp | 4 ++- apps/openmw/mwrender/renderingmanager.hpp | 1 + files/settings-default.cfg | 5 +++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8156712661..4e367b3b18 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -274,13 +275,15 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) : Animation(ptr, parentNode, resourceSystem), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), + mFirstPersonFieldOfView(firstPersonFieldOfView), mSoundsDisabled(disableSounds), mAccurateAiming(false), mAimingFactor(0.f) @@ -336,6 +339,37 @@ public: osg::ref_ptr mDepth; }; +/// Overrides Field of View to given value for rendering the subgraph. +/// Must be added as cull callback. +class OverrideFieldOfViewCallback : public osg::NodeCallback +{ +public: + OverrideFieldOfViewCallback(float fov) + : mFov(fov) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + osg::RefMatrix* projectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + float fov, aspect, zNear, zFar; + if (projectionMatrix->getPerspective(fov, aspect, zNear, zFar)) + { + fov = mFov; + projectionMatrix->makePerspective(fov, aspect, zNear, zFar); + cv->pushProjectionMatrix(projectionMatrix); + traverse(node, nv); + cv->popProjectionMatrix(); + } + else + traverse(node, nv); + } + +private: + float mFov; +}; + void NpcAnimation::setRenderBin() { if (mViewMode == VM_FirstPerson) @@ -445,6 +479,7 @@ void NpcAnimation::updateNpcBase() else { mObjectRoot->setNodeMask(Mask_FirstPerson); + mObjectRoot->addCullCallback(new OverrideFieldOfViewCallback(mFirstPersonFieldOfView)); if(isWerewolf) addAnimSource(smodel); else diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 2289703c8f..c5fc62f9cc 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -61,6 +61,8 @@ private: int mPartPriorities[ESM::PRT_Count]; osg::Vec3f mFirstPersonOffset; + // Field of view to use when rendering first person meshes + float mFirstPersonFieldOfView; boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; @@ -102,7 +104,7 @@ public: * @param viewMode */ NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener = false, - bool disableSounds = false, ViewMode viewMode=VM_Normal); + bool disableSounds = false, ViewMode viewMode=VM_Normal, float firstPersonFieldOfView=55.f); virtual ~NpcAnimation(); virtual void enableHeadAnimation(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e12f2b0cbb..4b208fa944 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -208,6 +208,7 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); + mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); @@ -729,7 +730,8 @@ namespace MWRender void RenderingManager::renderPlayer(const MWWorld::Ptr &player) { - mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); + mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, false, NpcAnimation::VM_Normal, + mFirstPersonFieldOfView)); mCamera->setAnimation(mPlayerAnimation.get()); mCamera->attachTo(player); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d510f52b56..7b1c8529fc 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -216,6 +216,7 @@ namespace MWRender float mFieldOfViewOverride; bool mFieldOfViewOverridden; float mFieldOfView; + float mFirstPersonFieldOfView; void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7ad2e7c1d5..6de42fd4ea 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -24,8 +24,13 @@ small feature culling = true viewing distance = 6666.0 # Camera field of view in degrees (e.g. 30.0 to 110.0). +# Does not affect the player's hands in the first person camera. field of view = 55.0 +# Field of view for first person meshes (i.e. the player's hands) +# Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. +first person field of view = 55.0 + [Cells] # Adjacent exterior cells loaded (>0). Caution: this setting can From 998ef36837c143af90c29a495a6d0828571dc6e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 18:04:23 +0100 Subject: [PATCH 1624/1812] Setting fix --- apps/openmw/mwgui/settingswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eb2f235299..78ff965328 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -256,7 +256,7 @@ namespace MWGui MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "Camera"))) + ")"); MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); From 152f415b9a94fae1a24798125047ba5309cc9050 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 18:32:58 +0100 Subject: [PATCH 1625/1812] Change texture coordinates when falling back to player_hit_01 --- apps/openmw/mwgui/screenfader.cpp | 18 ++++++++++++------ apps/openmw/mwgui/screenfader.hpp | 4 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index c44bcc3f1f..be0346e882 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -1,6 +1,7 @@ #include "screenfader.hpp" #include +#include namespace MWGui { @@ -66,20 +67,25 @@ namespace MWGui mFader->notifyOperationFinished(); } - ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout) + ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout, const MyGUI::FloatCoord& texCoordOverride) : WindowBase(layout) , mCurrentAlpha(0.f) , mFactor(1.f) , mRepeat(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); - setTexture(texturePath); setVisible(false); - } - void ScreenFader::setTexture(const std::string & texturePath) - { - mMainWidget->setProperty("ImageTexture", texturePath); + MyGUI::ImageBox* imageBox = mMainWidget->castType(false); + if (imageBox) + { + imageBox->setImageTexture(texturePath); + const MyGUI::IntSize imageSize = imageBox->getImageSize(); + imageBox->setImageCoord(MyGUI::IntCoord(texCoordOverride.left * imageSize.width, + texCoordOverride.top * imageSize.height, + texCoordOverride.width * imageSize.width, + texCoordOverride.height * imageSize.height)); + } } void ScreenFader::update(float dt) diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index d25f5fdc4e..f87fd84432 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,9 +36,7 @@ namespace MWGui class ScreenFader : public WindowBase { public: - ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout"); - - void setTexture(const std::string & texturePath); + ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout", const MyGUI::FloatCoord& texCoordOverride = MyGUI::FloatCoord(0,0,1,1)); void update(float dt); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccbae3ef37..31522913ea 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -330,12 +330,18 @@ namespace MWGui if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) mWerewolfFader = new ScreenFader(werewolfFaderTex); mBlindnessFader = new ScreenFader("black"); - std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; + // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available - // TODO: check if non-BM versions actually use player_hit_01.dds + std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; + const std::string hitFaderLayout = "openmw_screen_fader_hit.layout"; + MyGUI::FloatCoord hitFaderCoord (0,0,1,1); if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) + { hitFaderTexture = "textures\\player_hit_01.dds"; - mHitFader = new ScreenFader(hitFaderTexture, "openmw_screen_fader_hit.layout"); + hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5); + } + mHitFader = new ScreenFader(hitFaderTexture, hitFaderLayout, hitFaderCoord); + mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); From 1a654fa4515f98c1b44dfd13448f88c21e5fde32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 21:24:30 +0100 Subject: [PATCH 1626/1812] Reset locale after strftime() call --- apps/openmw/mwgui/savegamedialog.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 816fc0fa81..53c2807374 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -360,12 +360,17 @@ namespace MWGui timeinfo = localtime(&time); // Use system/environment locale settings for datetime formatting + char* oldLctime = setlocale(LC_TIME, NULL); setlocale(LC_TIME, ""); const int size=1024; char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; + + // reset + setlocale(LC_TIME, oldLctime); + text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; From f875597be5f2432536631ebe016d7f1b81dfbe57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 21:58:30 +0100 Subject: [PATCH 1627/1812] Don't use tolower() See https://forum.openmw.org/viewtopic.php?f=8&t=3231&p=35968 --- apps/openmw/mwdialogue/keywordsearch.hpp | 12 +++---- apps/openmw/mwgui/console.cpp | 4 +-- apps/openmw/mwgui/journalviewmodel.cpp | 2 +- components/files/linuxpath.cpp | 4 ++- components/files/macospath.cpp | 4 ++- components/files/multidircollection.cpp | 6 ++-- components/files/multidircollection.hpp | 6 ++-- components/interpreter/defines.cpp | 5 +-- components/misc/stringops.hpp | 46 +++++++++++++++++++++--- components/vfs/manager.cpp | 4 ++- 10 files changed, 71 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 3b68d3d6b9..3532dc22b8 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -44,7 +44,7 @@ public: typename Entry::childen_t::iterator current; typename Entry::childen_t::iterator next; - current = mRoot.mChildren.find (tolower (*keyword.begin())); + current = mRoot.mChildren.find (Misc::StringUtils::toLower (*keyword.begin())); if (current == mRoot.mChildren.end()) return false; else if (current->second.mKeyword.size() && Misc::StringUtils::ciEqual(current->second.mKeyword, keyword)) @@ -55,7 +55,7 @@ public: for (Point i = ++keyword.begin(); i != keyword.end(); ++i) { - next = current->second.mChildren.find(tolower (*i)); + next = current->second.mChildren.find(Misc::StringUtils::toLower (*i)); if (next == current->second.mChildren.end()) return false; if (Misc::StringUtils::ciEqual(next->second.mKeyword, keyword)) @@ -89,7 +89,7 @@ public: // check first character - typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (tolower (*i)); + typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (Misc::StringUtils::toLower (*i)); // no match, on to next character if (candidate == mRoot.mChildren.end ()) @@ -104,7 +104,7 @@ public: while ((j + 1) != end) { - typename Entry::childen_t::iterator next = candidate->second.mChildren.find (tolower (*++j)); + typename Entry::childen_t::iterator next = candidate->second.mChildren.find (Misc::StringUtils::toLower (*++j)); if (next == candidate->second.mChildren.end ()) { @@ -136,7 +136,7 @@ public: while (k != end && t != candidate->second.mKeyword.end ()) { - if (tolower (*k) != tolower (*t)) + if (Misc::StringUtils::toLower (*k) != Misc::StringUtils::toLower (*t)) break; ++k, ++t; @@ -212,7 +212,7 @@ private: void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry) { - int ch = tolower (keyword.at (depth)); + int ch = Misc::StringUtils::toLower (keyword.at (depth)); typename Entry::childen_t::iterator j = entry.mChildren.find (ch); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 761f7d1642..1777d86ad4 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -365,7 +365,7 @@ namespace MWGui /* Is the beginning of the string different from the input string? If yes skip it. */ for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();++iter, ++iter2) { - if( tolower(*iter) != tolower(*iter2) ) { + if( Misc::StringUtils::toLower(*iter) != Misc::StringUtils::toLower(*iter2) ) { string_different=true; break; } @@ -405,7 +405,7 @@ namespace MWGui for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) { for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { - if( tolower((*it)[i]) != tolower(*iter) ) { + if( Misc::StringUtils::toLower((*it)[i]) != Misc::StringUtils::toLower(*iter) ) { /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); return output; diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index f566e7769c..70f1305e0a 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -315,7 +315,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != tolower (character)) + if (i->first [0] != Misc::StringUtils::toLower(character)) continue; visitor (i->second.getName()); diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index a105bb928d..212db562c0 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -8,6 +8,8 @@ #include #include +#include + namespace { @@ -139,7 +141,7 @@ boost::filesystem::path LinuxPath::getInstallPath() const { // Change drive letter to lowercase, so we could use // ~/.wine/dosdevices symlinks - mwpath[0] = tolower(mwpath[0]); + mwpath[0] = Misc::StringUtils::toLower(mwpath[0]); installPath /= homePath; installPath /= ".wine/dosdevices/"; installPath /= mwpath; diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 6e794796f9..2371419605 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace { boost::filesystem::path getUserHome() @@ -129,7 +131,7 @@ boost::filesystem::path MacOsPath::getInstallPath() const if (!mwpath.empty()) { // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks - mwpath[0] = tolower(mwpath[0]); + mwpath[0] = Misc::StringUtils::toLower(mwpath[0]); installPath /= homePath; installPath /= ".wine/dosdevices/"; installPath /= mwpath; diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 9b4a542f58..b37a95b2fc 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -8,6 +8,8 @@ #include +#include + namespace Files { struct NameEqual @@ -28,8 +30,8 @@ namespace Files for (std::size_t i=0; i +#include + namespace Files { typedef std::vector PathContainer; @@ -27,8 +29,8 @@ namespace Files for (std::size_t i=0; i #include #include #include #include +#include + namespace Interpreter{ bool check(const std::string& str, const std::string& escword, unsigned int* i, unsigned int* start) @@ -35,7 +36,7 @@ namespace Interpreter{ { retval << text.substr(start, i - start); std::string temp = text.substr(i+1, 100); - transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + Misc::StringUtils::lowerCase(temp); bool found = false; try diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index d6bc190695..72c0275307 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -12,11 +12,49 @@ class StringUtils struct ci { bool operator()(char x, char y) const { - return tolower(x) < tolower(y); + return toLower(x) < toLower(y); } }; public: + + /// Plain and simple locale-unaware toLower. Anything from A to Z is lower-cased, multibyte characters are unchanged. + /// Don't use std::tolower(char, locale&) because that is abysmally slow. + /// Don't use tolower(int) because that depends on global locale. + static char toLower(char c) + { + switch(c) + { + case 'A':return 'a'; + case 'B':return 'b'; + case 'C':return 'c'; + case 'D':return 'd'; + case 'E':return 'e'; + case 'F':return 'f'; + case 'G':return 'g'; + case 'H':return 'h'; + case 'I':return 'i'; + case 'J':return 'j'; + case 'K':return 'k'; + case 'L':return 'l'; + case 'M':return 'm'; + case 'N':return 'n'; + case 'O':return 'o'; + case 'P':return 'p'; + case 'Q':return 'q'; + case 'R':return 'r'; + case 'S':return 's'; + case 'T':return 't'; + case 'U':return 'u'; + case 'V':return 'v'; + case 'W':return 'w'; + case 'X':return 'x'; + case 'Y':return 'y'; + case 'Z':return 'z'; + default:return c; + }; + } + static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } @@ -28,7 +66,7 @@ public: std::string::const_iterator xit = x.begin(); std::string::const_iterator yit = y.begin(); for (; xit != x.end(); ++xit, ++yit) { - if (tolower(*xit) != tolower(*yit)) { + if (toLower(*xit) != toLower(*yit)) { return false; } } @@ -42,7 +80,7 @@ public: for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len) { int res = *xit - *yit; - if(res != 0 && tolower(*xit) != tolower(*yit)) + if(res != 0 && toLower(*xit) != toLower(*yit)) return (res > 0) ? 1 : -1; } if(len > 0) @@ -58,7 +96,7 @@ public: /// Transforms input string to lower case w/o copy static std::string &toLower(std::string &inout) { for (unsigned int i=0; i #include +#include + #include "archive.hpp" namespace @@ -15,7 +17,7 @@ namespace char nonstrict_normalize_char(char ch) { - return ch == '\\' ? '/' : tolower(ch); + return ch == '\\' ? '/' : Misc::StringUtils::toLower(ch); } void normalize_path(std::string& path, bool strict) From 42d68eb7fb9b4d1773f5000138cd3d3c6fbe6996 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:29:57 +0100 Subject: [PATCH 1628/1812] Build fix --- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- components/misc/stringops.hpp | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 0b1af0e840..0bef1bb4e1 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -93,7 +93,7 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked) void CSMWorld::CommandDispatcher::setSelection (const std::vector& selection) { mSelection = selection; - std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower); + std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLowerStr); std::sort (mSelection.begin(), mSelection.end()); } diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index f644ad37ad..33025bd1c8 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -93,7 +93,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const { mIds = mData.getIds(); - std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLower); + std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLowerStr); std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 72c0275307..ce27d5fb2e 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -100,6 +100,11 @@ public: return inout; } + static std::string &toLowerStr(std::string &inout) + { + return toLower(inout); + } + /// Returns lower case copy of input string static std::string lowerCase(const std::string &in) { From e4751c68e948295a1fa36fee9a8904a6949d3953 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:30:02 +0100 Subject: [PATCH 1629/1812] Typo fix --- components/esm/loadregn.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 3d914bd17b..a946e488e2 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -45,7 +45,7 @@ struct Region WEATstruct mData; int mMapColor; // RGBA - // sleepList refers to a eveled list of creatures you can meet if + // sleepList refers to a leveled list of creatures you can meet if // you sleep outside in this region. std::string mId, mName, mSleepList; From 4dd4c5394bc97ce6d9cc87eedf8f4f35c5162df3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:30:37 +0100 Subject: [PATCH 1630/1812] Broken lower-casing fix --- apps/opencs/model/world/regionmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 10c67c909d..17831c2ac4 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -168,7 +168,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector& regions { std::vector regions2 (regions); - std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase); + std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::toLowerStr); std::sort (regions2.begin(), regions2.end()); for (std::map::const_iterator iter (mMap.begin()); From e3d3380c8ce1612f579f175972ffe79e00060df1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:41:55 +0100 Subject: [PATCH 1631/1812] Remove return value for in-place toLowerStr --- apps/essimporter/converter.hpp | 2 +- components/misc/stringops.hpp | 10 +++++----- components/nifosg/nifloader.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 8194f2b431..550b7c0aed 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -381,7 +381,7 @@ public: bool isDeleted = false; faction.load(esm, isDeleted); - std::string id = Misc::StringUtils::toLower(faction.mId); + std::string id = Misc::StringUtils::lowerCase(faction.mId); for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) { diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index ce27d5fb2e..2fd9972853 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -94,22 +94,22 @@ public: } /// Transforms input string to lower case w/o copy - static std::string &toLower(std::string &inout) { + static void toLower(std::string &inout) { for (unsigned int i=0; ilist[i].time, Misc::StringUtils::toLower(result))); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::lowerCase(result))); pos = nextpos; } From 07b064f61682096aef2f5f7838cd064847f5d24e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Dec 2015 22:49:15 +0100 Subject: [PATCH 1632/1812] Rename to lowerCaseInPlace --- apps/essimporter/converter.hpp | 2 +- apps/mwiniimporter/importer.cpp | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/regionmap.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- apps/openmw/mwclass/container.cpp | 4 ++-- apps/openmw/mwclass/door.cpp | 4 ++-- apps/openmw/mwgui/formatting.cpp | 4 ++-- apps/openmw/mwgui/itemmodel.cpp | 6 +++--- apps/openmw/mwmechanics/activespells.cpp | 8 ++------ apps/openmw/mwmechanics/activespells.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwscript/cellextensions.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 4 ++-- apps/openmw/mwscript/statsextensions.cpp | 20 +++++++++---------- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/store.cpp | 2 +- components/misc/resourcehelpers.cpp | 2 +- components/misc/stringops.hpp | 9 ++------- 21 files changed, 39 insertions(+), 48 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 550b7c0aed..f364e166c8 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -398,7 +398,7 @@ public: virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); - Misc::StringUtils::toLower(itemid); + Misc::StringUtils::lowerCaseInPlace(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 251889e281..5fdc3cbf56 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -846,7 +846,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { std::string filetype(entry->substr(entry->length()-3)); - Misc::StringUtils::toLower(filetype); + Misc::StringUtils::lowerCaseInPlace(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { boost::filesystem::path filepath(gameFilesDir); diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 0bef1bb4e1..a1fc980eb5 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -93,7 +93,7 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked) void CSMWorld::CommandDispatcher::setSelection (const std::vector& selection) { mSelection = selection; - std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLowerStr); + std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::lowerCaseInPlace); std::sort (mSelection.begin(), mSelection.end()); } diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 17831c2ac4..6dbbac97fb 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -168,7 +168,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector& regions { std::vector regions2 (regions); - std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::toLowerStr); + std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::lowerCaseInPlace); std::sort (regions2.begin(), regions2.end()); for (std::map::const_iterator iter (mMap.begin()); diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 33025bd1c8..344ae322e9 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -93,7 +93,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const { mIds = mData.getIds(); - std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLowerStr); + std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCaseInPlace); std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 6c44c97e25..bfdcc23c12 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -148,11 +148,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); - Misc::StringUtils::toLower(keyId); + Misc::StringUtils::lowerCaseInPlace(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::toLower(refId); + Misc::StringUtils::lowerCaseInPlace(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6fee79ddf0..56c5e655f0 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -117,11 +117,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); - Misc::StringUtils::toLower(keyId); + Misc::StringUtils::lowerCaseInPlace(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().getRefId(); - Misc::StringUtils::toLower(refId); + Misc::StringUtils::lowerCaseInPlace(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 6adef5eeb4..6a8145e970 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -129,7 +129,7 @@ namespace MWGui size_t tagNameEndPos = tag.find(' '); mAttributes.clear(); mTag = tag.substr(0, tagNameEndPos); - Misc::StringUtils::toLower(mTag); + Misc::StringUtils::lowerCaseInPlace(mTag); if (mTag.empty()) return; @@ -151,7 +151,7 @@ namespace MWGui return; std::string key = tag.substr(0, sepPos); - Misc::StringUtils::toLower(key); + Misc::StringUtils::lowerCaseInPlace(key); tag.erase(0, sepPos+1); std::string value; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index a1e36bce67..2c382f3cf4 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -35,7 +35,7 @@ namespace MWGui { const ESM::GameSetting ¤tSetting = *currentIteration; std::string currentGMSTID = currentSetting.mId; - Misc::StringUtils::toLower(currentGMSTID); + Misc::StringUtils::lowerCaseInPlace(currentGMSTID); // Don't bother checking this GMST if it's not a sMagicBound* one. const std::string& toFind = "smagicbound"; @@ -44,7 +44,7 @@ namespace MWGui // All sMagicBound* GMST's should be of type string std::string currentGMSTValue = currentSetting.getString(); - Misc::StringUtils::toLower(currentGMSTValue); + Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); boundItemIDCache.insert(currentGMSTValue); } @@ -52,7 +52,7 @@ namespace MWGui // Perform bound item check and assign the Flag_Bound bit if it passes std::string tempItemID = base.getCellRef().getRefId(); - Misc::StringUtils::toLower(tempItemID); + Misc::StringUtils::lowerCaseInPlace(tempItemID); if (boundItemIDCache.count(tempItemID) != 0) mFlags |= Flag_Bound; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 7068310a0d..6a247622c5 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -132,15 +132,11 @@ namespace MWMechanics return scaledDuration-usedUp; } - bool ActiveSpells::isSpellActive(std::string id) const + bool ActiveSpells::isSpellActive(const std::string& id) const { - Misc::StringUtils::toLower(id); for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter) { - std::string left = iter->first; - Misc::StringUtils::toLower(left); - - if (iter->first == id) + if (Misc::StringUtils::ciEqual(iter->first, id)) return true; } return false; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 2a4d75d402..3842ee61c5 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -97,7 +97,7 @@ namespace MWMechanics /// Remove all spells void clear(); - bool isSpellActive (std::string id) const; + bool isSpellActive (const std::string& id) const; ///< case insensitive const MagicEffects& getMagicEffects() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 68bea02b0c..ba958df10e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -604,7 +604,7 @@ namespace MWMechanics int rank = 0; std::string npcFaction = ptr.getClass().getPrimaryFaction(ptr); - Misc::StringUtils::toLower(npcFaction); + Misc::StringUtils::lowerCaseInPlace(npcFaction); if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end()) { @@ -1042,7 +1042,7 @@ namespace MWMechanics owner.first = ownerCellRef->getFaction(); owner.second = true; } - Misc::StringUtils::toLower(owner.first); + Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ecfb2df147..214e7f2217 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -390,7 +390,7 @@ namespace MWRender void Animation::addAnimSource(const std::string &model) { std::string kfname = model; - Misc::StringUtils::toLower(kfname); + Misc::StringUtils::lowerCaseInPlace(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index b6f7229e03..513c1cc42e 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -123,7 +123,7 @@ namespace MWScript const MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); - Misc::StringUtils::toLower(current); + Misc::StringUtils::lowerCaseInPlace(current); bool match = current.length()>=name.length() && current.substr (0, name.length())==name; diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 397e0cac5a..254da56d6e 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -116,7 +116,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { std::string cell = (runtime.getStringLiteral (runtime[0].mInteger)); - ::Misc::StringUtils::toLower(cell); + ::Misc::StringUtils::lowerCaseInPlace(cell); runtime.pop(); // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well." @@ -129,7 +129,7 @@ namespace MWScript for (; it != cells.extEnd(); ++it) { std::string name = it->mName; - ::Misc::StringUtils::toLower(name); + ::Misc::StringUtils::lowerCaseInPlace(name); if (name.find(cell) != std::string::npos) MWBase::Environment::get().getWindowManager()->addVisitedLocation ( it->mName, diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index e4ad71875f..3996dd80b4 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -543,7 +543,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -575,7 +575,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -614,7 +614,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -645,7 +645,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); @@ -756,7 +756,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); runtime.push ( @@ -791,7 +791,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, value); @@ -825,7 +825,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - ::Misc::StringUtils::toLower (factionId); + ::Misc::StringUtils::lowerCaseInPlace (factionId); MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, @@ -870,11 +870,11 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); std::string race = runtime.getStringLiteral(runtime[0].mInteger); - ::Misc::StringUtils::toLower(race); + ::Misc::StringUtils::lowerCaseInPlace(race); runtime.pop(); std::string npcRace = ptr.get()->mBase->mRace; - ::Misc::StringUtils::toLower(npcRace); + ::Misc::StringUtils::lowerCaseInPlace(npcRace); runtime.push (npcRace == race); } @@ -911,7 +911,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - ::Misc::StringUtils::toLower(factionID); + ::Misc::StringUtils::lowerCaseInPlace(factionID); MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5832a6727f..029dac22d0 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -472,7 +472,7 @@ namespace MWWorld void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) { - Misc::StringUtils::toLower (ref.mRefID); + Misc::StringUtils::lowerCaseInPlace (ref.mRefID); switch (store.find (ref.mRefID)) { diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 4a406613de..acc06b28a9 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -96,7 +96,7 @@ namespace MWWorld // This readRecord() method is used when reading a saved game. // Deleted globals can't appear there, so isDeleted will be ignored here. global.load(reader, isDeleted); - Misc::StringUtils::toLower(global.mId); + Misc::StringUtils::lowerCaseInPlace(global.mId); Collection::iterator iter = mVariables.find (global.mId); if (iter!=mVariables.end()) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 3d23f3da43..d1ba0ef0b5 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -190,7 +190,7 @@ namespace MWWorld bool isDeleted = false; record.load(esm, isDeleted); - Misc::StringUtils::toLower(record.mId); + Misc::StringUtils::lowerCaseInPlace(record.mId); std::pair inserted = mStatic.insert(std::make_pair(record.mId, record)); if (inserted.second) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 0c2635752d..6fe13abf31 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -51,7 +51,7 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev std::string prefix2 = topLevelDirectory + '/'; std::string correctedPath = resPath; - Misc::StringUtils::toLower(correctedPath); + Misc::StringUtils::lowerCaseInPlace(correctedPath); // Apparently, leading separators are allowed while (correctedPath.size() && (correctedPath[0] == '/' || correctedPath[0] == '\\')) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 2fd9972853..2723527f1d 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -94,21 +94,16 @@ public: } /// Transforms input string to lower case w/o copy - static void toLower(std::string &inout) { + static void lowerCaseInPlace(std::string &inout) { for (unsigned int i=0; i Date: Tue, 8 Dec 2015 09:56:42 +0100 Subject: [PATCH 1633/1812] some simplification --- apps/opencs/model/prefs/category.cpp | 9 ++----- apps/opencs/model/prefs/category.hpp | 4 +-- apps/opencs/model/prefs/state.cpp | 39 +++++++++++++--------------- apps/opencs/model/prefs/state.hpp | 18 +++++++++---- apps/opencs/view/prefs/dialogue.cpp | 8 +++--- apps/opencs/view/prefs/dialogue.hpp | 1 - 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 2f94c729bf..8143a19e5c 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -1,16 +1,11 @@ #include "category.hpp" -CSMPrefs::Category::Category (State *parent, const std::string& key, const std::string& name) -: mParent (parent), mKey (key), mName (name) +CSMPrefs::Category::Category (State *parent, const std::string& key) +: mParent (parent), mKey (key) {} const std::string& CSMPrefs::Category::getKey() const { return mKey; } - -const std::string& CSMPrefs::Category::getName() const -{ - return mName; -} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index d80d5416fb..43a6325ee4 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -11,15 +11,13 @@ namespace CSMPrefs { State *mParent; std::string mKey; - std::string mName; public: - Category (State *parent, const std::string& key, const std::string& name); + Category (State *parent, const std::string& key); const std::string& getKey() const; - const std::string& getName() const; }; } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 70e4c86c5e..d8a0a56140 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -28,28 +28,28 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { - declareCategory ("window", "Windows"); + declareCategory ("Windows"); - declareCategory ("records", "Records"); + declareCategory ("Records"); - declareCategory ("table-input", "ID Tables"); + declareCategory ("ID Tables"); - declareCategory ("dialogues", "ID Dialogues"); + declareCategory ("ID Dialogues"); - declareCategory ("report-input", "Reports"); + declareCategory ("Reports"); - declareCategory ("search", "Search & Replace"); + declareCategory ("Search & Replace"); - declareCategory ("script-editor", "Scripts"); + declareCategory ("Scripts"); - declareCategory ("general-input", "General Input"); + declareCategory ("General Input"); - declareCategory ("scene-input", "3D Scene Input"); + declareCategory ("3D Scene Input"); - declareCategory ("tooltips", "Tooltips"); + declareCategory ("Tooltips"); } -void CSMPrefs::State::declareCategory (const std::string& key, const std::string& name) +void CSMPrefs::State::declareCategory (const std::string& key) { std::map::iterator iter = mCategories.find (key); @@ -60,7 +60,7 @@ void CSMPrefs::State::declareCategory (const std::string& key, const std::string else { mCurrentCategory = - mCategories.insert (std::make_pair (key, Category (this, key, name))).first; + mCategories.insert (std::make_pair (key, Category (this, key))).first; } } @@ -88,17 +88,14 @@ void CSMPrefs::State::save() mSettings.saveUser (user.string()); } -std::vector > CSMPrefs::State::listCategories() const +CSMPrefs::State::Iterator CSMPrefs::State::begin() { - std::vector > list; + return mCategories.begin(); +} - for (std::map::const_iterator iter (mCategories.begin()); - iter!=mCategories.end(); ++iter) - list.push_back (std::make_pair (iter->second.getName(), iter->first)); - - std::sort (list.begin(), list.end()); - - return list; +CSMPrefs::State::Iterator CSMPrefs::State::end() +{ + return mCategories.end(); } CSMPrefs::State& CSMPrefs::State::get() diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index fd49db3ef5..d643dfa4a8 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -22,11 +22,18 @@ namespace CSMPrefs static State *sThis; + public: + + typedef std::map Collection; + typedef Collection::iterator Iterator; + + private: + const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; Settings::Manager mSettings; - std::map mCategories; - std::map::iterator mCurrentCategory; + Collection mCategories; + Iterator mCurrentCategory; // not implemented State (const State&); @@ -38,7 +45,7 @@ namespace CSMPrefs void declare(); - void declareCategory (const std::string& key, const std::string& name); + void declareCategory (const std::string& key); public: @@ -48,8 +55,9 @@ namespace CSMPrefs void save(); - /// \return collection of name, key pairs (sorted) - std::vector > listCategories() const; + Iterator begin(); + + Iterator end(); static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index cc794c286f..ec43d853dc 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -24,10 +24,10 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) int maxWidth = 1; - for (std::vector >::const_iterator iter (mCategories.begin()); - iter!=mCategories.end(); ++iter) + for (CSMPrefs::State::Iterator iter = CSMPrefs::get().begin(); iter!=CSMPrefs::get().end(); + ++iter) { - QString label = QString::fromUtf8 (iter->first.c_str()); + QString label = QString::fromUtf8 (iter->second.getKey().c_str()); maxWidth = std::max (maxWidth, metrics.width (label)); mList->addItem (label); @@ -46,7 +46,7 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } -CSVPrefs::Dialogue::Dialogue() : mCategories (CSMPrefs::get().listCategories()) +CSVPrefs::Dialogue::Dialogue() { setWindowTitle ("User Settings"); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 2773bccccb..78c832c9f5 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -15,7 +15,6 @@ namespace CSVPrefs QListWidget *mList; QStackedWidget *mContent; - std::vector > mCategories; private: From 5e40b4d2e83128721863e5c56c7f3b65aea0459e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 12:04:45 +0100 Subject: [PATCH 1634/1812] page switching mechanism --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/state.cpp | 10 ++++++++++ apps/opencs/model/prefs/state.hpp | 2 ++ apps/opencs/view/prefs/dialogue.cpp | 27 ++++++++++++++++++++++++++- apps/opencs/view/prefs/dialogue.hpp | 5 +++++ apps/opencs/view/prefs/pagebase.cpp | 19 +++++++++++++++++++ apps/opencs/view/prefs/pagebase.hpp | 27 +++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/prefs/pagebase.cpp create mode 100644 apps/opencs/view/prefs/pagebase.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b58000b565..1e666c77d8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -124,7 +124,7 @@ opencs_units_noqt (view/settings ) opencs_units (view/prefs - dialogue + dialogue pagebase ) opencs_units (model/settings diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d8a0a56140..c484a98d67 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -98,6 +98,16 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } +CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) +{ + Iterator iter = mCategories.find (key); + + if (iter==mCategories.end()) + throw std::logic_error ("Invalid user settings category: " + key); + + return iter->second; +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index d643dfa4a8..a2e7aa0384 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -59,6 +59,8 @@ namespace CSMPrefs Iterator end(); + Category& getCategory (const std::string& key); + static State& get(); }; diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index ec43d853dc..c4480fec46 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -10,6 +10,8 @@ #include "../../model/prefs/state.hpp" +#include "pagebase.hpp" + void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) { mList = new QListWidget (main); @@ -35,7 +37,8 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) mList->setMaximumWidth (maxWidth + 10); - /// \todo connect to selection signal + connect (mList, SIGNAL (currentItemChanged (QListWidgetItem *, QListWidgetItem *)), + this, SLOT (selectionChanged (QListWidgetItem *, QListWidgetItem *))); } void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) @@ -86,3 +89,25 @@ void CSVPrefs::Dialogue::show() QWidget::show(); } + +void CSVPrefs::Dialogue::selectionChanged (QListWidgetItem *current, QListWidgetItem *previous) +{ + if (current) + { + std::string key = current->text().toUtf8().data(); + + for (int i=0; icount(); ++i) + { + PageBase& page = dynamic_cast (*mContent->widget (i)); + + if (page.getCategory().getKey()==key) + { + mContent->setCurrentIndex (i); + return; + } + } + + PageBase *page = new PageBase (CSMPrefs::get().getCategory (key), mContent); + mContent->setCurrentIndex (mContent->addWidget (page)); + } +} diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 78c832c9f5..6bee54eb8a 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -6,6 +6,7 @@ class QSplitter; class QListWidget; class QStackedWidget; +class QListWidgetItem; namespace CSVPrefs { @@ -33,6 +34,10 @@ namespace CSVPrefs public slots: void show(); + + private slots: + + void selectionChanged (QListWidgetItem *current, QListWidgetItem *previous); }; } diff --git a/apps/opencs/view/prefs/pagebase.cpp b/apps/opencs/view/prefs/pagebase.cpp new file mode 100644 index 0000000000..28c33a94ad --- /dev/null +++ b/apps/opencs/view/prefs/pagebase.cpp @@ -0,0 +1,19 @@ + +#include "pagebase.hpp" + +#include + +#include "../../model/prefs/category.hpp" + +CSVPrefs::PageBase::PageBase (CSMPrefs::Category& category, QWidget *parent) +: QScrollArea (parent), mCategory (category) +{ +QLabel *temp = new QLabel (category.getKey().c_str(), this); +setWidget (temp); + +} + +CSMPrefs::Category& CSVPrefs::PageBase::getCategory() +{ + return mCategory; +} diff --git a/apps/opencs/view/prefs/pagebase.hpp b/apps/opencs/view/prefs/pagebase.hpp new file mode 100644 index 0000000000..affe49f4a9 --- /dev/null +++ b/apps/opencs/view/prefs/pagebase.hpp @@ -0,0 +1,27 @@ +#ifndef CSV_PREFS_PAGEBASE_H +#define CSV_PREFS_PAGEBASE_H + +#include + +namespace CSMPrefs +{ + class Category; +} + +namespace CSVPrefs +{ + class PageBase : public QScrollArea + { + Q_OBJECT + + CSMPrefs::Category& mCategory; + + public: + + PageBase (CSMPrefs::Category& category, QWidget *parent); + + CSMPrefs::Category& getCategory(); + }; +} + +#endif From c15822431424627b7d3708c5d9688bae511d1bfc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 12:09:53 +0100 Subject: [PATCH 1635/1812] fixed a faulty include --- apps/opencs/model/prefs/category.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 43a6325ee4..23caba5e47 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -1,7 +1,7 @@ #ifndef CSV_PREFS_CATEGORY_H #define CSM_PREFS_CATEGORY_H -#include +#include namespace CSMPrefs { From bd68ebac626de076b546e0c3174dca438a5fb25c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 15:24:02 +0100 Subject: [PATCH 1636/1812] GetEffect fix --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 68a30de4a6..8375cf8aee 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -425,7 +425,7 @@ namespace MWScript const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); for (MWMechanics::MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) { - if (it->first.mId == key) + if (it->first.mId == key && it->second.getModifier() > 0) { runtime.push(1); return; From 624809c8dc770336888d412c348071b99d1c70f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 16:48:01 +0100 Subject: [PATCH 1637/1812] Minor fix for error handling in skeleton.cpp --- components/sceneutil/skeleton.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 332dc3b071..d1299c0587 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -162,6 +162,7 @@ void Bone::update(const osg::Matrixf* parentMatrixInSkeletonSpace) if (!mNode) { std::cerr << "Bone without node " << std::endl; + return; } if (parentMatrixInSkeletonSpace) mMatrixInSkeletonSpace = mNode->getMatrix() * (*parentMatrixInSkeletonSpace); From e69750905a1a50479c0d13313ee6e0dd95657028 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 16:48:25 +0100 Subject: [PATCH 1638/1812] Fix gcc warning about function casts --- apps/openmw/mwsound/openal_output.cpp | 36 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 407a24ce10..c2e808dee5 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -50,6 +50,20 @@ namespace const int sLoudnessFPS = 20; // loudness values per second of audio +// Helper to get an OpenAL extension function +template +void convertPointer(T& dest, R src) +{ + memcpy(&dest, &src, sizeof(src)); +} + +template +void getFunc(T& func, ALCdevice *device, const char *name) +{ + void* funcPtr = alcGetProcAddress(device, name); + convertPointer(func, funcPtr); +} + } namespace MWSound @@ -602,9 +616,8 @@ std::vector OpenAL_Output::enumerateHrtf() if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) return ret; - LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcGetStringiSOFT") - ); + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); ALCint num_hrtf; alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); @@ -626,12 +639,12 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) return; } - LPALCGETSTRINGISOFT alcGetStringiSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcGetStringiSOFT") - ); - LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcResetDeviceSOFT") - ); + + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + + LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; + getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); @@ -681,9 +694,8 @@ void OpenAL_Output::disableHrtf() return; } - LPALCRESETDEVICESOFT alcResetDeviceSOFT = reinterpret_cast( - alcGetProcAddress(mDevice, "alcResetDeviceSOFT") - ); + LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; + getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); From c61d717e41836c11f5c8881fb9dbb1d65b9f541b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Dec 2015 17:21:58 +0100 Subject: [PATCH 1639/1812] added integer settings --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/prefs/category.cpp | 20 +++++++ apps/opencs/model/prefs/category.hpp | 19 ++++++- apps/opencs/model/prefs/intsetting.cpp | 69 +++++++++++++++++++++++ apps/opencs/model/prefs/intsetting.hpp | 39 +++++++++++++ apps/opencs/model/prefs/setting.cpp | 32 +++++++++++ apps/opencs/model/prefs/setting.hpp | 53 ++++++++++++++++++ apps/opencs/model/prefs/state.cpp | 76 ++++++++++++++++++++++++++ apps/opencs/model/prefs/state.hpp | 13 +++++ apps/opencs/view/prefs/dialogue.cpp | 11 +++- apps/opencs/view/prefs/dialogue.hpp | 4 ++ apps/opencs/view/prefs/page.cpp | 40 ++++++++++++++ apps/opencs/view/prefs/page.hpp | 29 ++++++++++ apps/opencs/view/prefs/pagebase.cpp | 8 +-- 14 files changed, 405 insertions(+), 12 deletions(-) create mode 100644 apps/opencs/model/prefs/intsetting.cpp create mode 100644 apps/opencs/model/prefs/intsetting.hpp create mode 100644 apps/opencs/model/prefs/setting.cpp create mode 100644 apps/opencs/model/prefs/setting.hpp create mode 100644 apps/opencs/view/prefs/page.cpp create mode 100644 apps/opencs/view/prefs/page.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1e666c77d8..003fd657b7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -124,7 +124,7 @@ opencs_units_noqt (view/settings ) opencs_units (view/prefs - dialogue pagebase + dialogue pagebase page ) opencs_units (model/settings @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state + state setting intsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 8143a19e5c..b001586b55 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -9,3 +9,23 @@ const std::string& CSMPrefs::Category::getKey() const { return mKey; } + +CSMPrefs::State *CSMPrefs::Category::getState() const +{ + return mParent; +} + +void CSMPrefs::Category::addSetting (Setting *setting) +{ + mSettings.push_back (setting); +} + +CSMPrefs::Category::Iterator CSMPrefs::Category::begin() +{ + return mSettings.begin(); +} + +CSMPrefs::Category::Iterator CSMPrefs::Category::end() +{ + return mSettings.end(); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 23caba5e47..0b8e45d56d 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -1,16 +1,26 @@ -#ifndef CSV_PREFS_CATEGORY_H +#ifndef CSM_PREFS_CATEGORY_H #define CSM_PREFS_CATEGORY_H #include +#include namespace CSMPrefs { class State; + class Setting; class Category { + public: + + typedef std::vector Container; + typedef Container::iterator Iterator; + + private: + State *mParent; std::string mKey; + Container mSettings; public: @@ -18,6 +28,13 @@ namespace CSMPrefs const std::string& getKey() const; + State *getState() const; + + void addSetting (Setting *setting); + + Iterator begin(); + + Iterator end(); }; } diff --git a/apps/opencs/model/prefs/intsetting.cpp b/apps/opencs/model/prefs/intsetting.cpp new file mode 100644 index 0000000000..83fb495c57 --- /dev/null +++ b/apps/opencs/model/prefs/intsetting.cpp @@ -0,0 +1,69 @@ + +#include "intsetting.hpp" + +#include + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::IntSetting::IntSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, int default_) +: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + mDefault (default_) +{} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setRange (int min, int max) +{ + mMin = min; + mMax = max; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setMin (int min) +{ + mMin = min; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setMax (int max) +{ + mMax = max; + return *this; +} + +CSMPrefs::IntSetting& CSMPrefs::IntSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::IntSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QSpinBox *widget = new QSpinBox (parent); + widget->setRange (mMin, mMax); + widget->setValue (mDefault); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (valueChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::IntSetting::valueChanged (int value) +{ + getValues().setInt (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp new file mode 100644 index 0000000000..314e68b372 --- /dev/null +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_PREFS_INTSETTING_H +#define CSM_PREFS_INTSETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class IntSetting : public Setting + { + Q_OBJECT + + int mMin; + int mMax; + std::string mTooltip; + int mDefault; + + public: + + IntSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, int default_); + + IntSetting& setRange (int min, int max); + + IntSetting& setMin (int min); + + IntSetting& setMax (int max); + + IntSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp new file mode 100644 index 0000000000..70dbbc7453 --- /dev/null +++ b/apps/opencs/model/prefs/setting.cpp @@ -0,0 +1,32 @@ + +#include "setting.hpp" + +#include "category.hpp" +#include "state.hpp" + +Settings::Manager& CSMPrefs::Setting::getValues() +{ + return *mValues; +} + +CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label) +: QObject (parent->getState()), mParent (parent), mValues (values), mKey (key), mLabel (label) +{} + +CSMPrefs::Setting:: ~Setting() {} + +const CSMPrefs::Category *CSMPrefs::Setting::getParent() const +{ + return mParent; +} + +const std::string& CSMPrefs::Setting::getKey() const +{ + return mKey; +} + +const std::string& CSMPrefs::Setting::getLabel() const +{ + return mLabel; +} diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp new file mode 100644 index 0000000000..148c642925 --- /dev/null +++ b/apps/opencs/model/prefs/setting.hpp @@ -0,0 +1,53 @@ +#ifndef CSM_PREFS_SETTING_H +#define CSM_PREFS_SETTING_H + +#include +#include + +#include + +class QWidget; + +namespace Settings +{ + class Manager; +} + +namespace CSMPrefs +{ + class Category; + + class Setting : public QObject + { + Q_OBJECT + + Category *mParent; + Settings::Manager *mValues; + std::string mKey; + std::string mLabel; + + protected: + + Settings::Manager& getValues(); + + public: + + Setting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label); + + virtual ~Setting(); + + /// Return label, input widget. + /// + /// \note first can be a 0-pointer, which means that the label is part of the input + /// widget. + virtual std::pair makeWidgets (QWidget *parent) = 0; + + const Category *getParent() const; + + const std::string& getKey() const; + + const std::string& getLabel() const; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c484a98d67..dfc4605285 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -3,6 +3,9 @@ #include #include +#include + +#include "intsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -29,6 +32,24 @@ void CSMPrefs::State::load() void CSMPrefs::State::declare() { declareCategory ("Windows"); + declareInt ("default-width", "Default window width", 800). + setTooltip ("Newly opened top-level windows will open with this width."). + setMin (80); + declareInt ("default-height", "Default window height", 600). + setTooltip ("Newly opened top-level windows will open with this height."). + setMin (80); + // reuse + // show-statusbar + declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). + setTooltip ("If the maximum number is reached and a new subview is opened " + "it will be placed into a new top-level window."). + setRange (1, 256); + // hide-subview + declareInt ("minimum-width", "Minimum subview width", 325). + setTooltip ("Minimum width of subviews."). + setRange (50, 10000); + // mainwindow-scrollbar + // grow-limit declareCategory ("Records"); @@ -39,14 +60,33 @@ void CSMPrefs::State::declare() declareCategory ("Reports"); declareCategory ("Search & Replace"); + declareInt ("char-before", "Characters before search string", 10). + setTooltip ("Maximum number of character to display in search result before the searched text"); + declareInt ("char-after", "Characters after search string", 10). + setTooltip ("Maximum number of character to display in search result after the searched text"); + // auto-delete declareCategory ("Scripts"); + // show-linenum + // mono-font + // warnings + // toolbar + declareInt ("compile-delay", "Delay between updating of source errors", 100). + setTooltip ("Delay in milliseconds"). + setRange (0, 10000); + declareInt ("error-height", "Initial height of the error panel", 100). + setRange (100, 10000); + // syntax-colouring declareCategory ("General Input"); declareCategory ("3D Scene Input"); declareCategory ("Tooltips"); + // scene + // scene-hide-basic + declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). + setMin (1); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -64,6 +104,37 @@ void CSMPrefs::State::declareCategory (const std::string& key) } } +CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, + const std::string& label, int default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::ostringstream stream; + stream << default_; + setDefault (key, stream.str()); + + default_ = mSettings.getInt (key, mCurrentCategory->second.getKey()); + + CSMPrefs::IntSetting *setting = + new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + +void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) +{ + Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); + + Settings::CategorySettingValueMap::iterator iter = + mSettings.mDefaultSettings.find (fullKey); + + if (iter==mSettings.mDefaultSettings.end()) + mSettings.mDefaultSettings.insert (std::make_pair (fullKey, default_)); +} + CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) : mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), mCurrentCategory (mCategories.end()) @@ -108,6 +179,11 @@ CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) return iter->second; } +void CSMPrefs::State::update (const Setting& setting) +{ + emit (settingChanged (setting)); +} + CSMPrefs::State& CSMPrefs::State::get() { if (!sThis) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index a2e7aa0384..c38f42049f 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -13,9 +13,12 @@ #include #include "category.hpp" +#include "setting.hpp" namespace CSMPrefs { + class IntSetting; + class State : public QObject { Q_OBJECT @@ -47,6 +50,10 @@ namespace CSMPrefs void declareCategory (const std::string& key); + IntSetting& declareInt (const std::string& key, const std::string& label, int default_); + + void setDefault (const std::string& key, const std::string& default_); + public: State (const Files::ConfigurationManager& configurationManager); @@ -61,7 +68,13 @@ namespace CSMPrefs Category& getCategory (const std::string& key); + void update (const Setting& setting); + static State& get(); + + signals: + + void settingChanged (const Setting& setting); }; // convenience function diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index c4480fec46..6135afde70 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -10,7 +10,7 @@ #include "../../model/prefs/state.hpp" -#include "pagebase.hpp" +#include "page.hpp" void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) { @@ -49,6 +49,13 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) main->addWidget (mContent); } +CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key) +{ + // special case page code goes here + + return new Page (CSMPrefs::get().getCategory (key), mContent); +} + CSVPrefs::Dialogue::Dialogue() { setWindowTitle ("User Settings"); @@ -107,7 +114,7 @@ void CSVPrefs::Dialogue::selectionChanged (QListWidgetItem *current, QListWidget } } - PageBase *page = new PageBase (CSMPrefs::get().getCategory (key), mContent); + PageBase *page = makePage (key); mContent->setCurrentIndex (mContent->addWidget (page)); } } diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 6bee54eb8a..3965800db3 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -10,6 +10,8 @@ class QListWidgetItem; namespace CSVPrefs { + class PageBase; + class Dialogue : public QMainWindow { Q_OBJECT @@ -23,6 +25,8 @@ namespace CSVPrefs void buildContentArea (QSplitter *main); + PageBase *makePage (const std::string& key); + public: Dialogue(); diff --git a/apps/opencs/view/prefs/page.cpp b/apps/opencs/view/prefs/page.cpp new file mode 100644 index 0000000000..181ae40fac --- /dev/null +++ b/apps/opencs/view/prefs/page.cpp @@ -0,0 +1,40 @@ + +#include "page.hpp" + +#include + +#include "../../model/prefs/setting.hpp" +#include "../../model/prefs/category.hpp" + +CSVPrefs::Page::Page (CSMPrefs::Category& category, QWidget *parent) +: PageBase (category, parent) +{ + QWidget *widget = new QWidget (parent); + mGrid = new QGridLayout (widget); + + for (CSMPrefs::Category::Iterator iter = category.begin(); iter!=category.end(); ++iter) + addSetting (*iter); + + setWidget (widget); +} + +void CSVPrefs::Page::addSetting (CSMPrefs::Setting *setting) +{ + std::pair widgets = setting->makeWidgets (this); + + int next = mGrid->rowCount(); + + if (widgets.first) + { + mGrid->addWidget (widgets.first, next, 0); + mGrid->addWidget (widgets.second, next, 1); + } + else if (widgets.second) + { + mGrid->addWidget (widgets.second, next, 0, next, 1); + } + else + { + mGrid->addWidget (new QWidget (this), next, 0); + } +} diff --git a/apps/opencs/view/prefs/page.hpp b/apps/opencs/view/prefs/page.hpp new file mode 100644 index 0000000000..ce13e5d9b9 --- /dev/null +++ b/apps/opencs/view/prefs/page.hpp @@ -0,0 +1,29 @@ +#ifndef CSV_PREFS_PAGE_H +#define CSV_PREFS_PAGE_H + +#include "pagebase.hpp" + +class QGridLayout; + +namespace CSMPrefs +{ + class Setting; +} + +namespace CSVPrefs +{ + class Page : public PageBase + { + Q_OBJECT + + QGridLayout *mGrid; + + public: + + Page (CSMPrefs::Category& category, QWidget *parent); + + void addSetting (CSMPrefs::Setting *setting); + }; +} + +#endif diff --git a/apps/opencs/view/prefs/pagebase.cpp b/apps/opencs/view/prefs/pagebase.cpp index 28c33a94ad..16684a69d4 100644 --- a/apps/opencs/view/prefs/pagebase.cpp +++ b/apps/opencs/view/prefs/pagebase.cpp @@ -1,17 +1,11 @@ #include "pagebase.hpp" -#include - #include "../../model/prefs/category.hpp" CSVPrefs::PageBase::PageBase (CSMPrefs::Category& category, QWidget *parent) : QScrollArea (parent), mCategory (category) -{ -QLabel *temp = new QLabel (category.getKey().c_str(), this); -setWidget (temp); - -} +{} CSMPrefs::Category& CSVPrefs::PageBase::getCategory() { From 1264651af73474a2da72a00c7e9e9553110efdd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 21:12:05 +0100 Subject: [PATCH 1640/1812] Fix coverity defects --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 6 +++--- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index db010d0fb5..eebfddaab3 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -709,7 +709,7 @@ namespace MWPhysics bool PhysicsSystem::isOnSolidGround (const MWWorld::Ptr& actor) const { const Actor* physactor = getActor(actor); - if (!physactor->getOnGround()) + if (!physactor || !physactor->getOnGround()) return false; CollisionMap::const_iterator found = mStandingCollisions.find(actor); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index c2e808dee5..02a9f33f90 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -363,9 +363,9 @@ OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) switch(type) { - case SampleType_UInt8: mSilence = 0x80; - case SampleType_Int16: mSilence = 0x00; - case SampleType_Float32: mSilence = 0x00; + case SampleType_UInt8: mSilence = 0x80; break; + case SampleType_Int16: mSilence = 0x00; break; + case SampleType_Float32: mSilence = 0x00; break; } mFrameSize = framesToBytes(1, chans, type); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a13acf3e2f..d12174e207 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -48,9 +48,6 @@ namespace MWSound , mListenerUp(0,0,1) , mPausedSoundTypes(0) { - if(!useSound) - return; - mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); @@ -67,6 +64,9 @@ namespace MWSound mBufferCacheMax *= 1024*1024; mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); + if(!useSound) + return; + std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); From 2f9b404094243c94465232e3932ac4b129953f21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 21:41:35 +0100 Subject: [PATCH 1641/1812] InstallationPage: properly exit the QThread (Fixes #2210) --- apps/wizard/installationpage.cpp | 7 +------ apps/wizard/unshield/unshieldworker.cpp | 2 -- apps/wizard/unshield/unshieldworker.hpp | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index dc2674680e..2f0af88c94 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -28,12 +28,6 @@ Wizard::InstallationPage::InstallationPage(QWidget *parent) : connect(mUnshield, SIGNAL(finished()), mThread, SLOT(quit())); - connect(mUnshield, SIGNAL(finished()), - mUnshield, SLOT(deleteLater())); - - connect(mUnshield, SIGNAL(finished()), - mThread, SLOT(deleteLater()));; - connect(mUnshield, SIGNAL(finished()), this, SLOT(installationFinished()), Qt::QueuedConnection); @@ -60,6 +54,7 @@ Wizard::InstallationPage::~InstallationPage() { if (mThread->isRunning()) { mUnshield->stopWorker(); + mThread->quit(); mThread->wait(); } diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 9daea2b71a..c8f7ca677c 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -45,9 +45,7 @@ Wizard::UnshieldWorker::~UnshieldWorker() void Wizard::UnshieldWorker::stopWorker() { - mMutex.lock(); mStopped = true; - mMutex.unlock(); } void Wizard::UnshieldWorker::setInstallComponent(Wizard::Component component, bool install) diff --git a/apps/wizard/unshield/unshieldworker.hpp b/apps/wizard/unshield/unshieldworker.hpp index c1d3cfff1f..3f922ad78a 100644 --- a/apps/wizard/unshield/unshieldworker.hpp +++ b/apps/wizard/unshield/unshieldworker.hpp @@ -104,7 +104,6 @@ namespace Wizard QTextCodec *mIniCodec; QWaitCondition mWait; - QMutex mMutex; QReadWriteLock mLock; From aa721fe1f662e9e9781b9522c26f2f4dd2994303 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Tue, 8 Dec 2015 22:38:26 +0100 Subject: [PATCH 1642/1812] Fix bug 2952 with merchant and levelled items --- AUTHORS.md | 1 + apps/openmw/mwworld/containerstore.cpp | 55 ++++++++++++++++++++------ components/esm/inventorystate.cpp | 17 ++++---- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e968d1d01a..077878ea21 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -74,6 +74,7 @@ Programmers Marco Melletti (mellotanica) Marco Schulze Mateusz Kołaczek (PL_kolek) + Mateusz Malisz (malice) megaton Michael Hogan (Xethik) Michael Mc Donnell diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 78a50b4e78..1130ec604c 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -415,6 +415,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { + if (count == 0) return; //Don't restock with nothing. try { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -463,8 +464,8 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { - //allowedForReplace - Holds information about how many items from the list were sold; - // Hence, tells us how many items we need to restock. + //allowedForReplace - Holds information about how many items from the list were not sold; + // Hence, tells us how many items we don't need to restock. //allowedForReplace[list] <- How many items we should generate(how many of these were sold) std::map allowedForReplace; @@ -473,20 +474,42 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { int spawnedCount = it->second.first; //How many items should be in shop originally int itemCount = count(it->first); //How many items are there in shop now - //If anything was sold - if(itemCount < spawnedCount) + //If something was not sold + if(itemCount >= spawnedCount) + { + const std::string& ancestor = it->second.second; + // Security check for old saves: + //If item is imported from old save(doesn't have an ancestor) and wasn't sold + if(ancestor == "") + { + //Remove it, from shop, + remove(it->first, itemCount, ptr);//ptr is the NPC + //And remove it from map, so that when we restock, the new item will have proper ancestor. + mLevelledItemMap.erase(it); + continue; + + } + //Create the entry if it does not exist yet + std::map::iterator listInMap = allowedForReplace.insert( + std::make_pair(it->second.second, 0)).first; + //And signal that we don't need to restock item from this list + listInMap->second += std::abs(itemCount); + } + //If every of the item was sold + else if (itemCount == 0) + { + mLevelledItemMap.erase(it); + } + //If some was sold, but some remain + else { //Create entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( std::make_pair(it->second.second, 0)).first; - //And signal that we need to restock item from this list - listInMap->second += std::abs(spawnedCount - itemCount); - //Also, remove the record if item no longer figures in the shop - if(!itemCount) - mLevelledItemMap.erase(it->first); - //If there's still item in the shop, change its spawnedCount to current count. - else - it->second.first -= itemCount; + //And signal that we don't need to restock all items from this list + listInMap->second += std::abs(itemCount); + //And update itemCount so we don't mistake it next time. + it->second.first = itemCount; } } @@ -504,8 +527,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { std::map::iterator listInMap = allowedForReplace.find(itemOrList); + + int restockNum = it-> mCount; + //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) - addInitialItem(itemOrList, owner, listInMap->second, true); + restockNum += listInMap->second;//We add, because list items have negative count + //restock + addInitialItem(itemOrList, owner, restockNum, true); + } else { diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 1864b6e8df..ad9e70af16 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -31,17 +31,20 @@ void ESM::InventoryState::load (ESMReader &esm) ++index; } - + //Next item is Levelled item while (esm.isNextSub("LEVM")) { + //Get its name std::string id = esm.getHString(); int count; - std::string parentList; - //TODO: How should I handle old saves? - if(esm.isNextSub("LLST")) - std::string parentList = esm.getHString(); + std::string parentGroup = ""; + //Then get its count esm.getHNT (count, "COUN"); - mLevelledItemMap[id] = count; + //Old save formats don't have information about parent group; check for that + if(esm.isNextSub("LGRP")) + //Newest saves contain parent group + parentGroup = esm.getHString(); + mLevelledItemMap[id] = std::make_pair(count, parentGroup); } while (esm.isNextSub("MAGI")) @@ -87,7 +90,7 @@ void ESM::InventoryState::save (ESMWriter &esm) const { esm.writeHNString ("LEVM", it->first); esm.writeHNT ("COUN", it->second.first); - esm.writeHNString("LLST", it->second.second) + esm.writeHNString("LGRP", it->second.second); } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) From b0e6a525956cbac9420624b619f4446528392c66 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Tue, 8 Dec 2015 22:45:16 +0100 Subject: [PATCH 1643/1812] Replace ancestor with parent --- apps/openmw/mwworld/containerstore.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 1130ec604c..99e051ea7a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -477,14 +477,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW //If something was not sold if(itemCount >= spawnedCount) { - const std::string& ancestor = it->second.second; + const std::string& parent = it->second.second; // Security check for old saves: - //If item is imported from old save(doesn't have an ancestor) and wasn't sold - if(ancestor == "") + //If item is imported from old save(doesn't have an parent) and wasn't sold + if(parent == "") { //Remove it, from shop, remove(it->first, itemCount, ptr);//ptr is the NPC - //And remove it from map, so that when we restock, the new item will have proper ancestor. + //And remove it from map, so that when we restock, the new item will have proper parent. mLevelledItemMap.erase(it); continue; From 39feb547a0892e27c256be1d7e20d67f14a6d266 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Dec 2015 23:12:40 +0100 Subject: [PATCH 1644/1812] Broken lower casing fix (Fixes #3068) --- components/interpreter/defines.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 3812e63c5a..2ceb857c40 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -35,8 +35,7 @@ namespace Interpreter{ if(text[i] == eschar) { retval << text.substr(start, i - start); - std::string temp = text.substr(i+1, 100); - Misc::StringUtils::lowerCase(temp); + std::string temp = Misc::StringUtils::lowerCase(text.substr(i+1, 100)); bool found = false; try From bc1f7499aba5d3793e5c09884a2572fd5aac604d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:26:39 +0100 Subject: [PATCH 1645/1812] Do not allow deleting the player object (Fixes #2982) --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2436225b40..e8855fa5c5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1073,6 +1073,9 @@ namespace MWWorld { if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) { + if (ptr == getPlayerPtr()) + throw std::runtime_error("can not delete player object"); + ptr.getRefData().setCount(0); if (ptr.isInCell() From 34f48d63f388a52443d1ba0d02bb485a216c0481 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:35:54 +0100 Subject: [PATCH 1646/1812] Apply spell absorption once per effect (Fixes #2942) --- apps/openmw/mwmechanics/spellcasting.cpp | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 2485091ea4..a2d32b3245 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -365,26 +365,6 @@ namespace MWMechanics bool castByPlayer = (!caster.isEmpty() && caster == getPlayer()); - // Try absorbing if it's a spell - // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure - // if that is worth replicating. - bool absorbed = false; - if (spell && caster != target && target.getClass().isActor()) - { - float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - absorbed = (Misc::Rng::roll0to99() < absorb); - if (absorbed) - { - const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); - MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( - "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); - // Magicka is increased by cost of spell - DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); - magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); - target.getClass().getCreatureStats(target).setMagicka(magicka); - } - } - for (std::vector::const_iterator effectIt (effects.mList.begin()); effectIt!=effects.mList.end(); ++effectIt) { @@ -404,6 +384,26 @@ namespace MWMechanics && target.getClass().isActor()) MWBase::Environment::get().getWindowManager()->setEnemy(target); + // Try absorbing if it's a spell + // NOTE: Vanilla does this once per spell absorption effect source instead of adding the % from all sources together, not sure + // if that is worth replicating. + bool absorbed = false; + if (spell && caster != target && target.getClass().isActor()) + { + float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); + absorbed = (Misc::Rng::roll0to99() < absorb); + if (absorbed) + { + const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); + MWBase::Environment::get().getWorld()->getAnimation(target)->addEffect( + "meshes\\" + absorbStatic->mModel, ESM::MagicEffect::SpellAbsorption, false, ""); + // Magicka is increased by cost of spell + DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); + magicka.setCurrent(magicka.getCurrent() + spell->mData.mCost); + target.getClass().getCreatureStats(target).setMagicka(magicka); + } + } + float magnitudeMult = 1; if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor()) { From a699b4128aaaa54a72f43875b451b273c59788d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 00:48:51 +0100 Subject: [PATCH 1647/1812] Add isInCell checks to PlaceAt and PlaceItem (Fixes #2873) Avoids the game crashing when a script calls these functions before the player has been moved to the starting location. --- apps/openmw/mwscript/transformationextensions.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 592168687a..474f2a392b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -458,6 +458,10 @@ namespace MWScript runtime.pop(); MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (!player.isInCell()) + throw std::runtime_error("player not in a cell"); + MWWorld::CellStore* store = NULL; if (player.getCell()->isExterior()) { @@ -505,6 +509,9 @@ namespace MWScript if (count<0) throw std::runtime_error ("count must be non-negative"); + if (!actor.isInCell()) + throw std::runtime_error ("actor is not in a cell"); + for (int i=0; i Date: Wed, 9 Dec 2015 01:06:53 +0100 Subject: [PATCH 1648/1812] WindowManager: explicitely pass the ESMStore Fixes potential crash when the loading screen layout tries to retrieve a GMST value via #{GMST} syntax before the World has been created. Possibly related to Bug #2854. --- apps/openmw/engine.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 29 ++++++++++++++++---------- apps/openmw/mwgui/windowmanagerimp.hpp | 9 ++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 66231dd987..6c360acf6e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -513,6 +513,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + window->setStore(mEnvironment.getWorld()->getStore()); window->initUI(); window->renderWorldMap(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 31522913ea..f151bee80b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -117,7 +117,8 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) - : mResourceSystem(resourceSystem) + : mStore(NULL) + , mResourceSystem(resourceSystem) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) , mCurrentModals() @@ -291,8 +292,7 @@ namespace MWGui bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); - mMessageBoxManager = new MessageBoxManager( - MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); mTradeWindow = new TradeWindow(); trackWindow(mTradeWindow, "barter"); @@ -461,6 +461,11 @@ namespace MWGui delete mGuiPlatform; } + void WindowManager::setStore(const MWWorld::ESMStore &store) + { + mStore = &store; + } + void WindowManager::cleanupGarbage() { // Delete any dialogs which are no longer in use @@ -908,8 +913,7 @@ namespace MWGui std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search(id); + const ESM::GameSetting *setting = mStore->get().search(id); if (setting && setting->mValue.getType()==ESM::VT_String) return setting->mValue.getString(); @@ -1139,8 +1143,12 @@ namespace MWGui } else { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(tag); + if (!mStore) + { + std::cerr << "WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'" << std::endl; + return; + } + const ESM::GameSetting *setting = mStore->get().find(tag); if (setting && setting->mValue.getType()==ESM::VT_String) _result = setting->mValue.getString(); @@ -1263,8 +1271,7 @@ namespace MWGui mSelectedSpell = spellId; mHud->setSelectedSpell(spellId, successChancePercent); - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + const ESM::Spell* spell = mStore->get().find(spellId); mSpellWindow->setTitle(spell->mName); } @@ -1272,7 +1279,7 @@ namespace MWGui void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { mSelectedSpell = ""; - const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + const ESM::Enchantment* ench = mStore->get() .find(item.getClass().getEnchantment(item)); int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 @@ -1707,7 +1714,7 @@ namespace MWGui { reader.getSubNameIs("ID__"); std::string spell = reader.getHString(); - if (MWBase::Environment::get().getWorld()->getStore().get().search(spell)) + if (mStore->get().search(spell)) mSelectedSpell = spell; } else if (type == ESM::REC_MARK) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7df5508a16..6edb4660cf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -28,6 +28,11 @@ namespace MyGUI class ImageBox; } +namespace MWWorld +{ + class ESMStore; +} + namespace Compiler { class Extensions; @@ -119,6 +124,9 @@ namespace MWGui Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); virtual ~WindowManager(); + /// Set the ESMStore to use for retrieving of GUI-related strings. + void setStore (const MWWorld::ESMStore& store); + void initUI(); void renderWorldMap(); @@ -372,6 +380,7 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); private: + const MWWorld::ESMStore* mStore; Resource::ResourceSystem* mResourceSystem; osgMyGUI::Platform* mGuiPlatform; From 6f98982bc2365631682cbafcdedf2c28c1e17779 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 01:52:20 +0100 Subject: [PATCH 1649/1812] Make sure that health is >= 1 when resurrecting the player (Fixes #2972) --- apps/openmw/mwmechanics/creaturestats.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 602e54a090..6933c40a3f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -267,9 +267,11 @@ namespace MWMechanics { if (mDead) { + if (mDynamic[0].getModified() < 1) + mDynamic[0].setModified(1, 0); + mDynamic[0].setCurrent(mDynamic[0].getModified()); - if (mDynamic[0].getCurrent()>=1) - mDead = false; + mDead = false; } } From de84452e5a2f1a51d5e08f9af65edcec80a9c995 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 04:50:59 +0100 Subject: [PATCH 1650/1812] NifFile: close the stream after reading (Fixes #3070) --- components/nif/niffile.cpp | 8 +++----- components/nif/niffile.hpp | 4 +--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index ccfcdfc73c..f6e489527e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -12,9 +12,8 @@ NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) : ver(0) , filename(name) , mUseSkinning(false) - , mStream(stream) { - parse(); + parse(stream); } NIFFile::~NIFFile() @@ -115,7 +114,6 @@ static std::map makeFactory() ///Make the factory map used for parsing the file static const std::map factories = makeFactory(); -/// Get the file's version in a human readable form std::string NIFFile::printVersion(unsigned int version) { union ver_quad @@ -134,9 +132,9 @@ std::string NIFFile::printVersion(unsigned int version) return stream.str(); } -void NIFFile::parse() +void NIFFile::parse(Files::IStreamPtr stream) { - NIFStream nif (this, mStream); + NIFStream nif (this, stream); // Check the header string std::string head = nif.getVersionString(); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6fbef31ca6..900c360bb8 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -35,7 +35,7 @@ class NIFFile bool mUseSkinning; /// Parse the file - void parse(); + void parse(Files::IStreamPtr stream); /// Get the file's version in a human readable form ///\returns A string containing a human readable NIF version number @@ -46,8 +46,6 @@ class NIFFile ///\overload void operator = (NIFFile const &); - Files::IStreamPtr mStream; - public: /// Used if file parsing fails void fail(const std::string &msg) From d00d487c3d66ab96f5944112a3d1f882071e8f41 Mon Sep 17 00:00:00 2001 From: cfcohen Date: Mon, 7 Dec 2015 20:03:11 -0500 Subject: [PATCH 1651/1812] Improved error reporting under POSIX using errno and strerror(). --- components/files/lowlevelfile.cpp | 40 +++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 8456c7a26d..169a6f8131 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #endif #if FILE_API == FILE_API_STDIO @@ -139,7 +141,7 @@ void LowLevelFile::open (char const * filename) if (mHandle == -1) { std::ostringstream os; - os << "Failed to open '" << filename << "' for reading."; + os << "Failed to open '" << filename << "' for reading: " << strerror(errno); throw std::runtime_error (os.str ()); } } @@ -160,15 +162,27 @@ size_t LowLevelFile::size () size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR); if (oldPosition == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } size_t Size = ::lseek (mHandle, 0, SEEK_END); if (Size == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } if (lseek (mHandle, oldPosition, SEEK_SET) == -1) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return Size; } @@ -178,7 +192,11 @@ void LowLevelFile::seek (size_t Position) assert (mHandle != -1); if (::lseek (mHandle, Position, SEEK_SET) == -1) - throw std::runtime_error ("A seek operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } } size_t LowLevelFile::tell () @@ -188,7 +206,11 @@ size_t LowLevelFile::tell () size_t Position = ::lseek (mHandle, 0, SEEK_CUR); if (Position == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + { + std::ostringstream os; + os << "An lseek() call failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return Position; } @@ -200,7 +222,11 @@ size_t LowLevelFile::read (void * data, size_t size) int amount = ::read (mHandle, data, size); if (amount == -1) - throw std::runtime_error ("A read operation on a file failed."); + { + std::ostringstream os; + os << "An attempt to read " << size << "bytes failed:" << strerror(errno); + throw std::runtime_error (os.str ()); + } return amount; } From a8c287c8314e79b5628066dd975d22dae9095f07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 14:33:02 +0100 Subject: [PATCH 1652/1812] Print detected game controllers to the log file --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0d1dc0e625..71938dfb04 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -119,10 +119,11 @@ namespace MWInput SDL_ControllerDeviceEvent evt; evt.which = i; controllerAdded(mFakeDeviceID, evt); + std::cout << "Detected game controller: " << SDL_GameControllerNameForIndex(i) << std::endl; } else { - //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + std::cout << "Detected unusable controller: " << SDL_JoystickNameForIndex(i) << std::endl; } } From 3b254ad6319a6687dcbf3b7e4f10679a7cceb259 Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Wed, 9 Dec 2015 18:24:35 +0100 Subject: [PATCH 1653/1812] Allows the same item to have multiple ancestors --- apps/openmw/mwworld/containerstore.cpp | 34 +++++++++++++------------- apps/openmw/mwworld/containerstore.hpp | 4 +-- components/esm/inventorystate.cpp | 10 ++++---- components/esm/inventorystate.hpp | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 99e051ea7a..5844cfa9a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -444,12 +444,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (!levItem.empty() && count < 0) { //If there is no item in map, insert it - std::map >::iterator itemInMap = - mLevelledItemMap.insert(std::make_pair(id, std::make_pair(0, levItem))).first; + std::map, int>::iterator itemInMap = + mLevelledItemMap.insert(std::make_pair(std::make_pair(id, levItem), 0)).first; //Update spawned count - itemInMap->second.first += std::abs(count); + itemInMap->second += std::abs(count); } - count = std::abs(count); + count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); addImp (ref.getPtr(), count); @@ -470,47 +470,48 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW std::map allowedForReplace; //Check which lists need restocking: - for (std::map >::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end();) { - int spawnedCount = it->second.first; //How many items should be in shop originally - int itemCount = count(it->first); //How many items are there in shop now + int spawnedCount = it->second; //How many items should be in shop originally + int itemCount = count(it->first.first); //How many items are there in shop now //If something was not sold if(itemCount >= spawnedCount) { - const std::string& parent = it->second.second; + const std::string& parent = it->first.second; // Security check for old saves: //If item is imported from old save(doesn't have an parent) and wasn't sold if(parent == "") { //Remove it, from shop, - remove(it->first, itemCount, ptr);//ptr is the NPC + remove(it->first.first, itemCount, ptr);//ptr is the NPC //And remove it from map, so that when we restock, the new item will have proper parent. - mLevelledItemMap.erase(it); + mLevelledItemMap.erase(it++); continue; - } //Create the entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( - std::make_pair(it->second.second, 0)).first; + std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock item from this list listInMap->second += std::abs(itemCount); } //If every of the item was sold else if (itemCount == 0) { - mLevelledItemMap.erase(it); + mLevelledItemMap.erase(it++); + continue; } //If some was sold, but some remain else { //Create entry if it does not exist yet std::map::iterator listInMap = allowedForReplace.insert( - std::make_pair(it->second.second, 0)).first; + std::make_pair(it->first.second, 0)).first; //And signal that we don't need to restock all items from this list listInMap->second += std::abs(itemCount); //And update itemCount so we don't mistake it next time. - it->second.first = itemCount; + it->second = itemCount; } + ++it; } //Restock: @@ -528,13 +529,12 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { std::map::iterator listInMap = allowedForReplace.find(itemOrList); - int restockNum = it-> mCount; + int restockNum = it->mCount; //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) restockNum += listInMap->second;//We add, because list items have negative count //restock addInitialItem(itemOrList, owner, restockNum, true); - } else { diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index aaf83755a3..876821f94d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -69,8 +69,8 @@ namespace MWWorld MWWorld::CellRefList repairs; MWWorld::CellRefList weapons; - std::map > mLevelledItemMap; - ///< Stores result of levelled item spawns. + std::map, int> mLevelledItemMap; + ///< Stores result of levelled item spawns. <(refId, spawningGroup), count> /// This is used to restock levelled items(s) if the old item was sold. mutable float mCachedWeight; diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index ad9e70af16..b24128ec35 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -44,7 +44,7 @@ void ESM::InventoryState::load (ESMReader &esm) if(esm.isNextSub("LGRP")) //Newest saves contain parent group parentGroup = esm.getHString(); - mLevelledItemMap[id] = std::make_pair(count, parentGroup); + mLevelledItemMap[std::make_pair(id, parentGroup)] = count; } while (esm.isNextSub("MAGI")) @@ -86,11 +86,11 @@ void ESM::InventoryState::save (ESMWriter &esm) const iter->save (esm, true); } - for (std::map >::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + for (std::map, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { - esm.writeHNString ("LEVM", it->first); - esm.writeHNT ("COUN", it->second.first); - esm.writeHNString("LGRP", it->second.second); + esm.writeHNString ("LEVM", it->first.first); + esm.writeHNT ("COUN", it->second); + esm.writeHNString("LGRP", it->first.second); } for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it) diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index a12be321ff..f4bb0ab487 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -20,7 +20,7 @@ namespace ESM // std::map mEquipmentSlots; - std::map > mLevelledItemMap; + std::map, int> mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From ddd4004c959252871aa5b0e8487322c2c25406ff Mon Sep 17 00:00:00 2001 From: MatthewRock Date: Wed, 9 Dec 2015 18:26:33 +0100 Subject: [PATCH 1654/1812] Fix: remove space --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5844cfa9a4..b45e7ef833 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -449,7 +449,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: //Update spawned count itemInMap->second += std::abs(count); } - count = std::abs(count); + count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); addImp (ref.getPtr(), count); From 9bc6f2d5f65866095e690332dacc8b7e56baf345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 20:35:51 +0100 Subject: [PATCH 1655/1812] Fix water ripples --- apps/openmw/mwrender/ripplesimulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 766e20fc4e..7439bfc702 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -127,7 +127,6 @@ void RippleSimulation::update(float dt) } osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); - currentPos.z() = 0; // Z is set by the Scene Node if ( (currentPos - it->mLastEmitPosition).length() > 10 // Only emit when close to the water surface, not above it and not too deep in the water @@ -136,6 +135,8 @@ void RippleSimulation::update(float dt) { it->mLastEmitPosition = currentPos; + currentPos.z() = mParticleNode->getPosition().z(); + if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) continue; // TODO: remove the oldest particle to make room? From 293f3f30b55fd0fae690887c05e9d577a869e628 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Dec 2015 23:30:24 +0100 Subject: [PATCH 1656/1812] Indentation fix --- components/sdlutil/sdlcursormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 0eb161a64d..26b0510dc1 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -218,7 +218,7 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { #ifdef ANDROID - return; + return; #endif if (mCursorMap.find(name) != mCursorMap.end()) From eb92b853fed11e93b4f954ce58bab793e8ade85a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Dec 2015 00:05:35 +0100 Subject: [PATCH 1657/1812] BulletNifLoader: preallocate the btTriangleMesh's vertices/indices --- components/nifbullet/bulletnifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 0b8e9c1638..19afe49d63 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -319,6 +319,9 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Vec3Array& vertices = *data->vertices; const osg::DrawElementsUShort& triangles = *data->triangles; + mStaticMesh->preallocateVertices(data->vertices->size()); + mStaticMesh->preallocateIndices(data->triangles->size()); + size_t numtris = data->triangles->size(); for(size_t i = 0;i < numtris;i+=3) { From 0efce6cd4ccb519ae563e0f6229f7f5c07eaf4d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Dec 2015 00:15:55 +0100 Subject: [PATCH 1658/1812] Fix typo in a comment --- components/to_utf8/to_utf8.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index d7f9c3a382..8af0bc5ed8 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -85,10 +85,10 @@ std::string Utf8Encoder::getUtf8(const char* input, size_t size) assert(input[size] == 0); // Note: The rest of this function is designed for single-character - // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. There are - // no plans to add more encodings to this module (we are using utf8 - // for new content files), so that shouldn't be an issue. + // input encodings only. It also assumes that the input encoding + // shares its first 128 values (0-127) with ASCII. There are no plans + // to add more encodings to this module (we are using utf8 for new + // content files), so that shouldn't be an issue. // Compute output length, and check for pure ascii input at the same // time. From 9ca5a1b64735fd3395fe548610b5d45abfcd8b04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 10:58:38 +0100 Subject: [PATCH 1659/1812] added double settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/doublesetting.cpp | 69 +++++++++++++++++++++++ apps/opencs/model/prefs/doublesetting.hpp | 39 +++++++++++++ apps/opencs/model/prefs/state.cpp | 36 ++++++++++++ apps/opencs/model/prefs/state.hpp | 2 + 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/prefs/doublesetting.cpp create mode 100644 apps/opencs/model/prefs/doublesetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 003fd657b7..2fce48fd5e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting + state setting intsetting doublesetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/doublesetting.cpp b/apps/opencs/model/prefs/doublesetting.cpp new file mode 100644 index 0000000000..2eabc78bf5 --- /dev/null +++ b/apps/opencs/model/prefs/doublesetting.cpp @@ -0,0 +1,69 @@ + +#include "doublesetting.hpp" + +#include + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::DoubleSetting::DoubleSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, double default_) +: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + mDefault (default_) +{} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setRange (double min, double max) +{ + mMin = min; + mMax = max; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setMin (double min) +{ + mMin = min; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setMax (double max) +{ + mMax = max; + return *this; +} + +CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::DoubleSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QDoubleSpinBox *widget = new QDoubleSpinBox (parent); + widget->setRange (mMin, mMax); + widget->setValue (mDefault); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (valueChanged (double)), this, SLOT (valueChanged (double))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::DoubleSetting::valueChanged (double value) +{ + getValues().setFloat (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp new file mode 100644 index 0000000000..ef432aeb7d --- /dev/null +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_PREFS_DOUBLESETTING_H +#define CSM_PREFS_DOUBLESETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class DoubleSetting : public Setting + { + Q_OBJECT + + double mMin; + double mMax; + std::string mTooltip; + double mDefault; + + public: + + DoubleSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, double default_); + + DoubleSetting& setRange (double min, double max); + + DoubleSetting& setMin (double min); + + DoubleSetting& setMax (double max); + + DoubleSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (double value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index dfc4605285..6ade42546b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -6,6 +6,7 @@ #include #include "intsetting.hpp" +#include "doublesetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -81,6 +82,21 @@ void CSMPrefs::State::declare() declareCategory ("General Input"); declareCategory ("3D Scene Input"); + // p-navi + // s-navi + // p-edit + // s-edit + // p-select + // s-select + // context-select + declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). + setRange (0.001, 100.0); + declareDouble ("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0). + setRange (0.001, 100.0); + declareDouble ("drag-shift-factor", + "Shift-acceleration factor during drag operations", 4.0). + setTooltip ("Acceleration factor during drag operations while holding down shift"). + setRange (0.001, 100.0); declareCategory ("Tooltips"); // scene @@ -124,6 +140,26 @@ CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, return *setting; } +CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, + const std::string& label, double default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::ostringstream stream; + stream << default_; + setDefault (key, stream.str()); + + default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey()); + + CSMPrefs::DoubleSetting *setting = + new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index c38f42049f..816f383ff7 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -18,6 +18,7 @@ namespace CSMPrefs { class IntSetting; + class DoubleSetting; class State : public QObject { @@ -51,6 +52,7 @@ namespace CSMPrefs void declareCategory (const std::string& key); IntSetting& declareInt (const std::string& key, const std::string& label, int default_); + DoubleSetting& declareDouble (const std::string& key, const std::string& label, double default_); void setDefault (const std::string& key, const std::string& default_); From b0fb6d56f12981895671f28fc255f8ca9c606018 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 13:28:48 +0100 Subject: [PATCH 1660/1812] added bool settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/boolsetting.cpp | 42 +++++++++++++++ apps/opencs/model/prefs/boolsetting.hpp | 31 +++++++++++ apps/opencs/model/prefs/state.cpp | 69 +++++++++++++++++++++---- apps/opencs/model/prefs/state.hpp | 3 ++ apps/opencs/view/prefs/page.cpp | 2 +- 6 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/model/prefs/boolsetting.cpp create mode 100644 apps/opencs/model/prefs/boolsetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 2fce48fd5e..e2f9205ea5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting + state setting intsetting doublesetting boolsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/boolsetting.cpp b/apps/opencs/model/prefs/boolsetting.cpp new file mode 100644 index 0000000000..459993325a --- /dev/null +++ b/apps/opencs/model/prefs/boolsetting.cpp @@ -0,0 +1,42 @@ + +#include "boolsetting.hpp" + +#include + +#include + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::BoolSetting::BoolSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, bool default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::BoolSetting::makeWidgets (QWidget *parent) +{ + QCheckBox *widget = new QCheckBox (QString::fromUtf8 (getLabel().c_str()), parent); + widget->setCheckState (mDefault ? Qt::Checked : Qt::Unchecked); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (stateChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (static_cast (0), widget); +} + +void CSMPrefs::BoolSetting::valueChanged (int value) +{ + getValues().setBool (getKey(), getParent()->getKey(), value); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/boolsetting.hpp b/apps/opencs/model/prefs/boolsetting.hpp new file mode 100644 index 0000000000..dfc28c5aeb --- /dev/null +++ b/apps/opencs/model/prefs/boolsetting.hpp @@ -0,0 +1,31 @@ +#ifndef CSM_PREFS_BOOLSETTING_H +#define CSM_PREFS_BOOLSETTING_H + +#include "setting.hpp" + +namespace CSMPrefs +{ + class BoolSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + bool mDefault; + + public: + + BoolSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, bool default_); + + BoolSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 6ade42546b..cf58edce96 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -7,6 +7,7 @@ #include "intsetting.hpp" #include "doublesetting.hpp" +#include "boolsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -39,24 +40,47 @@ void CSMPrefs::State::declare() declareInt ("default-height", "Default window height", 600). setTooltip ("Newly opened top-level windows will open with this height."). setMin (80); - // reuse - // show-statusbar + declareBool ("reuse", "Reuse Subviews", true). + setTooltip ("When a new subview is requested and a matching subview already " + " exist, do not open a new subview and use the existing one instead."); + declareBool ("show-statusbar", "Show Status Bar", true). + setTooltip ("If a newly open top level window is showing status bars or not. " + " Note that this does not affect existing windows."); declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). setTooltip ("If the maximum number is reached and a new subview is opened " "it will be placed into a new top-level window."). setRange (1, 256); - // hide-subview + declareBool ("hide-subview", "Hide single subview", false). + setTooltip ("When a view contains only a single subview, hide the subview title " + "bar and if this subview is closed also close the view (unless it is the last " + "view for this document)"); declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); // mainwindow-scrollbar - // grow-limit + declareBool ("grow-limit", "Grow Limit Screen", false). + setTooltip ("When \"Grow then Scroll\" option is selected, the window size grows to" + " the width of the virtual desktop. \nIf this option is selected the the window growth" + "is limited to the current screen."); declareCategory ("Records"); declareCategory ("ID Tables"); + // double + // double-s + // double-c + // double-sc + // jump-to-added + declareBool ("extended-config", + "Manually specify affected record types for an extended delete/revert", false). + setTooltip ("Delete and revert commands have an extended form that also affects " + "associated records.\n\n" + "If this option is enabled, types of affected records are selected " + "manually before a command execution.\nOtherwise, all associated " + "records are deleted/reverted immediately."); declareCategory ("ID Dialogues"); + declareBool ("toolbar", "Show toolbar", true); declareCategory ("Reports"); @@ -65,13 +89,15 @@ void CSMPrefs::State::declare() setTooltip ("Maximum number of character to display in search result before the searched text"); declareInt ("char-after", "Characters after search string", 10). setTooltip ("Maximum number of character to display in search result after the searched text"); - // auto-delete + declareBool ("auto-delete", "Delete row from result table after a successful replace", true); declareCategory ("Scripts"); - // show-linenum - // mono-font + declareBool ("show-linenum", "Show Line Numbers", true). + setTooltip ("Show line numbers to the left of the script editor window." + "The current row and column numbers of the text cursor are shown at the bottom."); + declareBool ("mono-font", "Use monospace font", true); // warnings - // toolbar + declareBool ("toolbar", "Show toolbar", true); declareInt ("compile-delay", "Delay between updating of source errors", 100). setTooltip ("Delay in milliseconds"). setRange (0, 10000); @@ -80,6 +106,9 @@ void CSMPrefs::State::declare() // syntax-colouring declareCategory ("General Input"); + declareBool ("cycle", "Cyclic next/previous", false). + setTooltip ("When using next/previous functions at the last/first item of a " + "list go to the first/last item"); declareCategory ("3D Scene Input"); // p-navi @@ -88,7 +117,7 @@ void CSMPrefs::State::declare() // s-edit // p-select // s-select - // context-select + declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); declareDouble ("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0). @@ -99,8 +128,8 @@ void CSMPrefs::State::declare() setRange (0.001, 100.0); declareCategory ("Tooltips"); - // scene - // scene-hide-basic + declareBool ("scene", "Show Tooltips in 3D scenes", true); + declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); } @@ -160,6 +189,24 @@ CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, return *setting; } +CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, + const std::string& label, bool default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_ ? "true" : "false"); + + default_ = mSettings.getBool (key, mCurrentCategory->second.getKey()); + + CSMPrefs::BoolSetting *setting = + new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 816f383ff7..28bafd6a18 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs { class IntSetting; class DoubleSetting; + class BoolSetting; class State : public QObject { @@ -54,6 +55,8 @@ namespace CSMPrefs IntSetting& declareInt (const std::string& key, const std::string& label, int default_); DoubleSetting& declareDouble (const std::string& key, const std::string& label, double default_); + BoolSetting& declareBool (const std::string& key, const std::string& label, bool default_); + void setDefault (const std::string& key, const std::string& default_); public: diff --git a/apps/opencs/view/prefs/page.cpp b/apps/opencs/view/prefs/page.cpp index 181ae40fac..c23e9f64fe 100644 --- a/apps/opencs/view/prefs/page.cpp +++ b/apps/opencs/view/prefs/page.cpp @@ -31,7 +31,7 @@ void CSVPrefs::Page::addSetting (CSMPrefs::Setting *setting) } else if (widgets.second) { - mGrid->addWidget (widgets.second, next, 0, next, 1); + mGrid->addWidget (widgets.second, next, 0, 1, 2); } else { From 8050eba83b3c4a549c6b5223690c8fe08ec14136 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 13:33:44 +0100 Subject: [PATCH 1661/1812] added a few comments --- apps/opencs/model/prefs/doublesetting.hpp | 1 + apps/opencs/model/prefs/intsetting.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp index ef432aeb7d..d0735d30ad 100644 --- a/apps/opencs/model/prefs/doublesetting.hpp +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs DoubleSetting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label, double default_); + // defaults to [0, std::numeric_limits::max()] DoubleSetting& setRange (double min, double max); DoubleSetting& setMin (double min); diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp index 314e68b372..05acb9fbc0 100644 --- a/apps/opencs/model/prefs/intsetting.hpp +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -19,6 +19,7 @@ namespace CSMPrefs IntSetting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label, int default_); + // defaults to [0, std::numeric_limits::max()] IntSetting& setRange (int min, int max); IntSetting& setMin (int min); From 590d6eba9b4b4e95775957f74605393daa32ab8a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Dec 2015 17:33:14 +0100 Subject: [PATCH 1662/1812] added enum settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/enumsetting.cpp | 107 ++++++++++++++++++++++++ apps/opencs/model/prefs/enumsetting.hpp | 61 ++++++++++++++ apps/opencs/model/prefs/state.cpp | 90 +++++++++++++++++--- apps/opencs/model/prefs/state.hpp | 3 + 5 files changed, 249 insertions(+), 14 deletions(-) create mode 100644 apps/opencs/model/prefs/enumsetting.cpp create mode 100644 apps/opencs/model/prefs/enumsetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e2f9205ea5..b51cfb52fc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting + state setting intsetting doublesetting boolsetting enumsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/enumsetting.cpp b/apps/opencs/model/prefs/enumsetting.cpp new file mode 100644 index 0000000000..ea7d0703ea --- /dev/null +++ b/apps/opencs/model/prefs/enumsetting.cpp @@ -0,0 +1,107 @@ + +#include "enumsetting.hpp" + +#include +#include + +#include + +#include "category.hpp" +#include "state.hpp" + + +CSMPrefs::EnumValue::EnumValue (const std::string& value, const std::string& tooltip) +: mValue (value), mTooltip (tooltip) +{} + +CSMPrefs::EnumValue::EnumValue (const char *value) +: mValue (value) +{} + + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const EnumValues& values) +{ + mValues.insert (mValues.end(), values.mValues.begin(), values.mValues.end()); + return *this; +} + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const EnumValue& value) +{ + mValues.push_back (value); + return *this; +} + +CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const std::string& tooltip) +{ + mValues.push_back (EnumValue (value, tooltip)); + return *this; +} + + +CSMPrefs::EnumSetting::EnumSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, const EnumValue& default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValues (const EnumValues& values) +{ + mValues.add (values); + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue (const EnumValue& value) +{ + mValues.add (value); + return *this; +} + +CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue (const std::string& value, const std::string& tooltip) +{ + mValues.add (value, tooltip); + return *this; +} + +std::pair CSMPrefs::EnumSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + QComboBox *widget = new QComboBox (parent); + + int index = 0; + + for (int i=0; i (mValues.mValues.size()); ++i) + { + if (mDefault.mValue==mValues.mValues[i].mValue) + index = i; + + widget->addItem (QString::fromUtf8 (mValues.mValues[i].mValue.c_str())); + + if (!mValues.mValues[i].mTooltip.empty()) + widget->setItemData (i, QString::fromUtf8 (mValues.mValues[i].mTooltip.c_str()), + Qt::ToolTipRole); + } + + widget->setCurrentIndex (index); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + } + + connect (widget, SIGNAL (currentIndexChanged (int)), this, SLOT (valueChanged (int))); + + return std::make_pair (label, widget); +} + +void CSMPrefs::EnumSetting::valueChanged (int value) +{ + getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/enumsetting.hpp b/apps/opencs/model/prefs/enumsetting.hpp new file mode 100644 index 0000000000..e2102d20eb --- /dev/null +++ b/apps/opencs/model/prefs/enumsetting.hpp @@ -0,0 +1,61 @@ +#ifndef CSM_PREFS_ENUMSETTING_H +#define CSM_PREFS_ENUMSETTING_H + +#include + +#include "setting.hpp" + +namespace CSMPrefs +{ + struct EnumValue + { + std::string mValue; + std::string mTooltip; + + EnumValue (const std::string& value, const std::string& tooltip = ""); + + EnumValue (const char *value); + }; + + struct EnumValues + { + std::vector mValues; + + EnumValues& add (const EnumValues& values); + + EnumValues& add (const EnumValue& value); + + EnumValues& add (const std::string& value, const std::string& tooltip); + }; + + class EnumSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + EnumValue mDefault; + EnumValues mValues; + + public: + + EnumSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, const EnumValue& default_); + + EnumSetting& setTooltip (const std::string& tooltip); + + EnumSetting& addValues (const EnumValues& values); + + EnumSetting& addValue (const EnumValue& value); + + EnumSetting& addValue (const std::string& value, const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged (int value); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index cf58edce96..99449309cc 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -57,20 +57,44 @@ void CSMPrefs::State::declare() declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); - // mainwindow-scrollbar + EnumValue scrollbarOnly ("Scrollbar Only", "Simple addition of scrollbars, the view window " + "does not grow automatically."); + declareEnum ("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly). + addValue (scrollbarOnly). + addValue ("Grow Only", "The view window grows as subviews are added. No scrollbars."). + addValue ("Grow then Scroll", "The view window grows. The scrollbar appears once it cannot grow any further."); declareBool ("grow-limit", "Grow Limit Screen", false). setTooltip ("When \"Grow then Scroll\" option is selected, the window size grows to" " the width of the virtual desktop. \nIf this option is selected the the window growth" "is limited to the current screen."); declareCategory ("Records"); + EnumValue iconAndText ("Icon and Text"); + EnumValues recordValues; + recordValues.add (iconAndText).add ("Icon Only").add ("Text only"); + declareEnum ("status-format", "Modification status display format", iconAndText). + addValues (recordValues); + declareEnum ("type-format", "ID type display format", iconAndText). + addValues (recordValues); declareCategory ("ID Tables"); - // double - // double-s - // double-c - // double-sc - // jump-to-added + EnumValue inPlaceEdit ("Edit in Place", "Edit the clicked cell"); + EnumValue editRecord ("Edit Record", "Open a dialogue subview for the clicked record"); + EnumValue view ("View", "Open a scene subview for the clicked record (not available everywhere)"); + EnumValue editRecordAndClose ("Edit Record and Close"); + EnumValues doubleClickValues; + doubleClickValues.add (inPlaceEdit).add (editRecord).add (view).add ("Revert"). + add ("Delete").add (editRecordAndClose). + add ("View and Close", "Open a scene subview for the clicked record and close the table subview"); + declareEnum ("double", "Double Click", inPlaceEdit).addValues (doubleClickValues); + declareEnum ("double-s", "Shift Double Click", editRecord).addValues (doubleClickValues); + declareEnum ("double-c", "Control Double Click", view).addValues (doubleClickValues); + declareEnum ("double-sc", "Shift Control Double Click", editRecordAndClose).addValues (doubleClickValues); + EnumValue jumpAndSelect ("Jump and Select", "Scroll new record into view and make it the selection"); + declareEnum ("jump-to-added", "Action on adding or cloning a record", jumpAndSelect). + addValue (jumpAndSelect). + addValue ("Jump Only", "Scroll new record into view"). + addValue ("No Jump", "No special action"); declareBool ("extended-config", "Manually specify affected record types for an extended delete/revert", false). setTooltip ("Delete and revert commands have an extended form that also affects " @@ -83,6 +107,16 @@ void CSMPrefs::State::declare() declareBool ("toolbar", "Show toolbar", true); declareCategory ("Reports"); + EnumValue actionNone ("None"); + EnumValue actionEdit ("Edit", "Open a table or dialogue suitable for addressing the listed report"); + EnumValue actionRemove ("Remove", "Remove the report from the report table"); + EnumValue actionEditAndRemove ("Edit And Remove", "Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table"); + EnumValues reportValues; + reportValues.add (actionNone).add (actionEdit).add (actionRemove).add (actionEditAndRemove); + declareEnum ("double", "Double Click", actionEdit).addValues (reportValues); + declareEnum ("double-s", "Shift Double Click", actionRemove).addValues (reportValues); + declareEnum ("double-c", "Control Double Click", actionEditAndRemove).addValues (reportValues); + declareEnum ("double-sc", "Shift Control Double Click", actionNone).addValues (reportValues); declareCategory ("Search & Replace"); declareInt ("char-before", "Characters before search string", 10). @@ -96,7 +130,11 @@ void CSMPrefs::State::declare() setTooltip ("Show line numbers to the left of the script editor window." "The current row and column numbers of the text cursor are shown at the bottom."); declareBool ("mono-font", "Use monospace font", true); - // warnings + EnumValue warningsNormal ("Normal", "Report warnings as warning"); + declareEnum ("warnings", "Warning Mode", warningsNormal). + addValue ("Ignore", "Do not report warning"). + addValue (warningsNormal). + addValue ("Strcit", "Promote warning to an error"); declareBool ("toolbar", "Show toolbar", true); declareInt ("compile-delay", "Delay between updating of source errors", 100). setTooltip ("Delay in milliseconds"). @@ -111,12 +149,20 @@ void CSMPrefs::State::declare() "list go to the first/last item"); declareCategory ("3D Scene Input"); - // p-navi - // s-navi - // p-edit - // s-edit - // p-select - // s-select + EnumValue left ("Left Mouse-Button"); + EnumValue cLeft ("Ctrl-Left Mouse-Button"); + EnumValue right ("Right Mouse-Button"); + EnumValue cRight ("Ctrl-Right Mouse-Button"); + EnumValue middle ("Middle Mouse-Button"); + EnumValue cMiddle ("Ctrl-Middle Mouse-Button"); + EnumValues inputButtons; + inputButtons.add (left).add (cLeft).add (right).add (cRight).add (middle).add (cMiddle); + declareEnum ("p-navi", "Primary Camera Navigation Button", left).addValues (inputButtons); + declareEnum ("s-navi", "Secondary Camera Navigation Button", cLeft).addValues (inputButtons); + declareEnum ("p-edit", "Primary Editing Button", right).addValues (inputButtons); + declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons); + declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons); + declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); @@ -207,6 +253,24 @@ CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, return *setting; } +CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, + const std::string& label, EnumValue default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_.mValue); + + default_.mValue = mSettings.getString (key, mCurrentCategory->second.getKey()); + + CSMPrefs::EnumSetting *setting = + new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 28bafd6a18..e4de7fcff3 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -14,6 +14,7 @@ #include "category.hpp" #include "setting.hpp" +#include "enumsetting.hpp" namespace CSMPrefs { @@ -57,6 +58,8 @@ namespace CSMPrefs BoolSetting& declareBool (const std::string& key, const std::string& label, bool default_); + EnumSetting& declareEnum (const std::string& key, const std::string& label, EnumValue default_); + void setDefault (const std::string& key, const std::string& default_); public: From f1f82af64ee25290b0971214e9bede59dfa74f5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 01:24:33 +0100 Subject: [PATCH 1663/1812] Fix improper swimming animations in first person mode --- apps/openmw/mwmechanics/character.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f7f355a389..10c20e65de 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -397,10 +397,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - if (weap != sWeaponTypeListEnd) - movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName.erase(swimpos, 4); - if(!mAnimation->hasAnimation(movementAnimName)) + if (weap != sWeaponTypeListEnd) + { + std::string weapMovementAnimName = movementAnimName + weap->shortgroup; + if(mAnimation->hasAnimation(weapMovementAnimName)) + movementAnimName = weapMovementAnimName; + else + movemask = MWRender::Animation::BlendMask_LowerBody; + } + + if (!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); } } From a00a4bce77ebec91438e908845efa921eff55b3f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 15:37:39 -0800 Subject: [PATCH 1664/1812] Avoid some unnecessary indirection --- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d12174e207..c568ef7780 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -221,7 +221,7 @@ namespace MWSound { DecoderPtr decoder = getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - if(decoder->mResourceMgr->exists(voicefile)) + if(mVFS->exists(voicefile)) decoder->open(voicefile); else { From a47bdecac77d78f3b06759f853d70bac5cd6b7eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 17:47:55 -0800 Subject: [PATCH 1665/1812] Add missing include Since Ptr is used directly in the header, a forward declaration isn't good enough. --- apps/openmw/mwworld/cellstore.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index b08349293f..5d1685c280 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -35,6 +35,7 @@ #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld #include "timestamp.hpp" +#include "ptr.hpp" namespace ESM { @@ -45,10 +46,8 @@ namespace ESM namespace MWWorld { - class Ptr; class ESMStore; - /// \brief Mutable state of a cell class CellStore { From 808f7010138454f7b86bc059557a6aa3a11937f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 17:48:45 -0800 Subject: [PATCH 1666/1812] Use the actor's Head position for Say streams --- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 22 +++++++++--------- apps/openmw/mwworld/worldimp.cpp | 30 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39c1910df5..a7ff9b35bf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -14,6 +14,7 @@ namespace osg { class Vec3f; + class Matrixf; class Quat; class Image; } @@ -373,6 +374,8 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const = 0; + virtual void togglePOV() = 0; virtual bool isFirstPerson() const = 0; virtual void togglePreviewMode(bool enable) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c568ef7780..801a262d84 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -397,8 +399,6 @@ namespace MWSound try { std::string voicefile = "Sound/"+filename; - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); Sound_Loudness *loudness; mVFS->normalizeFilename(voicefile); @@ -408,7 +408,9 @@ namespace MWSound mPendingSaySounds[ptr] = std::make_pair(decoder, loudness); else { - MWBase::SoundStreamPtr sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } } @@ -906,10 +908,10 @@ namespace MWSound sound = playVoice(decoder, osg::Vec3f(), true); else { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - sound = playVoice(decoder, objpos, (ptr == MWMechanics::getPlayer())); + sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } mActiveSaySounds[ptr] = std::make_pair(sound, loudness); } @@ -930,13 +932,13 @@ namespace MWSound MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - sound->setPosition(objpos); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + sound->setPosition(pos); if(sound->getDistanceCull()) { - if((mListenerPos - objpos).length2() > 2000*2000) + if((mListenerPos - pos).length2() > 2000*2000) mOutput->stopStream(sound); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9a32c63a39..c9971c6f06 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1038,32 +1038,30 @@ namespace MWWorld return facedObject; } - osg::Vec3f getActorHeadPosition(const MWWorld::Ptr& actor, MWRender::RenderingManager* rendering) + osg::Matrixf World::getActorHeadTransform(const MWWorld::Ptr& actor) const { - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - - MWRender::Animation* anim = rendering->getAnimation(actor); - if (anim != NULL) + MWRender::Animation *anim = mRendering->getAnimation(actor); + if(anim) { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) + const osg::Node *node = anim->getNode("Head"); + if(!node) node = anim->getNode("Bip01 Head"); + if(node) { osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); + if(!mats.empty()) + return mats[0]; } } - return origin; + return osg::Matrixf::translate(actor.getRefData().getPosition().asVec3()); } + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { const ESM::Position &posdata = ptr.getRefData().getPosition(); osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos = getActorHeadPosition(ptr, mRendering); + osg::Vec3f pos = getActorHeadTransform(ptr).getTrans(); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); if(result.first.isEmpty()) @@ -2659,7 +2657,7 @@ namespace MWWorld MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin = getActorHeadPosition(actor, mRendering); + osg::Vec3f origin = getActorHeadTransform(actor).getTrans(); osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); @@ -3297,14 +3295,14 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) { - osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } float World::getHitDistance(const Ptr &actor, const Ptr &target) { - osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); return mPhysics->getHitDistance(weaponPos, target); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 92027868e8..f08ede1005 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -469,6 +469,8 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const; + virtual void togglePOV(); virtual bool isFirstPerson() const; From 73ffdd5ac53676835d46f65be04436f97839c9c3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:15:14 +0100 Subject: [PATCH 1667/1812] added colour settings --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/coloursetting.cpp | 49 +++++++++++++++++++++++ apps/opencs/model/prefs/coloursetting.hpp | 33 +++++++++++++++ apps/opencs/model/prefs/state.cpp | 28 ++++++++++++- apps/opencs/model/prefs/state.hpp | 5 +++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/prefs/coloursetting.cpp create mode 100644 apps/opencs/model/prefs/coloursetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b51cfb52fc..e76b5ce77b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -138,7 +138,7 @@ opencs_hdrs_noqt (model/settings ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting enumsetting + state setting intsetting doublesetting boolsetting enumsetting coloursetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/coloursetting.cpp b/apps/opencs/model/prefs/coloursetting.cpp new file mode 100644 index 0000000000..a564852921 --- /dev/null +++ b/apps/opencs/model/prefs/coloursetting.cpp @@ -0,0 +1,49 @@ + +#include "coloursetting.hpp" + +#include + +#include + +#include + +#include "../../view/widget/coloreditor.hpp" + +#include "category.hpp" +#include "state.hpp" + +CSMPrefs::ColourSetting::ColourSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, QColor default_) +: Setting (parent, values, key, label), mDefault (default_) +{} + +CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip (const std::string& tooltip) +{ + mTooltip = tooltip; + return *this; +} + +std::pair CSMPrefs::ColourSetting::makeWidgets (QWidget *parent) +{ + QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent); + + CSVWidget::ColorEditor *widget = new CSVWidget::ColorEditor (mDefault, parent); + + if (!mTooltip.empty()) + { + QString tooltip = QString::fromUtf8 (mTooltip.c_str()); + label->setToolTip (tooltip); + widget->setToolTip (tooltip); + } + + connect (widget, SIGNAL (pickingFinished()), this, SLOT (valueChanged())); + + return std::make_pair (label, widget); +} + +void CSMPrefs::ColourSetting::valueChanged() +{ + CSVWidget::ColorEditor& widget = dynamic_cast (*sender()); + getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + getParent()->getState()->update (*this); +} diff --git a/apps/opencs/model/prefs/coloursetting.hpp b/apps/opencs/model/prefs/coloursetting.hpp new file mode 100644 index 0000000000..fed2adc0a8 --- /dev/null +++ b/apps/opencs/model/prefs/coloursetting.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_PREFS_COLOURSETTING_H +#define CSM_PREFS_COLOURSETTING_H + +#include "setting.hpp" + +#include + +namespace CSMPrefs +{ + class ColourSetting : public Setting + { + Q_OBJECT + + std::string mTooltip; + QColor mDefault; + + public: + + ColourSetting (Category *parent, Settings::Manager *values, + const std::string& key, const std::string& label, QColor default_); + + ColourSetting& setTooltip (const std::string& tooltip); + + /// Return label, input widget. + virtual std::pair makeWidgets (QWidget *parent); + + private slots: + + void valueChanged(); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 99449309cc..41956a5a9b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -8,6 +8,7 @@ #include "intsetting.hpp" #include "doublesetting.hpp" #include "boolsetting.hpp" +#include "coloursetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -141,8 +142,13 @@ void CSMPrefs::State::declare() setRange (0, 10000); declareInt ("error-height", "Initial height of the error panel", 100). setRange (100, 10000); - // syntax-colouring - + declareColour ("colour-int", "Highlight Colour: Integer Literals", QColor ("darkmagenta")); + declareColour ("colour-float", "Highlight Colour: Float Literals", QColor ("magenta")); + declareColour ("colour-name", "Highlight Colour: Names", QColor ("grey")); + declareColour ("colour-keyword", "Highlight Colour: Keywords", QColor ("red")); + declareColour ("colour-special", "Highlight Colour: Special Characters", QColor ("darkorange")); + declareColour ("colour-comment", "Highlight Colour: Comments", QColor ("green")); + declareColour ("colour-id", "Highlight Colour: IDs", QColor ("blue")); declareCategory ("General Input"); declareBool ("cycle", "Cyclic next/previous", false). setTooltip ("When using next/previous functions at the last/first item of a " @@ -271,6 +277,24 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, return *setting; } +CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, + const std::string& label, QColor default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + setDefault (key, default_.name().toUtf8().data()); + + default_.setNamedColor (QString::fromUtf8 (mSettings.getString (key, mCurrentCategory->second.getKey()).c_str())); + + CSMPrefs::ColourSetting *setting = + new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index e4de7fcff3..1e4ada5b4d 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -16,11 +16,14 @@ #include "setting.hpp" #include "enumsetting.hpp" +class QColor; + namespace CSMPrefs { class IntSetting; class DoubleSetting; class BoolSetting; + class ColourSetting; class State : public QObject { @@ -60,6 +63,8 @@ namespace CSMPrefs EnumSetting& declareEnum (const std::string& key, const std::string& label, EnumValue default_); + ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); + void setDefault (const std::string& key, const std::string& default_); public: From a907b4ab152fc984766cee1a5dbc549ff22b9295 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:22:15 +0100 Subject: [PATCH 1668/1812] made Setting class non-abstract --- apps/opencs/model/prefs/setting.cpp | 5 +++++ apps/opencs/model/prefs/setting.hpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 70dbbc7453..b23152d175 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -16,6 +16,11 @@ CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, CSMPrefs::Setting:: ~Setting() {} +std::pair CSMPrefs::Setting::makeWidgets (QWidget *parent) +{ + return std::pair (0, 0); +} + const CSMPrefs::Category *CSMPrefs::Setting::getParent() const { return mParent; diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index 148c642925..e970352f4f 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -40,7 +40,7 @@ namespace CSMPrefs /// /// \note first can be a 0-pointer, which means that the label is part of the input /// widget. - virtual std::pair makeWidgets (QWidget *parent) = 0; + virtual std::pair makeWidgets (QWidget *parent); const Category *getParent() const; From 31b105ad9eeb757ffa0fa1b8376f5dfdfdd856ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:32:55 +0100 Subject: [PATCH 1669/1812] improved settings layout --- apps/opencs/model/prefs/state.cpp | 22 +++++++++++++++++++--- apps/opencs/model/prefs/state.hpp | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 41956a5a9b..02ab1ca49e 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -41,12 +41,13 @@ void CSMPrefs::State::declare() declareInt ("default-height", "Default window height", 600). setTooltip ("Newly opened top-level windows will open with this height."). setMin (80); - declareBool ("reuse", "Reuse Subviews", true). - setTooltip ("When a new subview is requested and a matching subview already " - " exist, do not open a new subview and use the existing one instead."); declareBool ("show-statusbar", "Show Status Bar", true). setTooltip ("If a newly open top level window is showing status bars or not. " " Note that this does not affect existing windows."); + declareSeparator(); + declareBool ("reuse", "Reuse Subviews", true). + setTooltip ("When a new subview is requested and a matching subview already " + " exist, do not open a new subview and use the existing one instead."); declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256). setTooltip ("If the maximum number is reached and a new subview is opened " "it will be placed into a new top-level window."). @@ -58,6 +59,7 @@ void CSMPrefs::State::declare() declareInt ("minimum-width", "Minimum subview width", 325). setTooltip ("Minimum width of subviews."). setRange (50, 10000); + declareSeparator(); EnumValue scrollbarOnly ("Scrollbar Only", "Simple addition of scrollbars, the view window " "does not grow automatically."); declareEnum ("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly). @@ -91,6 +93,7 @@ void CSMPrefs::State::declare() declareEnum ("double-s", "Shift Double Click", editRecord).addValues (doubleClickValues); declareEnum ("double-c", "Control Double Click", view).addValues (doubleClickValues); declareEnum ("double-sc", "Shift Control Double Click", editRecordAndClose).addValues (doubleClickValues); + declareSeparator(); EnumValue jumpAndSelect ("Jump and Select", "Scroll new record into view and make it the selection"); declareEnum ("jump-to-added", "Action on adding or cloning a record", jumpAndSelect). addValue (jumpAndSelect). @@ -142,6 +145,7 @@ void CSMPrefs::State::declare() setRange (0, 10000); declareInt ("error-height", "Initial height of the error panel", 100). setRange (100, 10000); + declareSeparator(); declareColour ("colour-int", "Highlight Colour: Integer Literals", QColor ("darkmagenta")); declareColour ("colour-float", "Highlight Colour: Float Literals", QColor ("magenta")); declareColour ("colour-name", "Highlight Colour: Names", QColor ("grey")); @@ -169,6 +173,7 @@ void CSMPrefs::State::declare() declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons); declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons); declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons); + declareSeparator(); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); @@ -295,6 +300,17 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, return *setting; } +void CSMPrefs::State::declareSeparator() +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + CSMPrefs::Setting *setting = + new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, "", ""); + + mCurrentCategory->second.addSetting (setting); +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 1e4ada5b4d..f5376a7daa 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -65,6 +65,8 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); + void declareSeparator(); + void setDefault (const std::string& key, const std::string& default_); public: From 8245b9e4390309639f69545132d6c5464a482386 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 11:50:06 +0100 Subject: [PATCH 1670/1812] added interface for querying settings --- apps/opencs/model/prefs/category.cpp | 13 ++++++++ apps/opencs/model/prefs/category.hpp | 2 ++ apps/opencs/model/prefs/setting.cpp | 48 ++++++++++++++++++++++++++++ apps/opencs/model/prefs/setting.hpp | 17 ++++++++++ apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/prefs/state.hpp | 2 +- apps/opencs/view/prefs/dialogue.cpp | 2 +- 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index b001586b55..0de192eb5a 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -1,6 +1,10 @@ #include "category.hpp" +#include + +#include "setting.hpp" + CSMPrefs::Category::Category (State *parent, const std::string& key) : mParent (parent), mKey (key) {} @@ -29,3 +33,12 @@ CSMPrefs::Category::Iterator CSMPrefs::Category::end() { return mSettings.end(); } + +CSMPrefs::Setting& CSMPrefs::Category::operator[] (const std::string& key) +{ + for (Iterator iter = mSettings.begin(); iter!=mSettings.end(); ++iter) + if ((*iter)->getKey()==key) + return **iter; + + throw std::logic_error ("Invalid user setting: " + key); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 0b8e45d56d..7231fddea7 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -35,6 +35,8 @@ namespace CSMPrefs Iterator begin(); Iterator end(); + + Setting& operator[] (const std::string& key); }; } diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index b23152d175..39d997988e 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -1,6 +1,8 @@ #include "setting.hpp" +#include + #include "category.hpp" #include "state.hpp" @@ -35,3 +37,49 @@ const std::string& CSMPrefs::Setting::getLabel() const { return mLabel; } + +int CSMPrefs::Setting::toInt() const +{ + return mValues->getInt (mKey, mParent->getKey()); +} + +double CSMPrefs::Setting::toDouble() const +{ + return mValues->getFloat (mKey, mParent->getKey()); +} + +std::string CSMPrefs::Setting::toString() const +{ + return mValues->getString (mKey, mParent->getKey()); +} + +bool CSMPrefs::Setting::isTrue() const +{ + return mValues->getBool (mKey, mParent->getKey()); +} + +QColor CSMPrefs::Setting::toColor() const +{ + return QColor (QString::fromUtf8 (toString().c_str())); +} + +bool CSMPrefs::operator== (const Setting& setting, const std::string& key) +{ + std::string fullKey = setting.getParent()->getKey() + "/" + setting.getKey(); + return fullKey==key; +} + +bool CSMPrefs::operator== (const std::string& key, const Setting& setting) +{ + return setting==key; +} + +bool CSMPrefs::operator!= (const Setting& setting, const std::string& key) +{ + return !(setting==key); +} + +bool CSMPrefs::operator!= (const std::string& key, const Setting& setting) +{ + return !(key==setting); +} diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index e970352f4f..65354469d3 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -7,6 +7,7 @@ #include class QWidget; +class QColor; namespace Settings { @@ -47,7 +48,23 @@ namespace CSMPrefs const std::string& getKey() const; const std::string& getLabel() const; + + int toInt() const; + + double toDouble() const; + + std::string toString() const; + + bool isTrue() const; + + QColor toColor() const; }; + + // note: fullKeys have the format categoryKey/settingKey + bool operator== (const Setting& setting, const std::string& fullKey); + bool operator== (const std::string& fullKey, const Setting& setting); + bool operator!= (const Setting& setting, const std::string& fullKey); + bool operator!= (const std::string& fullKey, const Setting& setting); } #endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 02ab1ca49e..c31c2db5a0 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -356,7 +356,7 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } -CSMPrefs::Category& CSMPrefs::State::getCategory (const std::string& key) +CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) { Iterator iter = mCategories.find (key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index f5376a7daa..2b99eec055 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -81,7 +81,7 @@ namespace CSMPrefs Iterator end(); - Category& getCategory (const std::string& key); + Category& operator[](const std::string& key); void update (const Setting& setting); diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 6135afde70..97a36306ff 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -53,7 +53,7 @@ CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key) { // special case page code goes here - return new Page (CSMPrefs::get().getCategory (key), mContent); + return new Page (CSMPrefs::get()[key], mContent); } CSVPrefs::Dialogue::Dialogue() From 3a5238bebc3486d6c719150974e4aabd48b90dde Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Dec 2015 12:06:20 +0100 Subject: [PATCH 1671/1812] changed the settingChanged signature to accommodate queued connections --- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/prefs/state.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c31c2db5a0..d6250c5326 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -368,7 +368,7 @@ CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) void CSMPrefs::State::update (const Setting& setting) { - emit (settingChanged (setting)); + emit (settingChanged (&setting)); } CSMPrefs::State& CSMPrefs::State::get() diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 2b99eec055..13427b1aa1 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -89,7 +89,7 @@ namespace CSMPrefs signals: - void settingChanged (const Setting& setting); + void settingChanged (const Setting *setting); }; // convenience function From 06719df868aa934db7d99bed92567dd67e70c383 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 11 Dec 2015 15:59:16 +0100 Subject: [PATCH 1672/1812] Use the standard cursor if the custom cursor can't be used Signed-off-by: Paul Cercueil --- components/sdlutil/sdlcursormanager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 26b0510dc1..40b87d905e 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -217,14 +217,17 @@ namespace SDLUtil void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - #ifdef ANDROID - return; - #endif + osg::ref_ptr decompressed; if (mCursorMap.find(name) != mCursorMap.end()) return; - osg::ref_ptr decompressed = decompress(image, static_cast(rotDegrees)); + try { + decompressed = decompress(image, static_cast(rotDegrees)); + } catch (...) { + osg::notify(osg::NOTICE)<<"Using default cursor."< Date: Fri, 11 Dec 2015 16:18:08 +0100 Subject: [PATCH 1673/1812] Don't use osg::notify --- components/sdlutil/sdlcursormanager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 40b87d905e..9ecef04839 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -52,7 +53,7 @@ namespace if (!_gc) { - osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<pbuffer = false; _gc = osg::GraphicsContext::createGraphicsContext(traits.get()); @@ -224,8 +225,9 @@ namespace SDLUtil try { decompressed = decompress(image, static_cast(rotDegrees)); - } catch (...) { - osg::notify(osg::NOTICE)<<"Using default cursor."< Date: Fri, 11 Dec 2015 15:55:45 +0100 Subject: [PATCH 1674/1812] ESMStore: fill mIds in setUp() --- apps/openmw/mwworld/esmstore.cpp | 30 ++++++++++++++++-------------- apps/openmw/mwworld/store.hpp | 2 ++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 9cf8de6bbc..2e6161bf5e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -114,10 +114,6 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else { dialogue = 0; } - // Insert the reference into the global lookup - if (!id.mId.empty() && isCacheableRecord(n.val)) { - mIds[Misc::StringUtils::lowerCase (id.mId)] = n.val; - } } listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); } @@ -125,9 +121,20 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) void ESMStore::setUp() { - std::map::iterator it = mStores.begin(); - for (; it != mStores.end(); ++it) { - it->second->setUp(); + mIds.clear(); + + std::map::iterator storeIt = mStores.begin(); + for (; storeIt != mStores.end(); ++storeIt) { + if (isCacheableRecord(storeIt->first)) + { + std::vector identifiers; + storeIt->second->listIdentifier(identifiers); + + for (std::vector::const_iterator record = identifiers.begin(); record != identifiers.end(); ++record) + mIds[*record] = storeIt->first; + } + + storeIt->second->setUp(); } mSkills.setUp(); mMagicEffects.setUp(); @@ -189,18 +196,13 @@ void ESMStore::setUp() case ESM::REC_LEVC: { - RecordId id = mStores[type]->read (reader); - - // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame - // that really should be cleared instead of just overwritten - - mIds[id.mId] = type; + mStores[type]->read (reader); } if (type==ESM::REC_NPC_) { // NPC record will always be last and we know that there can be only one - // dynamic NPC record (player) -> We are done here with dynamic record laoding + // dynamic NPC record (player) -> We are done here with dynamic record loading setUp(); const ESM::NPC *player = mNpcs.find ("player"); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 443dd4175e..88457c950e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -32,6 +32,8 @@ namespace MWWorld virtual ~StoreBase() {} virtual void setUp() {} + + /// List identifiers of records contained in this Store (case-smashed). No-op for Stores that don't use string IDs. virtual void listIdentifier(std::vector &list) const {} virtual size_t getSize() const = 0; From cc2315a0de77b9c3d6e99ccb6dc657d18e136235 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 16:59:13 +0100 Subject: [PATCH 1675/1812] Minor fix --- apps/openmw/mwworld/esmstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 2e6161bf5e..1882c6e1aa 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -125,6 +125,8 @@ void ESMStore::setUp() std::map::iterator storeIt = mStores.begin(); for (; storeIt != mStores.end(); ++storeIt) { + storeIt->second->setUp(); + if (isCacheableRecord(storeIt->first)) { std::vector identifiers; @@ -133,8 +135,6 @@ void ESMStore::setUp() for (std::vector::const_iterator record = identifiers.begin(); record != identifiers.end(); ++record) mIds[*record] = storeIt->first; } - - storeIt->second->setUp(); } mSkills.setUp(); mMagicEffects.setUp(); From 7fc2df153a42ae5545d1129a31d610ea1b143f19 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 15:13:14 -0800 Subject: [PATCH 1676/1812] Rename stopSound/stopStream to finishSound/finishStream Since they're also used to clean up output resources, not just stopping. --- apps/openmw/mwsound/openal_output.cpp | 4 +-- apps/openmw/mwsound/openal_output.hpp | 4 +-- apps/openmw/mwsound/sound_output.hpp | 4 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++++++++++++------------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 02a9f33f90..d440206329 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -915,7 +915,7 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::stopSound(MWBase::SoundPtr sound) +void OpenAL_Output::finishSound(MWBase::SoundPtr sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -1012,7 +1012,7 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou sound->mHandle = stream; } -void OpenAL_Output::stopStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 28f30bec9f..4986cd3a03 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -58,13 +58,13 @@ namespace MWSound virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void stopSound(MWBase::SoundPtr sound); + virtual void finishSound(MWBase::SoundPtr sound); virtual bool isSoundPlaying(MWBase::SoundPtr sound); virtual void updateSound(MWBase::SoundPtr sound); virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound); - virtual void stopStream(MWBase::SoundStreamPtr sound); + virtual void finishStream(MWBase::SoundStreamPtr sound); virtual double getStreamDelay(MWBase::SoundStreamPtr sound); virtual double getStreamOffset(MWBase::SoundStreamPtr sound); virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 79025abb00..98eba8466c 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -37,13 +37,13 @@ namespace MWSound virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void stopSound(MWBase::SoundPtr sound) = 0; + virtual void finishSound(MWBase::SoundPtr sound) = 0; virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; virtual void updateSound(MWBase::SoundPtr sound) = 0; virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; - virtual void stopStream(MWBase::SoundStreamPtr sound) = 0; + virtual void finishStream(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 801a262d84..a36c21da12 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -309,7 +309,7 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) - mOutput->stopStream(mMusic); + mOutput->finishStream(mMusic); mMusic.reset(); } @@ -477,7 +477,7 @@ namespace MWSound SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - mOutput->stopStream(snditer->second.first); + mOutput->finishStream(snditer->second.first); mActiveSaySounds.erase(snditer); } mPendingSaySounds.erase(ptr); @@ -506,7 +506,7 @@ namespace MWSound void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) { - mOutput->stopStream(stream); + mOutput->finishStream(stream); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); if(iter != mActiveTracks.end() && *iter == stream) mActiveTracks.erase(iter); @@ -624,7 +624,7 @@ namespace MWSound void SoundManager::stopSound(MWBase::SoundPtr sound) { if (sound.get()) - mOutput->stopSound(sound); + mOutput->finishSound(sound); } void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) @@ -637,7 +637,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } } @@ -649,7 +649,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } @@ -664,7 +664,7 @@ namespace MWSound { SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } ++snditer; } @@ -675,7 +675,7 @@ namespace MWSound sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { - mOutput->stopStream(sayiter->second.first); + mOutput->finishStream(sayiter->second.first); } ++sayiter; } @@ -691,7 +691,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { if(sndidx->second == sfx) - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); } } } @@ -829,7 +829,7 @@ namespace MWSound env = Env_Underwater; else if(mUnderwaterSound) { - mOutput->stopSound(mUnderwaterSound); + mOutput->finishSound(mUnderwaterSound); mUnderwaterSound.reset(); } @@ -866,13 +866,13 @@ namespace MWSound if(sound->getDistanceCull()) { if((mListenerPos - objpos).length2() > 2000*2000) - mOutput->stopSound(sound); + mOutput->finishSound(sound); } } if(!mOutput->isSoundPlaying(sound)) { - mOutput->stopSound(sound); + mOutput->finishSound(sound); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -939,13 +939,13 @@ namespace MWSound if(sound->getDistanceCull()) { if((mListenerPos - pos).length2() > 2000*2000) - mOutput->stopStream(sound); + mOutput->finishStream(sound); } } if(!mOutput->isStreamPlaying(sound)) { - mOutput->stopStream(sound); + mOutput->finishStream(sound); mActiveSaySounds.erase(sayiter++); } else @@ -963,7 +963,7 @@ namespace MWSound MWBase::SoundStreamPtr sound = *trkiter; if(!mOutput->isStreamPlaying(sound)) { - mOutput->stopStream(sound); + mOutput->finishStream(sound); trkiter = mActiveTracks.erase(trkiter); } else @@ -1143,7 +1143,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - mOutput->stopSound(sndidx->first); + mOutput->finishSound(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1152,11 +1152,11 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) - mOutput->stopStream(sayiter->second.first); + mOutput->finishStream(sayiter->second.first); mActiveSaySounds.clear(); TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) - mOutput->stopStream(*trkiter); + mOutput->finishStream(*trkiter); mActiveTracks.clear(); mPendingSaySounds.clear(); mUnderwaterSound.reset(); From f47f0a996f096d7e0ce3cd4d89eb660b814b29b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 15:49:45 -0800 Subject: [PATCH 1677/1812] Stop the object's old say sound before playing the new one --- apps/openmw/mwsound/soundmanagerimp.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a36c21da12..d1a90759b1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -410,8 +410,10 @@ namespace MWSound { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + SoundLoudnessPair &old = mActiveSaySounds[ptr]; + if(old.first.get()) mOutput->finishStream(old.first); + old = std::make_pair(playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())), + loudness); } } catch(std::exception &e) @@ -450,8 +452,9 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - MWBase::SoundStreamPtr sound = playVoice(decoder, osg::Vec3f(), true); - mActiveSaySounds[MWWorld::Ptr()] = std::make_pair(sound, loudness); + SoundLoudnessPair &old = mActiveSaySounds[MWWorld::Ptr()]; + if(old.first.get()) mOutput->finishStream(old.first); + old = std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness); } } catch(std::exception &e) @@ -904,16 +907,18 @@ namespace MWSound MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; + + SoundLoudnessPair &old = mActiveSaySounds[ptr]; + if(old.first.get()) mOutput->finishStream(old.first); if(ptr == MWWorld::Ptr()) sound = playVoice(decoder, osg::Vec3f(), true); else { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } - mActiveSaySounds[ptr] = std::make_pair(sound, loudness); + old = std::make_pair(sound, loudness); } catch(std::exception &e) { std::cerr<< "Sound Error: "< Date: Sat, 12 Dec 2015 02:01:19 +0100 Subject: [PATCH 1678/1812] Update comment in settings-default.cfg There are antialiasing techniques that address texture/shading aliasing, but the one we use (MSAA) does not. --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d41ebfde26..a5fd3cccd0 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -204,7 +204,7 @@ minimize on focus loss = true # An operating system border is drawn around the OpenMW window. window border = true -# Anti-aliasing reduces texture distortion. (0, 2, 4, 8, 16). +# Anti-aliasing reduces jagged polygon edges. (0, 2, 4, 8, 16). antialiasing = 0 # Enable vertical syncing to reduce tearing defects. From 04a11679fb16ab4a60e51c8f7c98767020b2c09f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 11:58:53 +0100 Subject: [PATCH 1679/1812] added category update function --- apps/opencs/model/prefs/category.cpp | 7 +++++++ apps/opencs/model/prefs/category.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/apps/opencs/model/prefs/category.cpp b/apps/opencs/model/prefs/category.cpp index 0de192eb5a..6af0ac645b 100644 --- a/apps/opencs/model/prefs/category.cpp +++ b/apps/opencs/model/prefs/category.cpp @@ -4,6 +4,7 @@ #include #include "setting.hpp" +#include "state.hpp" CSMPrefs::Category::Category (State *parent, const std::string& key) : mParent (parent), mKey (key) @@ -42,3 +43,9 @@ CSMPrefs::Setting& CSMPrefs::Category::operator[] (const std::string& key) throw std::logic_error ("Invalid user setting: " + key); } + +void CSMPrefs::Category::update() +{ + for (Iterator iter = mSettings.begin(); iter!=mSettings.end(); ++iter) + mParent->update (**iter); +} diff --git a/apps/opencs/model/prefs/category.hpp b/apps/opencs/model/prefs/category.hpp index 7231fddea7..b70716aa0e 100644 --- a/apps/opencs/model/prefs/category.hpp +++ b/apps/opencs/model/prefs/category.hpp @@ -37,6 +37,8 @@ namespace CSMPrefs Iterator end(); Setting& operator[] (const std::string& key); + + void update(); }; } From 0ffe4290fb3b7654d95a445996ecb9bc4a011efc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 12:05:56 +0100 Subject: [PATCH 1680/1812] workaround for MOC's lack of namespace awareness --- apps/opencs/model/prefs/state.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 13427b1aa1..7807dac257 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -89,7 +89,7 @@ namespace CSMPrefs signals: - void settingChanged (const Setting *setting); + void settingChanged (const CSMPrefs::Setting *setting); }; // convenience function From cf9fa0e0e9742203303009725e79e2eafc4d70e6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Dec 2015 14:49:16 +0100 Subject: [PATCH 1681/1812] first batch of changing over user settings usage to the new system --- apps/opencs/view/doc/view.cpp | 59 +++---- apps/opencs/view/render/worldspacewidget.cpp | 117 ++++++------- apps/opencs/view/render/worldspacewidget.hpp | 11 +- apps/opencs/view/world/scenesubview.cpp | 6 - apps/opencs/view/world/scenesubview.hpp | 2 - apps/opencs/view/world/scriptedit.cpp | 34 ++-- apps/opencs/view/world/scriptedit.hpp | 6 +- apps/opencs/view/world/scripterrortable.cpp | 21 ++- apps/opencs/view/world/scripterrortable.hpp | 11 +- apps/opencs/view/world/scripthighlighter.cpp | 173 +++---------------- apps/opencs/view/world/scripthighlighter.hpp | 21 ++- apps/opencs/view/world/scriptsubview.cpp | 2 - apps/opencs/view/world/table.cpp | 76 ++++---- apps/opencs/view/world/table.hpp | 7 + 14 files changed, 197 insertions(+), 349 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 38088c6d70..776839d19e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,7 @@ #include "../../model/doc/document.hpp" #include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" @@ -121,10 +122,9 @@ void CSVDoc::View::setupViewMenu() mShowStatusBar = new QAction (tr ("Show Status Bar"), this); mShowStatusBar->setCheckable (true); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); - std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); - if(showStatusBar == "true") - mShowStatusBar->setChecked(true); + + mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); + view->addAction (mShowStatusBar); QAction *filters = new QAction (tr ("Filters"), this); @@ -333,9 +333,9 @@ void CSVDoc::View::updateTitle() if (mViewTotal>1) stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + bool hideTitle = windows["hide-subview"].isTrue() && mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); if (hideTitle) @@ -346,19 +346,18 @@ void CSVDoc::View::updateTitle() void CSVDoc::View::updateSubViewIndicies(SubView *view) { + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; + if(view && mSubViews.contains(view)) { mSubViews.removeOne(view); // adjust (reduce) the scroll area (even floating), except when it is "Scrollbar Only" - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow then Scroll") + if (windows["mainwindow-scrollbar"].toString() == "Grow then Scroll") updateScrollbar(); } - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - bool hideTitle = userSettings.setting ("window/hide-subview", QString ("false"))=="true" && + bool hideTitle = windows["hide-subview"].isTrue() && mSubViews.size()==1 && !mSubViews.at (0)->isFloating(); updateTitle(); @@ -406,21 +405,16 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mScroll(0), mScrollbarOnly(false) { - int width = CSMSettings::UserSettings::instance().settingValue - ("window/default-width").toInt(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - int height = CSMSettings::UserSettings::instance().settingValue - ("window/default-height").toInt(); - - width = std::max(width, 300); - height = std::max(height, 300); + int width = std::max (windows["default-width"].toInt(), 300); + int height = std::max (windows["default-height"].toInt(), 300); resize (width, height); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - if(settings.settingValue ("window/mainwindow-scrollbar") == "Grow Only") + if (windows["mainwindow-scrollbar"].toString() == "Grow Only") { setCentralWidget (&mSubViewWindow); } @@ -503,14 +497,12 @@ void CSVDoc::View::updateProgress (int current, int max, int type, int threads) void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::string& hint) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; bool isReferenceable = id.getClass() == CSMWorld::UniversalId::Class_RefRecord; // User setting to reuse sub views (on a per top level view basis) - bool reuse = - userSettings.setting ("window/reuse", QString("true")) == "true" ? true : false; - if(reuse) + if (windows["reuse"].isTrue()) { foreach(SubView *sb, mSubViews) { @@ -538,8 +530,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // // If the sub view limit setting is one, the sub view title bar is hidden and the // text in the main title bar is adjusted accordingly - int maxSubView = userSettings.setting("window/max-subviews", QString("256")).toInt(); - if(mSubViews.size() >= maxSubView) // create a new top level view + if(mSubViews.size() >= windows["max-subviews"].toInt()) // create a new top level view { mViewManager.addView(mDocument, id, hint); @@ -559,8 +550,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin view->setParent(this); mSubViews.append(view); // only after assert - int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt(); - view->setMinimumWidth(minWidth); + int minWidth = windows["minimum-width"].toInt(); + view->setMinimumWidth (minWidth); view->setStatusBar (mShowStatusBar->isChecked()); @@ -575,13 +566,11 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // should become visible) // - Move the scroll bar to the newly added subview // - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString mainwinScroll = settings.settingValue ("window/mainwindow-scrollbar"); - mScrollbarOnly = mainwinScroll.isEmpty() || mainwinScroll == "Scrollbar Only"; + mScrollbarOnly = windows["mainwindow-scrollbar"].toString() == "Scrollbar Only"; QDesktopWidget *dw = QApplication::desktop(); QRect rect; - if(settings.settingValue ("window/grow-limit") == "true") + if (windows["grow-limit"].isTrue()) rect = dw->screenGeometry(this); else rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); @@ -862,6 +851,7 @@ void CSVDoc::View::resizeViewHeight (int height) void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) { + if (name=="window/hide-subview") updateSubViewIndicies (0); @@ -944,10 +934,9 @@ void CSVDoc::View::stop() void CSVDoc::View::closeRequest (SubView *subView) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; - if (mSubViews.size()>1 || mViewTotal<=1 || - userSettings.setting ("window/hide-subview", QString ("false"))!="true") + if (mSubViews.size()>1 || mViewTotal<=1 || !windows["hide-subview"].isTrue()) { subView->deleteLater(); mSubViews.removeOne (subView); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0deb498405..46e2bc2e01 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -20,7 +20,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle2.hpp" @@ -31,17 +31,6 @@ #include "editmode.hpp" #include "instancemode.hpp" -namespace -{ - static const char * const sMappingSettings[] = - { - "p-navi", "s-navi", - "p-edit", "s-edit", - "p-select", "s-select", - 0 - }; -} - CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), @@ -77,19 +66,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - for (int i=0; sMappingSettings[i]; ++i) - { - QString key ("scene-input/"); - key += sMappingSettings[i]; - storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key)); - } - - mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble(); - mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble(); - mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble(); - - mShowToolTips = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene") == "true"; - mToolTipDelay = CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-delay").toInt(); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["3D Scene Input"].update(); + CSMPrefs::get()["Tooltips"].update(); mToolTipDelayTimer.setSingleShot (true); connect (&mToolTipDelayTimer, SIGNAL (timeout()), this, SLOT (showToolTip())); @@ -99,6 +79,23 @@ CSVRender::WorldspaceWidget::~WorldspaceWidget () { } +void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setting) +{ + if (storeMappingSetting (setting)) + return; + + if (*setting=="3D Scene Input/drag-factor") + mDragFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/drag-wheel-factor") + mDragWheelFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/drag-shift-factor") + mDragShiftFactor = setting->toDouble(); + else if (*setting=="Tooltips/scene-delay") + mToolTipDelay = setting->toInt(); + else if (*setting=="Tooltips/scene") + mShowToolTips = setting->isTrue(); +} + void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) { if (mode=="1st") @@ -291,25 +288,6 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const return mInteractionMask & getVisibilityMask(); } -void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value) -{ - if (!value.isEmpty() && storeMappingSetting (name, value.first())) - return; - - if (name=="scene-input/drag-factor") - mDragFactor = value.at (0).toDouble(); - else if (name=="scene-input/drag-wheel-factor") - mDragWheelFactor = value.at (0).toDouble(); - else if (name=="scene-input/drag-shift-factor") - mDragShiftFactor = value.at (0).toDouble(); - else if (name=="tooltips/scene-delay") - mToolTipDelay = value.at (0).toInt(); - else if (name=="tooltips/scene") - mShowToolTips = value.at (0)=="true"; - else - dynamic_cast (*mEditMode->getCurrent()).updateUserSetting (name, value); -} - void CSVRender::WorldspaceWidget::setEditLock (bool locked) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (locked); @@ -348,34 +326,40 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) } -bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const QString& value) +bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting) { - const QString prefix = "scene-input/"; + if (setting->getParent()->getKey()!="3D Scene Input") + return false; - if (key.startsWith (prefix)) + static const char * const sMappingSettings[] = { - QString key2 (key.mid (prefix.length())); + "p-navi", "s-navi", + "p-edit", "s-edit", + "p-select", "s-select", + 0 + }; - for (int i=0; sMappingSettings[i]; ++i) - if (key2==sMappingSettings[i]) - { - Qt::MouseButton button = Qt::NoButton; + for (int i=0; sMappingSettings[i]; ++i) + if (setting->getKey()==sMappingSettings[i]) + { + QString value = QString::fromUtf8 (setting->toString().c_str()); - if (value.endsWith ("Left Mouse-Button")) - button = Qt::LeftButton; - else if (value.endsWith ("Right Mouse-Button")) - button = Qt::RightButton; - else if (value.endsWith ("Middle Mouse-Button")) - button = Qt::MiddleButton; - else - return false; + Qt::MouseButton button = Qt::NoButton; - bool ctrl = value.startsWith ("Ctrl-"); + if (value.endsWith ("Left Mouse-Button")) + button = Qt::LeftButton; + else if (value.endsWith ("Right Mouse-Button")) + button = Qt::RightButton; + else if (value.endsWith ("Middle Mouse-Button")) + button = Qt::MiddleButton; + else + return false; - mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; - return true; - } - } + bool ctrl = value.startsWith ("Ctrl-"); + + mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; + return true; + } return false; } @@ -514,8 +498,7 @@ void CSVRender::WorldspaceWidget::showToolTip() if (osg::ref_ptr tag = mousePick (mapFromGlobal (pos))) { - bool hideBasics = - CSMSettings::UserSettings::instance().settingValue ("tooltips/scene-hide-basic")=="true"; + bool hideBasics = CSMPrefs::get()["Tooltips"]["scene-hide-basic"].isTrue(); QToolTip::showText (pos, tag->getToolTip (hideBasics), this); } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 0b5ae25233..54376cee45 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -13,6 +13,11 @@ #include "scenewidget.hpp" #include "elements.hpp" +namespace CSMPrefs +{ + class Setting; +} + namespace CSMWorld { class UniversalId; @@ -115,8 +120,6 @@ namespace CSVRender /// marked for interaction. unsigned int getInteractionMask() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void setEditLock (bool locked); CSMDoc::Document& getDocument(); @@ -151,7 +154,7 @@ namespace CSVRender void dragMoveEvent(QDragMoveEvent *event); /// \return Is \a key a button mapping setting? (ignored otherwise) - bool storeMappingSetting (const QString& key, const QString& value); + bool storeMappingSetting (const CSMPrefs::Setting *setting); osg::ref_ptr mousePick (const QPoint& localPos); @@ -161,6 +164,8 @@ namespace CSVRender private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void selectNavigationMode (const std::string& mode); virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 753d791c0f..44fe94d840 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -147,12 +147,6 @@ std::string CSVWorld::SceneSubView::getTitle() const return mTitle; } -void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value) -{ - mScene->updateUserSetting (name, value); - CSVDoc::SubView::updateUserSetting (name, value); -} - void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id) { setUniversalId(id); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 2458d58f42..0f18e8c303 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -59,8 +59,6 @@ namespace CSVWorld virtual std::string getTitle() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 25f4fd0777..9f1abcf970 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -12,8 +12,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/tablemimedata.hpp" -#include "../../model/settings/usersettings.hpp" - +#include "../../model/prefs/state.hpp" CSVWorld::ScriptEdit::ChangeLock::ChangeLock (ScriptEdit& edit) : mEdit (edit) { @@ -92,31 +91,24 @@ CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighli connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - connect (&userSettings, SIGNAL (userSettingUpdated(const QString &, const QStringList &)), - this, SLOT (updateUserSetting (const QString &, const QStringList &))); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + { + ChangeLock lock (*this); + CSMPrefs::get()["Scripts"].update(); + } mUpdateTimer.setSingleShot (true); // TODO: provide a font selector dialogue mMonoFont.setStyleHint(QFont::TypeWriter); - if (userSettings.setting("script-editor/mono-font", "true") == "true") - setFont(mMonoFont); - mLineNumberArea = new LineNumberArea(this); updateLineNumberAreaWidth(0); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - - showLineNum(userSettings.settingValue("script-editor/show-linenum") == "true"); -} - -void CSVWorld::ScriptEdit::updateUserSetting (const QString &name, const QStringList &list) -{ - if (mHighlighter->updateUserSetting (name, list)) - updateHighlighting(); + updateHighlighting(); } void CSVWorld::ScriptEdit::showLineNum(bool show) @@ -202,6 +194,16 @@ bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const return !(string.contains(mWhiteListQoutes)); } +void CSVWorld::ScriptEdit::settingChanged (const CSMPrefs::Setting *setting) +{ + if (mHighlighter->settingChanged (setting)) + updateHighlighting(); + else if (*setting=="Scripts/mono-font") + setFont (setting->isTrue() ? mMonoFont : mDefaultFont); + else if (*setting=="Scripts/show-linenum") + showLineNum (setting->isTrue()); +} + void CSVWorld::ScriptEdit::idListChanged() { mHighlighter->invalidateIds(); diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index d17abf24ed..941a6295d8 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -91,6 +91,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void idListChanged(); void updateHighlighting(); @@ -98,10 +100,6 @@ namespace CSVWorld void updateLineNumberAreaWidth(int newBlockCount); void updateLineNumberArea(const QRect &, int); - - public slots: - - void updateUserSetting (const QString &name, const QStringList &list); }; class LineNumberArea : public QWidget diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index a9e315c73c..b439e0df39 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -9,7 +9,8 @@ #include #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -57,7 +58,7 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setItem (row, 2, messageItem); } -void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) +void CSVWorld::ScriptErrorTable::setWarningsMode (const std::string& value) { if (value=="Ignore") Compiler::ErrorHandler::setWarningsMode (0); @@ -91,17 +92,13 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); - setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Scripts"].update(); connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int))); } -void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="script-editor/warnings" && !value.isEmpty()) - setWarningsMode (value.at (0)); -} - void CSVWorld::ScriptErrorTable::update (const std::string& source) { clear(); @@ -136,6 +133,12 @@ bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) return mContext.clearLocals (script); } +void CSVWorld::ScriptErrorTable::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Scripst/warnings") + setWarningsMode (setting->toString()); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 33af7c8643..4841aac5b3 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -14,6 +14,11 @@ namespace CSMDoc class Document; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler @@ -32,14 +37,12 @@ namespace CSVWorld void addMessage (const std::string& message, CSMDoc::Message::Severity severity, int line = -1, int column = -1); - void setWarningsMode (const QString& value); + void setWarningsMode (const std::string& value); public: ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); - void updateUserSetting (const QString& name, const QStringList& value); - void update (const std::string& source); void clear(); @@ -51,6 +54,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void cellClicked (int row, int column); signals: diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 487b5b1395..846a61b471 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -5,7 +5,8 @@ #include #include -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/setting.hpp" +#include "../../model/prefs/category.hpp" bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) @@ -79,79 +80,12 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode : QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data), mMode (mode) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + QColor color ("black"); + QTextCharFormat format; + format.setForeground (color); - QColor color = QColor(); - - { - color.setNamedColor(userSettings.setting("script-editor/colour-int", "Dark magenta")); - if (!color.isValid()) - color = QColor(Qt::darkMagenta); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Int, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-float", "Magenta")); - if (!color.isValid()) - color = QColor(Qt::magenta); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Float, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-name", "Gray")); - if (!color.isValid()) - color = QColor(Qt::gray); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Name, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-keyword", "Red")); - if (!color.isValid()) - color = QColor(Qt::red); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Keyword, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-special", "Dark yellow")); - if (!color.isValid()) - color = QColor(Qt::darkYellow); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Special, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-comment", "Green")); - if (!color.isValid()) - color = QColor(Qt::green); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Comment, format)); - } - - { - color.setNamedColor(userSettings.setting ("script-editor/colour-id", "Blue")); - if (!color.isValid()) - color = QColor(Qt::blue); - - QTextCharFormat format; - format.setForeground (color); - mScheme.insert (std::make_pair (Type_Id, format)); - } + for (int i=0; i<=Type_Id; ++i) + mScheme.insert (std::make_pair (static_cast (i), format)); // configure compiler Compiler::registerExtensions (mExtensions); @@ -176,85 +110,26 @@ void CSVWorld::ScriptHighlighter::invalidateIds() mContext.invalidateIds(); } -bool CSVWorld::ScriptHighlighter::updateUserSetting (const QString &name, const QStringList &list) +bool CSVWorld::ScriptHighlighter::settingChanged (const CSMPrefs::Setting *setting) { - if (list.empty()) - return false; - - QColor color = QColor(); - - if (name == "script-editor/colour-int") + if (setting->getParent()->getKey()=="Scripts") { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; + static const char *const colours[Type_Id+2] = + { + "colour-int", "colour-float", "colour-name", "colour-keyword", + "colour-special", "colour-comment", "colour-id", + 0 + }; - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Int] = format; + for (int i=0; colours[i]; ++i) + if (setting->getKey()==colours[i]) + { + QTextCharFormat format; + format.setForeground (setting->toColor()); + mScheme[static_cast (i)] = format; + return true; + } } - else if (name == "script-editor/colour-float") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Float] = format; - } - else if (name == "script-editor/colour-name") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Name] = format; - } - else if (name == "script-editor/colour-keyword") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Keyword] = format; - } - else if (name == "script-editor/colour-special") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Special] = format; - } - else if (name == "script-editor/colour-comment") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Comment] = format; - } - else if (name == "script-editor/colour-id") - { - color.setNamedColor(list.at(0)); - if (!color.isValid()) - return false; - - QTextCharFormat format; - format.setForeground (color); - mScheme[Type_Id] = format; - } - else - return false; - - return true; + return false; } diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index 6f1f58e823..33824da0dc 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -11,6 +11,11 @@ #include "../../model/world/scriptcontext.hpp" +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser @@ -19,13 +24,13 @@ namespace CSVWorld enum Type { - Type_Int, - Type_Float, - Type_Name, - Type_Keyword, - Type_Special, - Type_Comment, - Type_Id + Type_Int = 0, + Type_Float = 1, + Type_Name = 2, + Type_Keyword = 3, + Type_Special = 4, + Type_Comment = 5, + Type_Id = 6 }; enum Mode @@ -88,7 +93,7 @@ namespace CSVWorld void invalidateIds(); - bool updateUserSetting (const QString &name, const QStringList &list); + bool settingChanged (const CSMPrefs::Setting *setting); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index bd66f2bf6b..eb8bd2e29d 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -194,8 +194,6 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr if (mButtons) mButtons->updateUserSetting (name, value); - mErrors->updateUserSetting (name, value); - if (name=="script-editor/warnings") recompile(); } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 73bef7b26b..ba8c4ae563 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -23,7 +23,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "recordstatusdelegate.hpp" #include "tableeditidaction.hpp" @@ -232,23 +232,9 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : DragRecordTable(document), mCreateAction (0), mCloneAction(0),mRecordStatusDisplay (0) { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString jumpSetting = settings.settingValue ("table-input/jump-to-added"); - if (jumpSetting.isEmpty() || jumpSetting == "Jump and Select") // default - { - mJumpToAddedRecord = true; - mUnselectAfterJump = false; - } - else if(jumpSetting == "Jump Only") - { - mJumpToAddedRecord = true; - mUnselectAfterJump = true; - } - else - { - mJumpToAddedRecord = false; - mUnselectAfterJump = false; - } + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Tables"].update(); mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -358,7 +344,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); - connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), + connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), this, SLOT (rowAdded (const std::string &))); /// \note This signal could instead be connected to a slot that filters out changes not affecting @@ -404,7 +390,7 @@ std::vector CSVWorld::Table::getSelectedIds() const QModelIndexList selectedRows = selectionModel()->selectedRows(); int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); - for (QModelIndexList::const_iterator iter (selectedRows.begin()); + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter != selectedRows.end(); ++iter) { @@ -548,9 +534,7 @@ void CSVWorld::Table::previewRecord() void CSVWorld::Table::executeExtendedDelete() { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString configSetting = settings.settingValue ("table-input/extended-config"); - if (configSetting == "true") + if (CSMPrefs::get()["ID Tables"]["extended-config"].isTrue()) { emit extendedDeleteConfigRequest(getSelectedIds()); } @@ -562,9 +546,7 @@ void CSVWorld::Table::executeExtendedDelete() void CSVWorld::Table::executeExtendedRevert() { - CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); - QString configSetting = settings.settingValue ("table-input/extended-config"); - if (configSetting == "true") + if (CSMPrefs::get()["ID Tables"]["extended-config"].isTrue()) { emit extendedRevertConfigRequest(getSelectedIds()); } @@ -576,25 +558,6 @@ void CSVWorld::Table::executeExtendedRevert() void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { - if (name=="table-input/jump-to-added") - { - if(list.isEmpty() || list.at(0) == "Jump and Select") // default - { - mJumpToAddedRecord = true; - mUnselectAfterJump = false; - } - else if(list.at(0) == "Jump Only") - { - mJumpToAddedRecord = true; - mUnselectAfterJump = true; - } - else // No Jump - { - mJumpToAddedRecord = false; - mUnselectAfterJump = false; - } - } - if (name=="records/type-format" || name=="records/status-format") { int columns = mModel->columnCount(); @@ -650,6 +613,29 @@ void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList } } +void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="ID Tables/jump-to-added") + { + if (setting->toString()=="Jump and Select") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = false; + } + else if (setting->toString()=="Jump Only") + { + mJumpToAddedRecord = true; + mUnselectAfterJump = true; + } + else // No Jump + { + mJumpToAddedRecord = false; + mUnselectAfterJump = false; + } + } + +} + void CSVWorld::Table::tableSizeUpdate() { int size = 0; diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 95a25075d3..53401a1927 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -27,6 +27,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class CommandDelegate; @@ -140,6 +145,8 @@ namespace CSVWorld public slots: + void settingChanged (const CSMPrefs::Setting *setting); + void tableSizeUpdate(); void selectionSizeUpdate(); From 850092a5e576c278f85edd99686813f3e8629282 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Dec 2015 17:22:46 +0100 Subject: [PATCH 1682/1812] Store: be consistent about struct / class usage Don't inherit a struct from a class, and vice versa. --- apps/openmw/mwworld/store.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 88457c950e..617c3552af 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -27,8 +27,9 @@ namespace MWWorld RecordId(const std::string &id = "", bool isDeleted = false); }; - struct StoreBase + class StoreBase { + public: virtual ~StoreBase() {} virtual void setUp() {} @@ -351,14 +352,16 @@ namespace MWWorld template <> - struct Store : public IndexedStore + class Store : public IndexedStore { + public: Store(); }; template <> - struct Store : public IndexedStore + class Store : public IndexedStore { + public: Store(); }; From 18cce3a6f912e6fa56aa0d125c687e7debefc1c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 22:33:14 +0100 Subject: [PATCH 1683/1812] Don't reset delete flag when loading reference from a save game (Fixes #2724) --- apps/openmw/mwworld/livecellref.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 4 ++-- apps/openmw/mwworld/refdata.hpp | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index bfc708185d..dcd6da431f 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -19,7 +19,7 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(std::string type, const ESM::CellRef & void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) { mRef = state.mRef; - mData = RefData (state); + mData = RefData (state, mData.isDeletedByContentFile()); Ptr ptr (this); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 997b3fc94b..6a127085cc 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -49,8 +49,8 @@ namespace MWWorld { } - RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode(0), mDeleted(false), + RefData::RefData (const ESM::ObjectState& objectState, bool deleted) + : mBaseNode(0), mDeleted(deleted), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 19c31a14b5..fbb951c5af 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -30,10 +30,14 @@ namespace MWWorld MWScript::Locals mLocals; - bool mDeleted; // separate delete flag used for deletion by a content file - bool mEnabled; - int mCount; // 0: deleted + /// separate delete flag used for deletion by a content file + /// @note not stored in the save game file. + bool mDeleted; + bool mEnabled; + + /// 0: deleted + int mCount; ESM::Position mPosition; @@ -51,10 +55,10 @@ namespace MWWorld /// @param cellRef Used to copy constant data such as position into this class where it can /// be altered without affecting the original data. This makes it possible - /// to reset the position as the orignal data is still held in the CellRef + /// to reset the position as the original data is still held in the CellRef RefData (const ESM::CellRef& cellRef); - RefData (const ESM::ObjectState& objectState); + RefData (const ESM::ObjectState& objectState, bool deleted); ///< Ignores local variables and custom data (not enough context available here to /// perform these operations). From 359b0b377271efb985bcfda20ed3344a58e50820 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 22:37:23 +0100 Subject: [PATCH 1684/1812] Rename for clarity --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 18 +++++++++--------- apps/openmw/mwworld/refdata.hpp | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 2173820ad1..164ce55331 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -184,7 +184,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); if (deleted) - liveCellRef.mData.setDeleted(true); + liveCellRef.mData.setDeletedByContentFile(true); if (iter != mList.end()) *iter = liveCellRef; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 6a127085cc..56abba1657 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -18,7 +18,7 @@ namespace MWWorld mCount = refData.mCount; mPosition = refData.mPosition; mChanged = refData.mChanged; - mDeleted = refData.mDeleted; + mDeletedByContentFile = refData.mDeletedByContentFile; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -32,7 +32,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -42,15 +42,15 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mDeleted(false), mEnabled (true), + : mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged { } - RefData::RefData (const ESM::ObjectState& objectState, bool deleted) - : mBaseNode(0), mDeleted(deleted), + RefData::RefData (const ESM::ObjectState& objectState, bool deletedByContentFile) + : mBaseNode(0), mDeletedByContentFile(deletedByContentFile), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), @@ -139,19 +139,19 @@ namespace MWWorld mCount = count; } - void RefData::setDeleted(bool deleted) + void RefData::setDeletedByContentFile(bool deleted) { - mDeleted = deleted; + mDeletedByContentFile = deleted; } bool RefData::isDeleted() const { - return mDeleted || mCount == 0; + return mDeletedByContentFile || mCount == 0; } bool RefData::isDeletedByContentFile() const { - return mDeleted; + return mDeletedByContentFile; } MWScript::Locals& RefData::getLocals() diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index fbb951c5af..5421ea9634 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -32,7 +32,7 @@ namespace MWWorld /// separate delete flag used for deletion by a content file /// @note not stored in the save game file. - bool mDeleted; + bool mDeletedByContentFile; bool mEnabled; @@ -58,7 +58,7 @@ namespace MWWorld /// to reset the position as the original data is still held in the CellRef RefData (const ESM::CellRef& cellRef); - RefData (const ESM::ObjectState& objectState, bool deleted); + RefData (const ESM::ObjectState& objectState, bool deletedByContentFile); ///< Ignores local variables and custom data (not enough context available here to /// perform these operations). @@ -91,7 +91,7 @@ namespace MWWorld /// This flag is only used for content stack loading and will not be stored in the savegame. /// If the object was deleted by gameplay, then use setCount(0) instead. - void setDeleted(bool deleted); + void setDeletedByContentFile(bool deleted); /// Returns true if the object was either deleted by the content file or by gameplay. bool isDeleted() const; From 295563ba6594d991242e749f370f8b7d1f93c3f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 18:33:55 +0100 Subject: [PATCH 1685/1812] Minor fix --- components/resource/niffilemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index fd25c1c409..17165bcda4 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -55,7 +55,7 @@ namespace Resource return static_cast(obj.get())->mNifFile; else { - Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->get(name), name)); + Nif::NIFFilePtr file (new Nif::NIFFile(mVFS->getNormalized(name), name)); obj = new NifFileHolder(file); mCache->addEntryToObjectCache(name, obj); return file; From 64424e72626bff7abd1f87bd2dba530447495f58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Dec 2015 18:52:06 +0100 Subject: [PATCH 1686/1812] Move keyframe loading out of SceneManager to new KeyframeManager --- apps/openmw/mwrender/animation.cpp | 3 +- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.hpp | 11 +++++- components/resource/keyframemanager.cpp | 41 +++++++++++++++++++++ components/resource/keyframemanager.hpp | 47 +++++++++++++++++++++++++ components/resource/niffilemanager.cpp | 2 -- components/resource/resourcesystem.cpp | 9 ++++- components/resource/resourcesystem.hpp | 3 ++ components/resource/scenemanager.cpp | 25 ------------- components/resource/scenemanager.hpp | 11 ------ 10 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 components/resource/keyframemanager.cpp create mode 100644 components/resource/keyframemanager.hpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 214e7f2217..c285ba434d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include // KeyframeHolder @@ -402,7 +403,7 @@ namespace MWRender boost::shared_ptr animsrc; animsrc.reset(new AnimSource); - animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname); + animsrc->mKeyframes = mResourceSystem->getKeyframeManager()->get(kfname); if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty()) return; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a1ac53d1b1..bbbff234c4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,7 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache + scenemanager keyframemanager texturemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache ) add_component_dir (sceneutil diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 54f067e984..e15df53028 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -37,11 +37,20 @@ namespace NifOsg }; - class KeyframeHolder : public osg::Referenced + class KeyframeHolder : public osg::Object { public: + KeyframeHolder() {} + KeyframeHolder(const KeyframeHolder& copy, const osg::CopyOp& copyop) + : mTextKeys(copy.mTextKeys) + , mKeyframeControllers(copy.mKeyframeControllers) + { + } + TextKeyMap mTextKeys; + META_Object(OpenMW, KeyframeHolder) + typedef std::map > KeyframeControllerMap; KeyframeControllerMap mKeyframeControllers; }; diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp new file mode 100644 index 0000000000..860e9033f7 --- /dev/null +++ b/components/resource/keyframemanager.cpp @@ -0,0 +1,41 @@ +#include "keyframemanager.hpp" + +#include +#include + +#include "objectcache.hpp" + +namespace Resource +{ + + KeyframeManager::KeyframeManager(const VFS::Manager* vfs) + : mCache(new osgDB::ObjectCache) + , mVFS(vfs) + { + } + + KeyframeManager::~KeyframeManager() + { + } + + osg::ref_ptr KeyframeManager::get(const std::string &name) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); + if (obj) + return osg::ref_ptr(static_cast(obj.get())); + else + { + osg::ref_ptr loaded (new NifOsg::KeyframeHolder); + NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); + + mCache->addEntryToObjectCache(name, loaded); + return loaded; + } + } + + + +} diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp new file mode 100644 index 0000000000..5032d0e389 --- /dev/null +++ b/components/resource/keyframemanager.hpp @@ -0,0 +1,47 @@ +#ifndef OPENMW_COMPONENTS_KEYFRAMEMANAGER_H +#define OPENMW_COMPONENTS_KEYFRAMEMANAGER_H + +#include +#include + +namespace VFS +{ + class Manager; +} + +namespace osgDB +{ + class ObjectCache; +} + +namespace NifOsg +{ + class KeyframeHolder; +} + +namespace Resource +{ + + /// @brief Managing of keyframe resources + class KeyframeManager + { + public: + KeyframeManager(const VFS::Manager* vfs); + ~KeyframeManager(); + + void clearCache(); + + /// Retrieve a read-only keyframe resource by name (case-insensitive). + /// @note This method is safe to call from any thread. + /// @note Throws an exception if the resource is not found. + osg::ref_ptr get(const std::string& name); + + private: + osg::ref_ptr mCache; + + const VFS::Manager* mVFS; + }; + +} + +#endif diff --git a/components/resource/niffilemanager.cpp b/components/resource/niffilemanager.cpp index 17165bcda4..1d8019b69d 100644 --- a/components/resource/niffilemanager.cpp +++ b/components/resource/niffilemanager.cpp @@ -4,8 +4,6 @@ #include "objectcache.hpp" -#include - namespace Resource { diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 2dfd30314e..2ce8d22e6a 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -3,6 +3,7 @@ #include "scenemanager.hpp" #include "texturemanager.hpp" #include "niffilemanager.hpp" +#include "keyframemanager.hpp" namespace Resource { @@ -11,6 +12,7 @@ namespace Resource : mVFS(vfs) { mNifFileManager.reset(new NifFileManager(vfs)); + mKeyframeManager.reset(new KeyframeManager(vfs)); mTextureManager.reset(new TextureManager(vfs)); mSceneManager.reset(new SceneManager(vfs, mTextureManager.get(), mNifFileManager.get())); } @@ -30,11 +32,16 @@ namespace Resource return mTextureManager.get(); } - NifFileManager *ResourceSystem::getNifFileManager() + NifFileManager* ResourceSystem::getNifFileManager() { return mNifFileManager.get(); } + KeyframeManager* ResourceSystem::getKeyframeManager() + { + return mKeyframeManager.get(); + } + void ResourceSystem::clearCache() { mNifFileManager->clearCache(); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index 7f90bff27a..3e1a793cac 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -14,6 +14,7 @@ namespace Resource class SceneManager; class TextureManager; class NifFileManager; + class KeyframeManager; /// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems. /// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but @@ -27,6 +28,7 @@ namespace Resource SceneManager* getSceneManager(); TextureManager* getTextureManager(); NifFileManager* getNifFileManager(); + KeyframeManager* getKeyframeManager(); /// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced. void clearCache(); @@ -37,6 +39,7 @@ namespace Resource std::auto_ptr mSceneManager; std::auto_ptr mTextureManager; std::auto_ptr mNifFileManager; + std::auto_ptr mKeyframeManager; const VFS::Manager* mVFS; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3ee7a8c001..1d1c5a3656 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -233,31 +233,6 @@ namespace Resource return cloned; } - osg::ref_ptr SceneManager::getKeyframes(const std::string &name) - { - std::string normalized = name; - mVFS->normalizeFilename(normalized); - - KeyframeIndex::iterator it = mKeyframeIndex.find(normalized); - if (it == mKeyframeIndex.end()) - { - Files::IStreamPtr file = mVFS->get(normalized); - - std::string ext = getFileExtension(normalized); - - if (ext != "nif" && ext != "kf") - return NULL; - - osg::ref_ptr loaded (new NifOsg::KeyframeHolder); - NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get()); - - mKeyframeIndex[normalized] = loaded; - return loaded; - } - else - return it->second; - } - void SceneManager::attachTo(osg::Node *instance, osg::Group *parentNode) const { parentNode->addChild(instance); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 3c1984fd91..67fa2ab433 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -18,11 +18,6 @@ namespace VFS class Manager; } -namespace NifOsg -{ - class KeyframeHolder; -} - namespace osgUtil { class IncrementalCompileOperation; @@ -57,9 +52,6 @@ namespace Resource /// @note Assumes the given instance was not attached to any parents before. void attachTo(osg::Node* instance, osg::Group* parentNode) const; - /// Get a read-only copy of the given keyframe file. - osg::ref_ptr getKeyframes(const std::string& name); - /// Manually release created OpenGL objects for the given graphics context. This may be required /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); @@ -90,9 +82,6 @@ namespace Resource typedef std::map > Index; Index mIndex; - typedef std::map > KeyframeIndex; - KeyframeIndex mKeyframeIndex; - SceneManager(const SceneManager&); void operator = (const SceneManager&); }; From a7e0562e1c78429ec05a21cfe0412ba3b7a66d29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 Dec 2015 17:42:11 +0100 Subject: [PATCH 1687/1812] Fix improper handling of multiple AiFollow packages with the same target (Fixes #3077) --- apps/openmw/mwmechanics/actors.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index eb837613b2..c4cd8ee4b9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1333,8 +1333,7 @@ namespace MWMechanics continue; if (followTarget == actor) list.push_back(static_cast(*it)->getFollowIndex()); - else - break; + break; } else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) break; From 76bde5ee13de76d15a9a355906fa2dfe909dbcd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 11:24:23 -0800 Subject: [PATCH 1688/1812] Separate and expand texture filtering options --- apps/openmw/engine.cpp | 35 +++++++++++++++++++---- apps/openmw/mwgui/settingswindow.cpp | 26 +++++++++++++++-- apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 30 ++++++++++++++++--- files/mygui/openmw_settings_window.layout | 14 +++++++-- files/settings-default.cfg | 7 +++-- 6 files changed, 96 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6c360acf6e..86ccb7b3b3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -451,12 +451,35 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); - osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if (Settings::Manager::getString("texture filtering", "General") == "trilinear") - min = osg::Texture::LINEAR_MIPMAP_LINEAR; - int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); - mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + { + osg::Texture::FilterMode min = osg::Texture::LINEAR; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + std::string filter = Settings::Manager::getString("texture filtering", "General"); + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + + std::string mipmap = Settings::Manager::getString("texture mipmapping", "General"); + if(mipmap == "nearest") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_NEAREST; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_NEAREST; + } + else if(mipmap != "none") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_LINEAR; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + } + int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); + mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); + } // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 78ff965328..72c0042711 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -37,10 +37,20 @@ namespace std::string textureFilteringToStr(const std::string& val) { - if (val == "trilinear") - return "Trilinear"; + if (val == "nearest") + return "Nearest"; else - return "Bilinear"; + return "Linear"; + } + + std::string textureMipmappingToStr(const std::string& val) + { + if (val == "linear") + return "Linear"; + else if (val == "none") + return "None"; + else + return "Nearest"; } void parseResolution (int &x, int &y, const std::string& str) @@ -169,6 +179,7 @@ namespace MWGui getWidget(mFOVSlider, "FOVSlider"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); + getWidget(mTextureMipmappingButton, "TextureMipmappingButton"); getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); @@ -200,6 +211,7 @@ namespace MWGui mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); + mTextureMipmappingButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureMipmappingChanged); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -237,6 +249,8 @@ namespace MWGui std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); + std::string tmip = Settings::Manager::getString("texture mipmapping", "General"); + mTextureMipmappingButton->setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); @@ -429,6 +443,12 @@ namespace MWGui apply(); } + void SettingsWindow::onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos) + { + Settings::Manager::setString("texture mipmapping", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); + apply(); + } + void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { if (getSettingType(scroller) == "Slider") diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 99553808b4..da9c8628e0 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -34,6 +34,7 @@ namespace MWGui MyGUI::ScrollBar* mDifficultySlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::ComboBox* mTextureFilteringButton; + MyGUI::ComboBox* mTextureMipmappingButton; MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; @@ -53,6 +54,7 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); + void onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4b208fa944..f66398d2f3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -781,11 +781,31 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { - osg::Texture::FilterMode min = osg::Texture::LINEAR_MIPMAP_NEAREST; + osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if (Settings::Manager::getString("texture filtering", "General") == "trilinear") - min = osg::Texture::LINEAR_MIPMAP_LINEAR; + std::string filter = Settings::Manager::getString("texture filtering", "General"); + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + + std::string mipmap = Settings::Manager::getString("texture mipmapping", "General"); + if(mipmap == "nearest") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_NEAREST; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_NEAREST; + } + else if(mipmap != "none") + { + if(min == osg::Texture::NEAREST) + min = osg::Texture::NEAREST_MIPMAP_LINEAR; + else if(min == osg::Texture::LINEAR) + min = osg::Texture::LINEAR_MIPMAP_LINEAR; + } int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); @@ -826,7 +846,9 @@ namespace MWRender mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } - else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) + else if (it->first == "General" && (it->second == "texture filtering" || + it->second == "texture mipmapping" || + it->second == "anisotropy")) updateTextureFiltering(); else if (it->first == "Water") mWater->processChangedSettings(changed); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6d2424aa5b..df268eec40 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -322,10 +322,18 @@ - - + + - + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a5fd3cccd0..c9132dadad 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -110,8 +110,11 @@ anisotropy = 4 # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Isotropic texture filtering. (bilinear or trilinear). -texture filtering = trilinear +# Texture filtering. (nearest or linear). +texture filtering = linear + +# Texture mipmapping. (none, nearest, or linear). +texture mipmapping = nearest [Input] From fb6abb53aeb8d3e65a5ddc376df2a80530b008cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 15:02:36 -0800 Subject: [PATCH 1689/1812] Simplify the in-game texture options This makes it behave like it originally did, although the config options remain expanded. --- apps/openmw/mwgui/settingswindow.cpp | 38 +++++++---------------- apps/openmw/mwgui/settingswindow.hpp | 1 - files/mygui/openmw_settings_window.layout | 14 ++------- 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 72c0042711..b9aa3aa267 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -35,22 +35,13 @@ namespace return "#{sOn}"; } - std::string textureFilteringToStr(const std::string& val) - { - if (val == "nearest") - return "Nearest"; - else - return "Linear"; - } - std::string textureMipmappingToStr(const std::string& val) { - if (val == "linear") - return "Linear"; - else if (val == "none") - return "None"; - else - return "Nearest"; + if (val == "linear") return "Trilinear"; + if (val == "nearest") return "Bilinear"; + if (val != "none") + std::cerr<< "Invalid texture mipmap option: "<eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mTextureMipmappingButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureMipmappingChanged); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -247,10 +236,8 @@ namespace MWGui } highlightCurrentResolution(); - std::string tf = Settings::Manager::getString("texture filtering", "General"); - mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); std::string tmip = Settings::Manager::getString("texture mipmapping", "General"); - mTextureMipmappingButton->setCaption(textureMipmappingToStr(tmip)); + mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); @@ -439,13 +426,12 @@ namespace MWGui void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { - Settings::Manager::setString("texture filtering", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); - apply(); - } - - void SettingsWindow::onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos) - { - Settings::Manager::setString("texture mipmapping", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); + if(pos == 0) + Settings::Manager::setString("texture mipmapping", "General", "nearest"); + else if(pos == 1) + Settings::Manager::setString("texture mipmapping", "General", "linear"); + else + std::cerr<< "Unexpected option pos "< - - + + - - - - - - - - - + From 646092ce3ad88edeb001216c03cc31a70072d141 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 15:20:59 -0800 Subject: [PATCH 1690/1812] Add warnings when loading unknown texture options --- apps/openmw/engine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 86ccb7b3b3..eeba6e65ca 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -461,6 +461,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) min = osg::Texture::NEAREST; mag = osg::Texture::NEAREST; } + else if(filter != "linear") + std::cerr<< "Invalid texture filtering option: "< Date: Sun, 13 Dec 2015 16:02:09 -0800 Subject: [PATCH 1691/1812] Rename the texture filter options To avoid compatibility issues with upgrading from or downgrading to older builds. --- apps/openmw/engine.cpp | 8 ++++---- apps/openmw/mwgui/settingswindow.cpp | 6 +++--- apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- files/settings-default.cfg | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index eeba6e65ca..1441f8b4f5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -455,16 +455,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - std::string filter = Settings::Manager::getString("texture filtering", "General"); + std::string filter = Settings::Manager::getString("texture filter", "General"); if(filter == "nearest") { min = osg::Texture::NEAREST; mag = osg::Texture::NEAREST; } else if(filter != "linear") - std::cerr<< "Invalid texture filtering option: "<setCaption(textureMipmappingToStr(tmip)); mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); @@ -427,9 +427,9 @@ namespace MWGui void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { if(pos == 0) - Settings::Manager::setString("texture mipmapping", "General", "nearest"); + Settings::Manager::setString("texture mipmap", "General", "nearest"); else if(pos == 1) - Settings::Manager::setString("texture mipmapping", "General", "linear"); + Settings::Manager::setString("texture mipmap", "General", "linear"); else std::cerr<< "Unexpected option pos "<setFogEnd(mViewDistance); updateProjectionMatrix(); } - else if (it->first == "General" && (it->second == "texture filtering" || - it->second == "texture mipmapping" || + else if (it->first == "General" && (it->second == "texture filter" || + it->second == "texture mipmap" || it->second == "anisotropy")) updateTextureFiltering(); else if (it->first == "Water") diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c9132dadad..b77b95c52b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -110,11 +110,11 @@ anisotropy = 4 # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png -# Texture filtering. (nearest or linear). -texture filtering = linear +# Texture filter type. (nearest or linear). +texture filter = linear -# Texture mipmapping. (none, nearest, or linear). -texture mipmapping = nearest +# Texture mipmap type. (none, nearest, or linear). +texture mipmap = nearest [Input] From fb9f5f8fe865e92477b2216f8751682aefcda1eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 01:36:53 +0100 Subject: [PATCH 1692/1812] Fix typo --- apps/opencs/model/world/nestedcoladapterimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 002838c67d..bfacc15dc9 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -606,7 +606,7 @@ namespace CSMWorld funcMap["09"] = "PC Fatigue"; funcMap["10"] = "PC Strength"; funcMap["11"] = "PC Block"; - funcMap["12"] = "PC Armoror"; + funcMap["12"] = "PC Armorer"; funcMap["13"] = "PC Medium Armor"; funcMap["14"] = "PC Heavy Armor"; funcMap["15"] = "PC Blunt Weapon"; From 5c0a847eafb2c3c31850870709d65b3ee8631254 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 16:51:27 -0800 Subject: [PATCH 1693/1812] Combine some duplicate code --- apps/openmw/engine.cpp | 39 ++++------------------- apps/openmw/mwrender/renderingmanager.cpp | 37 ++++----------------- components/resource/texturemanager.cpp | 36 +++++++++++++++++++++ components/resource/texturemanager.hpp | 12 +++++-- 4 files changed, 58 insertions(+), 66 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1441f8b4f5..50f097ce72 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -451,39 +451,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); - { - osg::Texture::FilterMode min = osg::Texture::LINEAR; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - - std::string filter = Settings::Manager::getString("texture filter", "General"); - if(filter == "nearest") - { - min = osg::Texture::NEAREST; - mag = osg::Texture::NEAREST; - } - else if(filter != "linear") - std::cerr<< "Invalid texture filter option: "<getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); - } + mResourceSystem->getTextureManager()->setFilterSettings( + Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mipmap", "General"), + Settings::Manager::getInt("anisotropy", "General"), + NULL + ); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index edc877ad43..ceea7ce970 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -781,37 +781,12 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { - osg::Texture::FilterMode min = osg::Texture::LINEAR; - osg::Texture::FilterMode mag = osg::Texture::LINEAR; - - std::string filter = Settings::Manager::getString("texture filter", "General"); - if(filter == "nearest") - { - min = osg::Texture::NEAREST; - mag = osg::Texture::NEAREST; - } - - std::string mipmap = Settings::Manager::getString("texture mipmap", "General"); - if(mipmap == "nearest") - { - if(min == osg::Texture::NEAREST) - min = osg::Texture::NEAREST_MIPMAP_NEAREST; - else if(min == osg::Texture::LINEAR) - min = osg::Texture::LINEAR_MIPMAP_NEAREST; - } - else if(mipmap != "none") - { - if(min == osg::Texture::NEAREST) - min = osg::Texture::NEAREST_MIPMAP_LINEAR; - else if(min == osg::Texture::LINEAR) - min = osg::Texture::LINEAR_MIPMAP_LINEAR; - } - - int maxAnisotropy = Settings::Manager::getInt("anisotropy", "General"); - - mViewer->stopThreading(); - mResourceSystem->getTextureManager()->setFilterSettings(min, mag, maxAnisotropy); - mViewer->startThreading(); + mResourceSystem->getTextureManager()->setFilterSettings( + Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mipmap", "General"), + Settings::Manager::getInt("anisotropy", "General"), + mViewer + ); } void RenderingManager::updateAmbient() diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 15ac375142..ea9e7ae5d5 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -65,6 +66,41 @@ namespace Resource mUnRefImageDataAfterApply = unref; } + void TextureManager::setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, osgViewer::Viewer *viewer) + { + osg::Texture::FilterMode min = osg::Texture::LINEAR; + osg::Texture::FilterMode mag = osg::Texture::LINEAR; + + if(filter == "nearest") + { + min = osg::Texture::NEAREST; + mag = osg::Texture::NEAREST; + } + else if(filter != "linear") + std::cerr<< "Invalid texture filter: "<stopThreading(); + setFilterSettings(min, mag, maxAnisotropy); + if(viewer) viewer->startThreading(); + } + void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy) { mMinFilter = minFilter; diff --git a/components/resource/texturemanager.hpp b/components/resource/texturemanager.hpp index 0f40d7dfec..c7b4d4f595 100644 --- a/components/resource/texturemanager.hpp +++ b/components/resource/texturemanager.hpp @@ -8,6 +8,11 @@ #include #include +namespace osgViewer +{ + class Viewer; +} + namespace VFS { class Manager; @@ -23,8 +28,8 @@ namespace Resource TextureManager(const VFS::Manager* vfs); ~TextureManager(); - /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! - void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); + void setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *view); /// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts, /// otherwise should be disabled to reduce memory usage. @@ -58,6 +63,9 @@ namespace Resource bool mUnRefImageDataAfterApply; + /// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first! + void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy); + TextureManager(const TextureManager&); void operator = (const TextureManager&); }; From 2737aabe93cde10ece0857ed4bbd10aac1bf90d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 01:52:13 +0100 Subject: [PATCH 1694/1812] Pc functions apply to creature dialogue (Fixes #3078) --- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwdialogue/selectwrapper.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index e3a773b052..d41820b71c 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -313,7 +313,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con int value = 0; - for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition + for (int i=0; i<=15; ++i) // everything except things held in hands and ammunition { MWWorld::ContainerStoreIterator slot = store.getSlot (i); diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index a4eba30ae4..68c88e9437 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -263,10 +263,6 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { Function_NotFaction, Function_NotClass, Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, - Function_PcSkill, - Function_PcExpelled, - Function_PcVampire, - Function_PcCrimeLevel, Function_RankRequirement, Function_Reputation, Function_FactionRankDiff, Function_Werewolf, Function_WerewolfKills, From f1faeeae3a765c3967270c36239fd84f5d798205 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Dec 2015 17:05:19 -0800 Subject: [PATCH 1695/1812] Use separate config options for min and mag texture filters --- apps/openmw/engine.cpp | 3 ++- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/resource/texturemanager.cpp | 18 +++++++++++------- components/resource/texturemanager.hpp | 3 ++- files/settings-default.cfg | 7 +++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 50f097ce72..b43fd2f530 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -452,7 +452,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true); mResourceSystem->getTextureManager()->setFilterSettings( - Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mag filter", "General"), + Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), Settings::Manager::getInt("anisotropy", "General"), NULL diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ceea7ce970..b44d777220 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -782,7 +782,8 @@ namespace MWRender void RenderingManager::updateTextureFiltering() { mResourceSystem->getTextureManager()->setFilterSettings( - Settings::Manager::getString("texture filter", "General"), + Settings::Manager::getString("texture mag filter", "General"), + Settings::Manager::getString("texture min filter", "General"), Settings::Manager::getString("texture mipmap", "General"), Settings::Manager::getInt("anisotropy", "General"), mViewer diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index ea9e7ae5d5..d7f3fc61a1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -66,18 +66,22 @@ namespace Resource mUnRefImageDataAfterApply = unref; } - void TextureManager::setFilterSettings(const std::string &filter, const std::string &mipmap, int maxAnisotropy, osgViewer::Viewer *viewer) + void TextureManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter, + const std::string &mipmap, int maxAnisotropy, + osgViewer::Viewer *viewer) { osg::Texture::FilterMode min = osg::Texture::LINEAR; osg::Texture::FilterMode mag = osg::Texture::LINEAR; - if(filter == "nearest") - { - min = osg::Texture::NEAREST; + if(magfilter == "nearest") mag = osg::Texture::NEAREST; - } - else if(filter != "linear") - std::cerr<< "Invalid texture filter: "< Date: Sun, 13 Dec 2015 17:13:36 -0800 Subject: [PATCH 1696/1812] Remove left over declaration --- apps/openmw/mwgui/settingswindow.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 5910f07e00..99553808b4 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -53,7 +53,6 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); - void onTextureMipmappingChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); From 271fcb80c6fd42d15fae3856e8f28269eb44ccf1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 02:57:55 +0100 Subject: [PATCH 1697/1812] Remove container scripts before deleting container --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwclass/container.cpp | 1 + apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwscript/statsextensions.cpp | 1 + apps/openmw/mwworld/localscripts.hpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 3 ++- 7 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a7ff9b35bf..ba48aa910c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -549,6 +549,8 @@ namespace MWBase /// Return the distance between actor's weapon and target's collision box. virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + + virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b600cf3536..c9f9f3740e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -77,6 +77,7 @@ namespace MWClass ptr.get(); if (ref->mBase->mFlags & ESM::Container::Respawn) { + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e5a98c8893..d6270077d6 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -762,6 +762,7 @@ namespace MWClass // Reset to original position ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 41894c1dcb..60ab73e04d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1224,6 +1224,7 @@ namespace MWClass // Reset to original position ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 3996dd80b4..dcac733117 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1127,6 +1127,7 @@ namespace MWScript { MWBase::Environment::get().getWorld()->undeleteObject(ptr); // resets runtime state such as inventory, stats and AI. does not reset position in the world + MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); ptr.getRefData().setCustomData(NULL); } } diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 9d612cb33c..5a156a2e97 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -52,7 +52,7 @@ namespace MWWorld void remove (RefData *ref); void remove (const Ptr& ptr); - ///< Remove script for given reference (ignored if reference does not have a scirpt listed). + ///< Remove script for given reference (ignored if reference does not have a script listed). }; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f08ede1005..7132132874 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -129,8 +129,9 @@ namespace MWWorld void updateWindowManager (); void updatePlayer(bool paused); MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); - + public: // FIXME void removeContainerScripts(const Ptr& reference); + private: void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); From 572786bff27e270b9666bc86d64990101998ceb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 03:27:49 +0100 Subject: [PATCH 1698/1812] Instant effects that were added by a permanent ability are applied every frame Via http://forum.openmw.org/viewtopic.php?f=2&t=3212&p=36120#p36121 --- apps/openmw/mwmechanics/actors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c4cd8ee4b9..185364fae7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -486,11 +486,14 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - // tickable effects (i.e. effects having a lasting impact after expiry) - // these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) { + // tickable effects (i.e. effects having a lasting impact after expiry) effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + + // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); } // attributes From 076dc539bc67ff1b979ac3c4ded838ade561ae49 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 15:11:06 +0100 Subject: [PATCH 1699/1812] KeyframeManager fix --- components/resource/keyframemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 860e9033f7..7e948dcb03 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -31,7 +31,7 @@ namespace Resource osg::ref_ptr loaded (new NifOsg::KeyframeHolder); NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); - mCache->addEntryToObjectCache(name, loaded); + mCache->addEntryToObjectCache(normalized, loaded); return loaded; } } From c70790ecb7e1483e747145780813eca83d5f038f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Dec 2015 15:50:30 +0100 Subject: [PATCH 1700/1812] Remove outdated comment --- components/resource/bulletshapemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 5933221906..4cbe62f3c3 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -125,7 +125,6 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: if (ext == "nif") { NifBullet::BulletNifLoader loader; - // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(mNifFileManager->get(normalized)); } else From a3a2c2f476d3a0753976dee335a200a2cbfca1c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Dec 2015 17:38:33 +0100 Subject: [PATCH 1701/1812] second batch of changing over user settings usage to the new system --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/view/tools/reportsubview.cpp | 7 +- apps/opencs/view/tools/reportsubview.hpp | 2 - apps/opencs/view/tools/reporttable.cpp | 78 +++++++++++-------- apps/opencs/view/tools/reporttable.hpp | 9 ++- apps/opencs/view/tools/searchsubview.cpp | 5 -- apps/opencs/view/tools/searchsubview.hpp | 4 +- .../opencs/view/world/datadisplaydelegate.cpp | 40 ++++------ .../opencs/view/world/datadisplaydelegate.hpp | 17 ++-- apps/opencs/view/world/dialoguesubview.cpp | 3 - apps/opencs/view/world/idtypedelegate.cpp | 2 +- apps/opencs/view/world/recordbuttonbar.cpp | 25 +++--- apps/opencs/view/world/recordbuttonbar.hpp | 13 +++- .../view/world/recordstatusdelegate.cpp | 2 +- apps/opencs/view/world/scripterrortable.cpp | 2 +- apps/opencs/view/world/scriptsubview.cpp | 75 +++++++----------- apps/opencs/view/world/scriptsubview.hpp | 9 ++- apps/opencs/view/world/table.cpp | 28 +++---- apps/opencs/view/world/util.cpp | 8 +- apps/opencs/view/world/util.hpp | 12 ++- 20 files changed, 164 insertions(+), 178 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d6250c5326..ab9fd0a28c 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -153,6 +153,7 @@ void CSMPrefs::State::declare() declareColour ("colour-special", "Highlight Colour: Special Characters", QColor ("darkorange")); declareColour ("colour-comment", "Highlight Colour: Comments", QColor ("green")); declareColour ("colour-id", "Highlight Colour: IDs", QColor ("blue")); + declareCategory ("General Input"); declareBool ("cycle", "Cyclic next/previous", false). setTooltip ("When using next/previous functions at the last/first item of a " diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index a7316359e5..c7712f29cf 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -27,11 +27,6 @@ void CSVTools::ReportSubView::setEditLock (bool locked) // ignored. We don't change document state anyway. } -void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting (name, list); -} - void CSVTools::ReportSubView::refreshRequest() { if (!(mDocument.getState() & mRefreshState)) @@ -39,7 +34,7 @@ void CSVTools::ReportSubView::refreshRequest() if (mRefreshState==CSMDoc::State_Verifying) { mTable->clear(); - mDocument.verify (getUniversalId()); + mDocument.verify (getUniversalId()); } } } diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index b8eb2690a7..9f43efdac8 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -29,8 +29,6 @@ namespace CSVTools virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString &, const QStringList &); - private slots: void refreshRequest(); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index d4cecc9719..bfc002933d 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -14,6 +14,8 @@ #include "../../model/tools/reportmodel.hpp" +#include "../../model/prefs/state.hpp" + #include "../../view/world/idtypedelegate.hpp" namespace CSVTools @@ -189,6 +191,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Reports"].update(); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -206,40 +212,6 @@ std::vector CSVTools::ReportTable::getDraggedRecords() co return ids; } -void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) -{ - mIdTypeDelegate->updateUserSetting (name, list); - - QString base ("report-input/double"); - if (name.startsWith (base)) - { - QString modifierString = name.mid (base.size()); - Qt::KeyboardModifiers modifiers = 0; - - if (modifierString=="-s") - modifiers = Qt::ShiftModifier; - else if (modifierString=="-c") - modifiers = Qt::ControlModifier; - else if (modifierString=="-sc") - modifiers = Qt::ShiftModifier | Qt::ControlModifier; - - DoubleClickAction action = Action_None; - - QString value = list.at (0); - - if (value=="Edit") - action = Action_Edit; - else if (value=="Remove") - action = Action_Remove; - else if (value=="Edit And Remove") - action = Action_EditAndRemove; - - mDoubleClickActions[modifiers] = action; - - return; - } -} - std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const { std::vector indices; @@ -285,6 +257,44 @@ void CSVTools::ReportTable::flagAsReplaced (int index) mModel->flagAsReplaced (index); } +void CSVTools::ReportTable::settingChanged (const CSMPrefs::Setting *setting) +{ + if (setting->getParent()->getKey()=="Reports") + { + QString base ("double"); + QString key = setting->getKey().c_str(); + if (key.startsWith (base)) + { + QString modifierString = key.mid (base.size()); + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + std::string value = setting->toString(); + + if (value=="Edit") + action = Action_Edit; + else if (value=="Remove") + action = Action_Remove; + else if (value=="Edit And Remove") + action = Action_EditAndRemove; + + mDoubleClickActions[modifiers] = action; + + return; + } + } + else if (*setting=="Records/type-format") + mIdTypeDelegate->settingChanged (setting); +} + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index c847b2d478..88936d3c3b 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -13,6 +13,11 @@ namespace CSMTools class ReportModel; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class CommandDelegate; @@ -61,8 +66,6 @@ namespace CSVTools virtual std::vector getDraggedRecords() const; - void updateUserSetting (const QString& name, const QStringList& list); - void clear(); /// Return indices of rows that are suitable for replacement. @@ -77,6 +80,8 @@ namespace CSVTools private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void showSelection(); void removeSelection(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index d3fdbbf5da..c2cdd10a8e 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -102,11 +102,6 @@ void CSVTools::SearchSubView::setEditLock (bool locked) mSearchBox.setEditLock (locked); } -void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting (name, list); -} - void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 2e96b98b50..ac0a5a762d 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -36,15 +36,13 @@ namespace CSVTools protected: void showEvent (QShowEvent *event); - + public: SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString &, const QStringList &); - private slots: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 72f45a18c1..51d7137ec5 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -1,5 +1,6 @@ #include "datadisplaydelegate.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" #include #include @@ -8,8 +9,8 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, - const QString &pageName, - const QString &settingName, + const std::string &pageName, + const std::string &settingName, QObject *parent) : EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly), mIcons (icons), mIconSize (QSize(16, 16)), @@ -18,10 +19,8 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, { buildPixmaps(); - QString value = - CSMSettings::UserSettings::instance().settingValue (mSettingKey); - - updateDisplayMode(value); + if (!pageName.empty()) + updateDisplayMode (CSMPrefs::get()[pageName][settingName].toString()); } void CSVWorld::DataDisplayDelegate::buildPixmaps () @@ -52,7 +51,7 @@ void CSVWorld::DataDisplayDelegate::setTextLeftOffset(int offset) QSize CSVWorld::DataDisplayDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = EnumDelegate::sizeHint(option, index); - + int valueIndex = getValueIndex(index); if (valueIndex != -1) { @@ -105,7 +104,7 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp textRect.setLeft(iconRect.right() + mTextLeftOffset); textRect.setRight(option.rect.right() - mHorizontalMargin); - QString text = option.fontMetrics.elidedText(mValues.at(index).second, + QString text = option.fontMetrics.elidedText(mValues.at(index).second, option.textElideMode, textRect.width()); QApplication::style()->drawItemText(painter, @@ -118,19 +117,7 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp QApplication::style()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, mPixmaps.at(index).second); } -void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name, - const QStringList &list) -{ - if (list.isEmpty()) - return; - - QString value = list.at(0); - - if (name == mSettingKey) - updateDisplayMode (value); -} - -void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode) +void CSVWorld::DataDisplayDelegate::updateDisplayMode (const std::string &mode) { if (mode == "Icon and Text") mDisplayMode = Mode_IconAndText; @@ -146,6 +133,13 @@ CSVWorld::DataDisplayDelegate::~DataDisplayDelegate() { } +void CSVWorld::DataDisplayDelegate::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting==mSettingKey) + updateDisplayMode (setting->toString()); +} + + void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename) { mIcons.push_back (std::make_pair(enumValue, QIcon(iconFilename))); @@ -158,5 +152,3 @@ CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate ( { return new DataDisplayDelegate (mValues, mIcons, dispatcher, document, "", "", parent); } - - diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index e565a3469e..cde109fd4c 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -4,10 +4,13 @@ #include #include "enumdelegate.hpp" +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { - - class DataDisplayDelegate : public EnumDelegate { public: @@ -34,12 +37,12 @@ namespace CSVWorld int mHorizontalMargin; int mTextLeftOffset; - QString mSettingKey; + std::string mSettingKey; public: DataDisplayDelegate (const ValueList & values, const IconList & icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, - const QString &pageName, const QString &settingName, QObject *parent); + const std::string& pageName, const std::string& settingName, QObject *parent); ~DataDisplayDelegate(); @@ -53,13 +56,10 @@ namespace CSVWorld /// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels. void setTextLeftOffset (int offset); - ///update the display mode for the delegate - void updateUserSetting (const QString &name, const QStringList &list); - private: /// update the display mode based on a passed string - void updateDisplayMode (const QString &); + void updateDisplayMode (const std::string &); /// custom paint function for painting the icon. Mode_IconAndText and Mode_Icon only. void paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int i) const; @@ -67,6 +67,7 @@ namespace CSVWorld /// rebuild the list of pixmaps from the provided icons (called when icon size is changed) void buildPixmaps(); + virtual void settingChanged (const CSMPrefs::Setting *setting); }; class DataDisplayDelegateFactory : public EnumDelegateFactory diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 61d3fb1caa..e0c167b0e3 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -919,9 +919,6 @@ void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QS } } } - - if (mButtons) - mButtons->updateUserSetting (name, value); } void CSVWorld::DialogueSubView::showPreview () diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp index 34c8d12cd7..ee35e07d41 100755 --- a/apps/opencs/view/world/idtypedelegate.cpp +++ b/apps/opencs/view/world/idtypedelegate.cpp @@ -5,7 +5,7 @@ CSVWorld::IdTypeDelegate::IdTypeDelegate (const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) : DataDisplayDelegate (values, icons, dispatcher, document, - "records", "type-format", + "Records", "type-format", parent) {} diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 1a838a3b31..40a24bf658 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -6,7 +6,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/commanddispatcher.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "../world/tablebottombox.hpp" @@ -32,7 +32,7 @@ void CSVWorld::RecordButtonBar::updatePrevNextButtons() mPrevButton->setDisabled (true); mNextButton->setDisabled (true); } - else if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")=="true") + else if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) { mPrevButton->setDisabled (false); mNextButton->setDisabled (false); @@ -131,6 +131,9 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + updateModificationButtons(); updatePrevNextButtons(); } @@ -141,18 +144,18 @@ void CSVWorld::RecordButtonBar::setEditLock (bool locked) updateModificationButtons(); } -void CSVWorld::RecordButtonBar::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="general-input/cycle") - updatePrevNextButtons(); -} - void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id) { mId = id; updatePrevNextButtons(); } +void CSVWorld::RecordButtonBar::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="General Input/cycle") + updatePrevNextButtons(); +} + void CSVWorld::RecordButtonBar::cloneRequest() { if (mBottom) @@ -173,8 +176,7 @@ void CSVWorld::RecordButtonBar::nextId() if (newRow >= mTable.rowCount()) { - if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") - =="true") + if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) newRow = 0; else return; @@ -189,8 +191,7 @@ void CSVWorld::RecordButtonBar::prevId() if (newRow < 0) { - if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle") - =="true") + if (CSMPrefs::get()["General Input"]["cycle"].isTrue()) newRow = mTable.rowCount()-1; else return; diff --git a/apps/opencs/view/world/recordbuttonbar.hpp b/apps/opencs/view/world/recordbuttonbar.hpp index 93ca45518e..fbee066cea 100644 --- a/apps/opencs/view/world/recordbuttonbar.hpp +++ b/apps/opencs/view/world/recordbuttonbar.hpp @@ -14,6 +14,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class TableBottomBox; @@ -49,7 +54,7 @@ namespace CSVWorld void updateModificationButtons(); void updatePrevNextButtons(); - + public: RecordButtonBar (const CSMWorld::UniversalId& id, @@ -58,14 +63,14 @@ namespace CSVWorld void setEditLock (bool locked); - void updateUserSetting (const QString& name, const QStringList& value); - public slots: void universalIdChanged (const CSMWorld::UniversalId& id); private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void cloneRequest(); void nextId(); @@ -73,7 +78,7 @@ namespace CSVWorld void prevId(); void rowNumberChanged (const QModelIndex& parent, int start, int end); - + signals: void showPreview(); diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 58a5c01774..0aec13bcfd 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -11,7 +11,7 @@ CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, const IconList & icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) : DataDisplayDelegate (values, icons, dispatcher, document, - "records", "status-format", + "Records", "status-format", parent) {} diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index b439e0df39..c22bcf1991 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -135,7 +135,7 @@ bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) void CSVWorld::ScriptErrorTable::settingChanged (const CSMPrefs::Setting *setting) { - if (*setting=="Scripst/warnings") + if (*setting=="Scripts/warnings") setWarningsMode (setting->toString()); } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index eb8bd2e29d..ee0acb560a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -13,7 +13,7 @@ #include "../../model/world/columnbase.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "scriptedit.hpp" #include "recordbuttonbar.hpp" @@ -39,8 +39,7 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { if (!mCompileDelay->isActive() && !isDeleted()) - mCompileDelay->start ( - CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); + mCompileDelay->start (CSMPrefs::get()["Scripts"]["compile-delay"].toInt()); } bool CSVWorld::ScriptSubView::isDeleted() const @@ -89,7 +88,7 @@ void CSVWorld::ScriptSubView::adjustSplitter() CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())), - mErrorHeight (CSMSettings::UserSettings::instance().setting ("script-editor/error-height").toInt()) + mErrorHeight (CSMPrefs::get()["Scripts"]["error-height"].toInt()) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); @@ -126,9 +125,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: // bottom box and buttons mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") - addButtonBar(); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (switchToId (const std::string&))); @@ -156,46 +152,10 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); updateDeletedState(); -} -void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name == "script-editor/show-linenum") - { - std::string showLinenum = value.at(0).toUtf8().constData(); - mEditor->showLineNum(showLinenum == "true"); - mBottom->setVisible(showLinenum == "true"); - } - else if (name == "script-editor/mono-font") - { - mEditor->setMonoFont (value.at(0)==QString ("true")); - } - else if (name=="script-editor/toolbar") - { - if (value.at(0)==QString ("true")) - { - addButtonBar(); - } - else - { - if (mButtons) - { - mLayout.removeWidget (mButtons); - delete mButtons; - mButtons = 0; - } - } - } - else if (name=="script-editor/compile-delay") - { - mCompileDelay->setInterval (value.at (0).toInt()); - } - - if (mButtons) - mButtons->updateUserSetting (name, value); - - if (name=="script-editor/warnings") - recompile(); + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["Scripts"].update(); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -203,6 +163,29 @@ void CSVWorld::ScriptSubView::setStatusBar (bool show) mBottom->setStatusBar (show); } +void CSVWorld::ScriptSubView::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Scripts/toolbar") + { + if (setting->isTrue()) + { + addButtonBar(); + } + else if (mButtons) + { + mLayout.removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } + else if (*setting=="Scripts/compile-delay") + { + mCompileDelay->setInterval (setting->toInt()); + } + else if (*setting=="Scripts/warnings") + recompile(); +} + void CSVWorld::ScriptSubView::updateStatusBar () { mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1, diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 179430ef90..c1016babf9 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -23,6 +23,11 @@ namespace CSMWorld class IdTable; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { class ScriptEdit; @@ -69,8 +74,6 @@ namespace CSVWorld virtual void useHint (const std::string& hint); - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void setStatusBar (bool show); public slots: @@ -83,6 +86,8 @@ namespace CSVWorld private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void updateStatusBar(); void switchToRow (int row); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba8c4ae563..832e074c45 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -558,23 +558,6 @@ void CSVWorld::Table::executeExtendedRevert() void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { - if (name=="records/type-format" || name=="records/status-format") - { - int columns = mModel->columnCount(); - - for (int i=0; i - (*delegate).updateUserSetting (name, list); - { - emit dataChanged (mModel->index (0, i), - mModel->index (mModel->rowCount()-1, i)); - } - } - return; - } - QString base ("table-input/double"); if (name.startsWith (base)) { @@ -633,7 +616,18 @@ void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) mUnselectAfterJump = false; } } + else if (*setting=="Records/type-format" || *setting=="Records/status-format") + { + int columns = mModel->columnCount(); + for (int i=0; i (*delegate).settingChanged (setting); + emit dataChanged (mModel->index (0, i), + mModel->index (mModel->rowCount()-1, i)); + } + } } void CSVWorld::Table::tableSizeUpdate() diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b87d6b4f48..b0431f71a0 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -166,7 +166,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO const QModelIndex& index) const { CSMWorld::ColumnBase::Display display = getDisplayTypeFromIndex(index); - + // This createEditor() method is called implicitly from tables. // For boolean values in tables use the default editor (combobox). // Checkboxes is looking ugly in the table view. @@ -239,7 +239,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO edit->setUndoRedoEnabled (false); return edit; } - + case CSMWorld::ColumnBase::Display_Boolean: return new QCheckBox(parent); @@ -260,7 +260,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO widget->setMaxLength (32); return widget; } - + default: return QStyledItemDelegate::createEditor (parent, option, index); @@ -329,3 +329,5 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde } } + +void CSVWorld::CommandDelegate::settingChanged (const CSMPrefs::Setting *setting) {} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index d695be0d7e..766d729588 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -18,6 +18,11 @@ namespace CSMWorld class CommandDispatcher; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWorld { ///< \brief Getting the data out of an editor widget @@ -138,10 +143,9 @@ namespace CSVWorld virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const; - public slots: - - virtual void updateUserSetting - (const QString &name, const QStringList &list) {} + /// \attention This is not a slot. For ordering reasons this function needs to be + /// called manually from the parent object's settingChanged function. + virtual void settingChanged (const CSMPrefs::Setting *setting); }; } From cddea4a99cd4af28800e017d0c4b5c789806fb56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 Dec 2015 13:54:53 -0800 Subject: [PATCH 1702/1812] Start underwater sound after updating sounds In between the startUpdate/finishUpdate calls, changes are deferred so that they can happen all at once. This includes starting sounds, so when the underwater sound is started it will be immediately checked to see if it's playing. Since it's not yet playing, it'll be seen as stopped and get cleaned up before ever playing. --- apps/openmw/mwsound/soundmanagerimp.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d1a90759b1..522efe3a78 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -844,13 +844,6 @@ namespace MWSound env ); - if(mListenerUnderwater) - { - // Play underwater sound (after updating listener) - if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); - } - // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -979,6 +972,13 @@ namespace MWSound ++trkiter; } } + + if(mListenerUnderwater) + { + // Play underwater sound (after updating sounds) + if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + } mOutput->finishUpdate(); } From ecbd68a19bbf65ef4f2c527298e041dfde63ae73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 10:40:00 +0100 Subject: [PATCH 1703/1812] third batch of changing over user settings usage to the new system --- apps/opencs/view/doc/subview.cpp | 5 +- apps/opencs/view/doc/subview.hpp | 2 - apps/opencs/view/doc/view.cpp | 97 ++++++++++------------ apps/opencs/view/doc/view.hpp | 9 +- apps/opencs/view/doc/viewmanager.cpp | 14 +--- apps/opencs/view/render/editmode.cpp | 5 -- apps/opencs/view/render/editmode.hpp | 3 - apps/opencs/view/render/instancemode.cpp | 21 +---- apps/opencs/view/render/instancemode.hpp | 6 -- apps/opencs/view/tools/searchsubview.cpp | 12 +-- apps/opencs/view/world/dialoguesubview.cpp | 30 +++---- apps/opencs/view/world/dialoguesubview.hpp | 9 +- apps/opencs/view/world/table.cpp | 84 +++++++++---------- apps/opencs/view/world/table.hpp | 2 - apps/opencs/view/world/tablesubview.cpp | 6 -- apps/opencs/view/world/tablesubview.hpp | 3 - 16 files changed, 121 insertions(+), 187 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index e0c2fbc46a..67a8f8c705 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -16,7 +16,7 @@ bool CSVDoc::SubView::event (QEvent *event) emit closeRequest(); return true; } - + return QDockWidget::event (event); } @@ -38,9 +38,6 @@ void CSVDoc::SubView::setStatusBar (bool show) {} void CSVDoc::SubView::useHint (const std::string& hint) {} -void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) -{} - void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 189bb40ebe..1c5f8a7866 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -52,8 +52,6 @@ namespace CSVDoc virtual std::string getTitle() const; - virtual void updateUserSetting (const QString& name, const QStringList& value); - private: void closeEvent (QCloseEvent *event); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 776839d19e..3491c9de2b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -15,7 +15,6 @@ #include #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" #include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" @@ -443,6 +442,9 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); } CSVDoc::View::~View() @@ -626,6 +628,45 @@ void CSVDoc::View::moveScrollBarToEnd(int min, int max) } } +void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) +{ + if (*setting=="Windows/hide-subview") + updateSubViewIndicies (0); + else if (*setting=="Windows/mainwindow-scrollbar") + { + if (setting->toString()!="Grow Only") + { + if (mScroll) + { + if (setting->toString()=="Scrollbar Only") + { + mScrollbarOnly = true; + mSubViewWindow.setMinimumWidth(0); + } + else if (mScrollbarOnly) + { + mScrollbarOnly = false; + updateScrollbar(); + } + } + else + { + mScroll = new QScrollArea(this); + mScroll->setWidgetResizable(true); + mScroll->setWidget(&mSubViewWindow); + setCentralWidget(mScroll); + } + } + else if (mScroll) + { + mScroll->takeWidget(); + setCentralWidget (&mSubViewWindow); + mScroll->deleteLater(); + mScroll = 0; + } + } +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); @@ -849,60 +890,6 @@ void CSVDoc::View::resizeViewHeight (int height) resize (geometry().width(), height); } -void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) -{ - - if (name=="window/hide-subview") - updateSubViewIndicies (0); - - foreach (SubView *subView, mSubViews) - { - subView->updateUserSetting (name, list); - } - - if (name=="window/mainwindow-scrollbar") - { - if(list.at(0) != "Grow Only") - { - if (mScroll) - { - if (list.at(0).isEmpty() || list.at(0) == "Scrollbar Only") - { - mScrollbarOnly = true; - mSubViewWindow.setMinimumWidth(0); - } - else - { - if(!mScrollbarOnly) - return; - - mScrollbarOnly = false; - updateScrollbar(); - } - } - else - { - mScroll = new QScrollArea(this); - mScroll->setWidgetResizable(true); - mScroll->setWidget(&mSubViewWindow); - setCentralWidget(mScroll); - } - } - else - { - if (mScroll) - { - mScroll->takeWidget(); - setCentralWidget (&mSubViewWindow); - mScroll->deleteLater(); - mScroll = 0; - } - else - return; - } - } -} - void CSVDoc::View::toggleShowStatusBar (bool show) { foreach (QObject *view, mSubViewWindow.children()) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 2dd7174407..90eeeb4074 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -22,6 +22,11 @@ namespace CSMWorld class UniversalId; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSVDoc { class ViewManager; @@ -137,8 +142,6 @@ namespace CSVDoc void abortOperation (int type); - void updateUserSetting (const QString &, const QStringList &); - void updateTitle(); // called when subviews are added or removed @@ -146,6 +149,8 @@ namespace CSVDoc private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void newView(); void save(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 116febae44..024636f34b 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -14,6 +14,8 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../../model/prefs/state.hpp" + #include "../world/util.hpp" #include "../world/enumdelegate.hpp" #include "../world/vartypedelegate.hpp" @@ -22,8 +24,6 @@ #include "../world/idcompletiondelegate.hpp" #include "../world/colordelegate.hpp" -#include "../../model/settings/usersettings.hpp" - #include "view.hpp" void CSVDoc::ViewManager::updateIndices() @@ -165,10 +165,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) mViews.push_back (view); - std::string showStatusBar = - CSMSettings::UserSettings::instance().settingValue("window/show-statusbar").toStdString(); - - view->toggleStatusBar (showStatusBar == "true"); + view->toggleStatusBar (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); view->show(); connect (view, SIGNAL (newGameRequest ()), this, SIGNAL (newGameRequest())); @@ -177,11 +174,6 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *))); - connect (&CSMSettings::UserSettings::instance(), - SIGNAL (userSettingUpdated(const QString &, const QStringList &)), - view, - SLOT (updateUserSetting (const QString &, const QStringList &))); - updateIndices(); return view; diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 4c6f2bd438..a77ef21a5d 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -24,11 +24,6 @@ void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) mWorldspaceWidget->clearSelection (~mMask); } -void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value) -{ - -} - void CSVRender::EditMode::setEditLock (bool locked) { diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index c17616b569..9a8ac9a3a3 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -30,9 +30,6 @@ namespace CSVRender virtual void activate (CSVWidget::SceneToolbar *toolbar); - /// Default-implementation: Do nothing. - virtual void updateUserSetting (const QString& name, const QStringList& value); - /// Default-implementation: Ignored. virtual void setEditLock (bool locked); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 8f0526443a..a4d147bb4d 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,7 +1,7 @@ #include "instancemode.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "elements.hpp" #include "object.hpp" @@ -9,33 +9,20 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", - parent), mContextSelect (false) + parent) { } -void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) -{ - EditMode::activate (toolbar); - - mContextSelect = CSMSettings::UserSettings::instance().setting ("scene-input/context-select")=="true"; -} - -void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="scene-input/context-select") - mContextSelect = value.at (0)=="true"; -} - void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { - if (mContextSelect) + if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) primarySelectPressed (tag); } void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr tag) { - if (mContextSelect) + if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) secondarySelectPressed (tag); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 50bd8243d3..66451bd996 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -9,16 +9,10 @@ namespace CSVRender { Q_OBJECT - bool mContextSelect; - public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); - virtual void activate (CSVWidget::SceneToolbar *toolbar); - - virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index c2cdd10a8e..493defa5ad 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -6,7 +6,7 @@ #include "../../model/tools/search.hpp" #include "../../model/tools/reportmodel.hpp" #include "../../model/world/idtablebase.hpp" -#include "../../model/settings/usersettings.hpp" +#include "../../model/prefs/state.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -23,8 +23,7 @@ void CSVTools::SearchSubView::replace (bool selection) const CSMTools::ReportModel& model = dynamic_cast (*mTable->model()); - bool autoDelete = CSMSettings::UserSettings::instance().setting ( - "search/auto-delete", QString ("true"))=="true"; + bool autoDelete = CSMPrefs::get()["Search & Replace"]["auto-delete"].isTrue(); CSMTools::Search search (mSearch); CSMWorld::IdTableBase *currentTable = 0; @@ -109,13 +108,10 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - int paddingBefore = userSettings.setting ("search/char-before", QString ("5")).toInt(); - int paddingAfter = userSettings.setting ("search/char-after", QString ("5")).toInt(); + CSMPrefs::Category& settings = CSMPrefs::get()["Search & Replace"]; mSearch = search; - mSearch.setPadding (paddingBefore, paddingAfter); + mSearch.setPadding (settings["char-before"].toInt(), settings["char-after"].toInt()); mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e0c167b0e3..25bd8e8ee4 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -31,7 +31,8 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" -#include "../../model/settings/usersettings.hpp" + +#include "../../model/prefs/state.hpp" #include "../widget/coloreditor.hpp" #include "../widget/droplineedit.hpp" @@ -883,12 +884,12 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (requestFocus (const std::string&))); - // button bar - if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true") - addButtonBar(); - // layout getMainLayout().addWidget (mBottom); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Dialogues"].update(); } void CSVWorld::DialogueSubView::setEditLock (bool locked) @@ -899,24 +900,19 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mButtons->setEditLock (locked); } -void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) +void CSVWorld::DialogueSubView::settingChanged (const CSMPrefs::Setting *setting) { - SimpleDialogueSubView::updateUserSetting (name, value); - - if (name=="dialogues/toolbar") + if (*setting=="ID Dialogues/toolbar") { - if (value.at(0)==QString ("true")) + if (setting->isTrue()) { addButtonBar(); } - else + else if (mButtons) { - if (mButtons) - { - getMainLayout().removeWidget (mButtons); - delete mButtons; - mButtons = 0; - } + getMainLayout().removeWidget (mButtons); + delete mButtons; + mButtons = 0; } } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2ae0f97203..bd7116ba2e 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -27,6 +27,11 @@ namespace CSMWorld class NestedTableProxyModel; } +namespace CSMPrefs +{ + class Setting; +} + namespace CSMDoc { class Document; @@ -271,10 +276,10 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateUserSetting (const QString& name, const QStringList& value); - private slots: + void settingChanged (const CSMPrefs::Setting *setting); + void showPreview(); void viewRecord(); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 832e074c45..95dfa10340 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -23,6 +23,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/commanddispatcher.hpp" + #include "../../model/prefs/state.hpp" #include "recordstatusdelegate.hpp" @@ -232,10 +233,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : DragRecordTable(document), mCreateAction (0), mCloneAction(0),mRecordStatusDisplay (0) { - connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), - this, SLOT (settingChanged (const CSMPrefs::Setting *))); - CSMPrefs::get()["ID Tables"].update(); - mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || @@ -361,6 +358,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_EditRecord)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_View)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier | Qt::ControlModifier, Action_EditRecordAndClose)); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); + CSMPrefs::get()["ID Tables"].update(); } void CSVWorld::Table::setEditLock (bool locked) @@ -556,46 +557,6 @@ void CSVWorld::Table::executeExtendedRevert() } } -void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) -{ - QString base ("table-input/double"); - if (name.startsWith (base)) - { - QString modifierString = name.mid (base.size()); - Qt::KeyboardModifiers modifiers = 0; - - if (modifierString=="-s") - modifiers = Qt::ShiftModifier; - else if (modifierString=="-c") - modifiers = Qt::ControlModifier; - else if (modifierString=="-sc") - modifiers = Qt::ShiftModifier | Qt::ControlModifier; - - DoubleClickAction action = Action_None; - - QString value = list.at (0); - - if (value=="Edit in Place") - action = Action_InPlaceEdit; - else if (value=="Edit Record") - action = Action_EditRecord; - else if (value=="View") - action = Action_View; - else if (value=="Revert") - action = Action_Revert; - else if (value=="Delete") - action = Action_Delete; - else if (value=="Edit Record and Close") - action = Action_EditRecordAndClose; - else if (value=="View and Close") - action = Action_ViewAndClose; - - mDoubleClickActions[modifiers] = action; - - return; - } -} - void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) { if (*setting=="ID Tables/jump-to-added") @@ -628,6 +589,41 @@ void CSVWorld::Table::settingChanged (const CSMPrefs::Setting *setting) mModel->index (mModel->rowCount()-1, i)); } } + else if (setting->getParent()->getKey()=="ID Tables" && + setting->getKey().substr (0, 6)=="double") + { + std::string modifierString = setting->getKey().substr (6); + + Qt::KeyboardModifiers modifiers = 0; + + if (modifierString=="-s") + modifiers = Qt::ShiftModifier; + else if (modifierString=="-c") + modifiers = Qt::ControlModifier; + else if (modifierString=="-sc") + modifiers = Qt::ShiftModifier | Qt::ControlModifier; + + DoubleClickAction action = Action_None; + + std::string value = setting->toString(); + + if (value=="Edit in Place") + action = Action_InPlaceEdit; + else if (value=="Edit Record") + action = Action_EditRecord; + else if (value=="View") + action = Action_View; + else if (value=="Revert") + action = Action_Revert; + else if (value=="Delete") + action = Action_Delete; + else if (value=="Edit Record and Close") + action = Action_EditRecordAndClose; + else if (value=="View and Close") + action = Action_ViewAndClose; + + mDoubleClickActions[modifiers] = action; + } } void CSVWorld::Table::tableSizeUpdate() diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 53401a1927..53249f66fe 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -155,8 +155,6 @@ namespace CSVWorld void recordFilterChanged (boost::shared_ptr filter); - void updateUserSetting (const QString &name, const QStringList &list); - void rowAdded(const std::string &id); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 81b2699934..1b25e1c086 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -98,12 +98,6 @@ void CSVWorld::TableSubView::editRequest (const CSMWorld::UniversalId& id, const focusId (id, hint); } -void CSVWorld::TableSubView::updateUserSetting - (const QString &name, const QStringList &list) -{ - mTable->updateUserSetting(name, list); -} - void CSVWorld::TableSubView::setStatusBar (bool show) { mBottom->setStatusBar (show); diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 9d86c32e40..7d143d927c 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -43,9 +43,6 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateUserSetting - (const QString& name, const QStringList &list); - virtual void setStatusBar (bool show); virtual void useHint (const std::string& hint); From 591564566c91162a8225f360c9b52bf03840acc7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:19:48 +0100 Subject: [PATCH 1704/1812] made user settings access thread-safe --- apps/opencs/model/prefs/boolsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/boolsetting.hpp | 2 +- apps/opencs/model/prefs/coloursetting.cpp | 13 ++++++++----- apps/opencs/model/prefs/coloursetting.hpp | 3 ++- apps/opencs/model/prefs/doublesetting.cpp | 12 +++++++++--- apps/opencs/model/prefs/doublesetting.hpp | 3 ++- apps/opencs/model/prefs/enumsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/enumsetting.hpp | 3 ++- apps/opencs/model/prefs/intsetting.cpp | 11 ++++++++--- apps/opencs/model/prefs/intsetting.hpp | 2 +- apps/opencs/model/prefs/setting.cpp | 16 ++++++++++++++-- apps/opencs/model/prefs/setting.hpp | 6 +++++- apps/opencs/model/prefs/state.cpp | 17 +++++++++++------ apps/opencs/model/prefs/state.hpp | 6 ++++++ 14 files changed, 85 insertions(+), 31 deletions(-) diff --git a/apps/opencs/model/prefs/boolsetting.cpp b/apps/opencs/model/prefs/boolsetting.cpp index 459993325a..6c0babaf7d 100644 --- a/apps/opencs/model/prefs/boolsetting.cpp +++ b/apps/opencs/model/prefs/boolsetting.cpp @@ -2,6 +2,7 @@ #include "boolsetting.hpp" #include +#include #include @@ -9,8 +10,8 @@ #include "state.hpp" CSMPrefs::BoolSetting::BoolSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, bool default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, bool default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip (const std::string& tooltip) @@ -37,6 +38,10 @@ std::pair CSMPrefs::BoolSetting::makeWidgets (QWidget *par void CSMPrefs::BoolSetting::valueChanged (int value) { - getValues().setBool (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setBool (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/boolsetting.hpp b/apps/opencs/model/prefs/boolsetting.hpp index dfc28c5aeb..f8a321859f 100644 --- a/apps/opencs/model/prefs/boolsetting.hpp +++ b/apps/opencs/model/prefs/boolsetting.hpp @@ -15,7 +15,7 @@ namespace CSMPrefs public: BoolSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, bool default_); + QMutex *mutex, const std::string& key, const std::string& label, bool default_); BoolSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/coloursetting.cpp b/apps/opencs/model/prefs/coloursetting.cpp index a564852921..d51bfad567 100644 --- a/apps/opencs/model/prefs/coloursetting.cpp +++ b/apps/opencs/model/prefs/coloursetting.cpp @@ -1,9 +1,8 @@ #include "coloursetting.hpp" -#include - #include +#include #include @@ -13,8 +12,8 @@ #include "state.hpp" CSMPrefs::ColourSetting::ColourSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, QColor default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, QColor default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip (const std::string& tooltip) @@ -44,6 +43,10 @@ std::pair CSMPrefs::ColourSetting::makeWidgets (QWidget *p void CSMPrefs::ColourSetting::valueChanged() { CSVWidget::ColorEditor& widget = dynamic_cast (*sender()); - getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + { + QMutexLocker lock (getMutex()); + getValues().setString (getKey(), getParent()->getKey(), widget.color().name().toUtf8().data()); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/coloursetting.hpp b/apps/opencs/model/prefs/coloursetting.hpp index fed2adc0a8..be58426f2a 100644 --- a/apps/opencs/model/prefs/coloursetting.hpp +++ b/apps/opencs/model/prefs/coloursetting.hpp @@ -17,7 +17,8 @@ namespace CSMPrefs public: ColourSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, QColor default_); + QMutex *mutex, const std::string& key, const std::string& label, + QColor default_); ColourSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/doublesetting.cpp b/apps/opencs/model/prefs/doublesetting.cpp index 2eabc78bf5..7c247777d2 100644 --- a/apps/opencs/model/prefs/doublesetting.cpp +++ b/apps/opencs/model/prefs/doublesetting.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -12,8 +13,9 @@ #include "state.hpp" CSMPrefs::DoubleSetting::DoubleSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, double default_) -: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + QMutex *mutex, const std::string& key, const std::string& label, double default_) +: Setting (parent, values, mutex, key, label), + mMin (0), mMax (std::numeric_limits::max()), mDefault (default_) {} @@ -64,6 +66,10 @@ std::pair CSMPrefs::DoubleSetting::makeWidgets (QWidget *p void CSMPrefs::DoubleSetting::valueChanged (double value) { - getValues().setFloat (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setFloat (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/doublesetting.hpp b/apps/opencs/model/prefs/doublesetting.hpp index d0735d30ad..3868f014e2 100644 --- a/apps/opencs/model/prefs/doublesetting.hpp +++ b/apps/opencs/model/prefs/doublesetting.hpp @@ -17,7 +17,8 @@ namespace CSMPrefs public: DoubleSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, double default_); + QMutex *mutex, const std::string& key, const std::string& label, + double default_); // defaults to [0, std::numeric_limits::max()] DoubleSetting& setRange (double min, double max); diff --git a/apps/opencs/model/prefs/enumsetting.cpp b/apps/opencs/model/prefs/enumsetting.cpp index ea7d0703ea..e69f717ead 100644 --- a/apps/opencs/model/prefs/enumsetting.cpp +++ b/apps/opencs/model/prefs/enumsetting.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -39,8 +40,8 @@ CSMPrefs::EnumValues& CSMPrefs::EnumValues::add (const std::string& value, const CSMPrefs::EnumSetting::EnumSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, const EnumValue& default_) -: Setting (parent, values, key, label), mDefault (default_) + QMutex *mutex, const std::string& key, const std::string& label, const EnumValue& default_) +: Setting (parent, values, mutex, key, label), mDefault (default_) {} CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip (const std::string& tooltip) @@ -102,6 +103,10 @@ std::pair CSMPrefs::EnumSetting::makeWidgets (QWidget *par void CSMPrefs::EnumSetting::valueChanged (int value) { - getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + { + QMutexLocker lock (getMutex()); + getValues().setString (getKey(), getParent()->getKey(), mValues.mValues.at (value).mValue); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/enumsetting.hpp b/apps/opencs/model/prefs/enumsetting.hpp index e2102d20eb..728de3acd2 100644 --- a/apps/opencs/model/prefs/enumsetting.hpp +++ b/apps/opencs/model/prefs/enumsetting.hpp @@ -39,7 +39,8 @@ namespace CSMPrefs public: EnumSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, const EnumValue& default_); + QMutex *mutex, const std::string& key, const std::string& label, + const EnumValue& default_); EnumSetting& setTooltip (const std::string& tooltip); diff --git a/apps/opencs/model/prefs/intsetting.cpp b/apps/opencs/model/prefs/intsetting.cpp index 83fb495c57..269a63af43 100644 --- a/apps/opencs/model/prefs/intsetting.cpp +++ b/apps/opencs/model/prefs/intsetting.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -12,8 +13,8 @@ #include "state.hpp" CSMPrefs::IntSetting::IntSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, int default_) -: Setting (parent, values, key, label), mMin (0), mMax (std::numeric_limits::max()), + QMutex *mutex, const std::string& key, const std::string& label, int default_) +: Setting (parent, values, mutex, key, label), mMin (0), mMax (std::numeric_limits::max()), mDefault (default_) {} @@ -64,6 +65,10 @@ std::pair CSMPrefs::IntSetting::makeWidgets (QWidget *pare void CSMPrefs::IntSetting::valueChanged (int value) { - getValues().setInt (getKey(), getParent()->getKey(), value); + { + QMutexLocker lock (getMutex()); + getValues().setInt (getKey(), getParent()->getKey(), value); + } + getParent()->getState()->update (*this); } diff --git a/apps/opencs/model/prefs/intsetting.hpp b/apps/opencs/model/prefs/intsetting.hpp index 05acb9fbc0..0ee6cf9e34 100644 --- a/apps/opencs/model/prefs/intsetting.hpp +++ b/apps/opencs/model/prefs/intsetting.hpp @@ -17,7 +17,7 @@ namespace CSMPrefs public: IntSetting (Category *parent, Settings::Manager *values, - const std::string& key, const std::string& label, int default_); + QMutex *mutex, const std::string& key, const std::string& label, int default_); // defaults to [0, std::numeric_limits::max()] IntSetting& setRange (int min, int max); diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 39d997988e..89924ae29d 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -2,6 +2,7 @@ #include "setting.hpp" #include +#include #include "category.hpp" #include "state.hpp" @@ -11,9 +12,15 @@ Settings::Manager& CSMPrefs::Setting::getValues() return *mValues; } -CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, +QMutex *CSMPrefs::Setting::getMutex() +{ + return mMutex; +} + +CSMPrefs::Setting::Setting (Category *parent, Settings::Manager *values, QMutex *mutex, const std::string& key, const std::string& label) -: QObject (parent->getState()), mParent (parent), mValues (values), mKey (key), mLabel (label) +: QObject (parent->getState()), mParent (parent), mValues (values), mMutex (mutex), mKey (key), + mLabel (label) {} CSMPrefs::Setting:: ~Setting() {} @@ -40,26 +47,31 @@ const std::string& CSMPrefs::Setting::getLabel() const int CSMPrefs::Setting::toInt() const { + QMutexLocker lock (mMutex); return mValues->getInt (mKey, mParent->getKey()); } double CSMPrefs::Setting::toDouble() const { + QMutexLocker lock (mMutex); return mValues->getFloat (mKey, mParent->getKey()); } std::string CSMPrefs::Setting::toString() const { + QMutexLocker lock (mMutex); return mValues->getString (mKey, mParent->getKey()); } bool CSMPrefs::Setting::isTrue() const { + QMutexLocker lock (mMutex); return mValues->getBool (mKey, mParent->getKey()); } QColor CSMPrefs::Setting::toColor() const { + QMutexLocker lock (mMutex); return QColor (QString::fromUtf8 (toString().c_str())); } diff --git a/apps/opencs/model/prefs/setting.hpp b/apps/opencs/model/prefs/setting.hpp index 65354469d3..00bcc638bb 100644 --- a/apps/opencs/model/prefs/setting.hpp +++ b/apps/opencs/model/prefs/setting.hpp @@ -8,6 +8,7 @@ class QWidget; class QColor; +class QMutex; namespace Settings { @@ -24,6 +25,7 @@ namespace CSMPrefs Category *mParent; Settings::Manager *mValues; + QMutex *mMutex; std::string mKey; std::string mLabel; @@ -31,9 +33,11 @@ namespace CSMPrefs Settings::Manager& getValues(); + QMutex *getMutex(); + public: - Setting (Category *parent, Settings::Manager *values, const std::string& key, const std::string& label); + Setting (Category *parent, Settings::Manager *values, QMutex *mutex, const std::string& key, const std::string& label); virtual ~Setting(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index ab9fd0a28c..64ce512bf2 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -220,7 +220,8 @@ CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key, default_ = mSettings.getInt (key, mCurrentCategory->second.getKey()); CSMPrefs::IntSetting *setting = - new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -240,7 +241,8 @@ CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key, default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey()); CSMPrefs::DoubleSetting *setting = - new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label, default_); mCurrentCategory->second.addSetting (setting); @@ -258,7 +260,8 @@ CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key, default_ = mSettings.getBool (key, mCurrentCategory->second.getKey()); CSMPrefs::BoolSetting *setting = - new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -276,7 +279,8 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key, default_.mValue = mSettings.getString (key, mCurrentCategory->second.getKey()); CSMPrefs::EnumSetting *setting = - new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -294,7 +298,8 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, default_.setNamedColor (QString::fromUtf8 (mSettings.getString (key, mCurrentCategory->second.getKey()).c_str())); CSMPrefs::ColourSetting *setting = - new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, key, label, default_); + new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label, + default_); mCurrentCategory->second.addSetting (setting); @@ -307,7 +312,7 @@ void CSMPrefs::State::declareSeparator() throw std::logic_error ("no category for setting"); CSMPrefs::Setting *setting = - new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, "", ""); + new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", ""); mCurrentCategory->second.addSetting (setting); } diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 7807dac257..bcd76c6712 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -5,6 +5,7 @@ #include #include +#include #ifndef Q_MOC_RUN #include @@ -25,6 +26,10 @@ namespace CSMPrefs class BoolSetting; class ColourSetting; + /// \brief User settings state + /// + /// \note Access to the user settings is thread-safe once all declarations and loading has + /// been completed. class State : public QObject { Q_OBJECT @@ -43,6 +48,7 @@ namespace CSMPrefs Settings::Manager mSettings; Collection mCategories; Iterator mCurrentCategory; + QMutex mMutex; // not implemented State (const State&); From 44925e9fc8c4858ee3a0f3bbe9597ee033fcaca9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:26:08 +0100 Subject: [PATCH 1705/1812] fixed records settings (Text Only wasn't updating) --- apps/opencs/model/prefs/state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 64ce512bf2..738a509677 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -74,7 +74,7 @@ void CSMPrefs::State::declare() declareCategory ("Records"); EnumValue iconAndText ("Icon and Text"); EnumValues recordValues; - recordValues.add (iconAndText).add ("Icon Only").add ("Text only"); + recordValues.add (iconAndText).add ("Icon Only").add ("Text Only"); declareEnum ("status-format", "Modification status display format", iconAndText). addValues (recordValues); declareEnum ("type-format", "ID type display format", iconAndText). From 67cf260144845858a5c56cbc066edab9238ad17d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:44:04 +0100 Subject: [PATCH 1706/1812] final batch of changing over user settings usage to the new system --- apps/opencs/model/doc/operation.cpp | 23 ++----------------- apps/opencs/model/doc/operation.hpp | 8 ------- apps/opencs/model/doc/operationholder.cpp | 5 ---- apps/opencs/model/doc/stage.cpp | 2 -- apps/opencs/model/doc/stage.hpp | 4 ---- apps/opencs/model/tools/scriptcheck.cpp | 28 +++++++++++------------ apps/opencs/model/tools/scriptcheck.hpp | 4 +--- apps/opencs/model/tools/tools.cpp | 5 ---- apps/opencs/view/doc/view.hpp | 2 -- 9 files changed, 16 insertions(+), 65 deletions(-) diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index cb9b7ec295..2fd54bd3e4 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -23,9 +23,6 @@ void CSMDoc::Operation::prepareStages() { iter->second = iter->first->setup(); mTotalSteps += iter->second; - - for (std::map::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2) - iter->first->updateUserSetting (iter2->first, iter2->second); } } @@ -47,7 +44,7 @@ CSMDoc::Operation::~Operation() void CSMDoc::Operation::run() { mTimer->stop(); - + if (!mConnected) { connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); @@ -64,14 +61,6 @@ void CSMDoc::Operation::appendStage (Stage *stage) mStages.push_back (std::make_pair (stage, 0)); } -void CSMDoc::Operation::configureSettings (const std::vector& settings) -{ - for (std::vector::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter) - { - mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter))); - } -} - void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity) { mDefaultSeverity = severity; @@ -101,14 +90,6 @@ void CSMDoc::Operation::abort() mCurrentStage = mStages.end(); } -void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value) -{ - std::map::iterator iter = mSettings.find (name); - - if (iter!=mSettings.end()) - iter->second = value; -} - void CSMDoc::Operation::executeStage() { if (!mPrepared) @@ -116,7 +97,7 @@ void CSMDoc::Operation::executeStage() prepareStages(); mPrepared = true; } - + Messages messages (mDefaultSeverity); while (mCurrentStage!=mStages.end()) diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c86a6e235..ff396fa3ce 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -34,7 +34,6 @@ namespace CSMDoc bool mError; bool mConnected; QTimer *mTimer; - std::map mSettings; bool mPrepared; Message::Severity mDefaultSeverity; @@ -53,11 +52,6 @@ namespace CSMDoc /// /// \attention Do no call this function while this Operation is running. - /// Specify settings to be passed on to stages. - /// - /// \attention Do no call this function while this Operation is running. - void configureSettings (const std::vector& settings); - /// \attention Do no call this function while this Operation is running. void setDefaultSeverity (Message::Severity severity); @@ -77,8 +71,6 @@ namespace CSMDoc void run(); - void updateUserSetting (const QString& name, const QStringList& value); - private slots: void executeStage(); diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index db0d1a9a4b..5fcf24fe4f 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,7 +1,5 @@ #include "operationholder.hpp" -#include "../settings/usersettings.hpp" - #include "operation.hpp" CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) @@ -30,9 +28,6 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation) connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); - - connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)), - mOperation, SLOT (updateUserSetting (const QString&, const QStringList&))); } bool CSMDoc::OperationHolder::isRunning() const diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index c8da860693..3c8c107ba0 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,5 +1,3 @@ #include "stage.hpp" CSMDoc::Stage::~Stage() {} - -void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {} diff --git a/apps/opencs/model/doc/stage.hpp b/apps/opencs/model/doc/stage.hpp index e0328a91a1..1eae27a982 100644 --- a/apps/opencs/model/doc/stage.hpp +++ b/apps/opencs/model/doc/stage.hpp @@ -23,11 +23,7 @@ namespace CSMDoc virtual void perform (int stage, Messages& messages) = 0; ///< Messages resulting from this stage will be appended to \a messages. - - /// Default-implementation: ignore - virtual void updateUserSetting (const QString& name, const QStringList& value); }; } #endif - diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d7c41cfcf3..268aea3798 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -10,6 +10,8 @@ #include "../world/data.hpp" +#include "../prefs/state.hpp" + CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type) { switch (type) @@ -46,7 +48,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) std::ostringstream stream; stream << "script " << mFile << ": " << message; - + mMessages->add (id, stream.str(), "", getSeverity (type)); } @@ -62,6 +64,15 @@ CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) int CSMTools::ScriptCheckStage::setup() { + std::string warnings = CSMPrefs::get()["Scripts"]["warnings"].toString(); + + if (warnings=="Ignore") + mWarningMode = Mode_Ignore; + else if (warnings=="Normal") + mWarningMode = Mode_Normal; + else if (warnings=="Strict") + mWarningMode = Mode_Strict; + mContext.clear(); mMessages = 0; mId.clear(); @@ -110,22 +121,9 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) std::ostringstream stream; stream << "script " << mFile << ": " << error.what(); - + messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError); } mMessages = 0; } - -void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) -{ - if (name=="script-editor/warnings" && !value.isEmpty()) - { - if (value.at (0)=="Ignore") - mWarningMode = Mode_Ignore; - else if (value.at (0)=="Normal") - mWarningMode = Mode_Normal; - else if (value.at (0)=="Strict") - mWarningMode = Mode_Strict; - } -} diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 3f02766526..f58215800f 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -34,7 +34,7 @@ namespace CSMTools WarningMode mWarningMode; CSMDoc::Message::Severity getSeverity (Type type); - + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); ///< Report error to the user. @@ -50,8 +50,6 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. - - virtual void updateUserSetting (const QString& name, const QStringList& value); }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index fdbf406f1c..608ed9922f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -53,11 +53,6 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); - std::vector settings; - settings.push_back ("script-editor/warnings"); - - mVerifierOperation->configureSettings (settings); - connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)), diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 90eeeb4074..7d53042693 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -88,8 +88,6 @@ namespace CSVDoc void exitApplication(); - void loadUserSettings(); - /// User preference function void resizeViewWidth (int width); From c646533448aec57a6b6d204b856d6dc80f74b17b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 12:49:55 +0100 Subject: [PATCH 1707/1812] removed old user settings system --- apps/opencs/CMakeLists.txt | 27 - apps/opencs/editor.cpp | 5 +- apps/opencs/editor.hpp | 4 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/settings/connector.cpp | 128 --- apps/opencs/model/settings/connector.hpp | 67 -- apps/opencs/model/settings/setting.cpp | 414 --------- apps/opencs/model/settings/setting.hpp | 159 ---- apps/opencs/model/settings/support.hpp | 149 ---- apps/opencs/model/settings/usersettings.cpp | 824 ------------------ apps/opencs/model/settings/usersettings.hpp | 107 --- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/settings/booleanview.cpp | 120 --- apps/opencs/view/settings/booleanview.hpp | 45 - apps/opencs/view/settings/dialog.cpp | 127 --- apps/opencs/view/settings/dialog.hpp | 50 -- apps/opencs/view/settings/frame.cpp | 108 --- apps/opencs/view/settings/frame.hpp | 60 -- apps/opencs/view/settings/listview.cpp | 106 --- apps/opencs/view/settings/listview.hpp | 63 -- apps/opencs/view/settings/page.cpp | 110 --- apps/opencs/view/settings/page.hpp | 56 -- apps/opencs/view/settings/rangeview.cpp | 208 ----- apps/opencs/view/settings/rangeview.hpp | 55 -- .../view/settings/resizeablestackedwidget.cpp | 39 - .../view/settings/resizeablestackedwidget.hpp | 25 - apps/opencs/view/settings/settingwindow.cpp | 131 --- apps/opencs/view/settings/settingwindow.hpp | 58 -- apps/opencs/view/settings/spinbox.cpp | 50 -- apps/opencs/view/settings/spinbox.hpp | 38 - apps/opencs/view/settings/textview.cpp | 63 -- apps/opencs/view/settings/textview.hpp | 51 -- apps/opencs/view/settings/view.cpp | 222 ----- apps/opencs/view/settings/view.hpp | 160 ---- .../view/world/recordstatusdelegate.cpp | 1 - 35 files changed, 1 insertion(+), 3831 deletions(-) delete mode 100644 apps/opencs/model/settings/connector.cpp delete mode 100644 apps/opencs/model/settings/connector.hpp delete mode 100644 apps/opencs/model/settings/setting.cpp delete mode 100644 apps/opencs/model/settings/setting.hpp delete mode 100644 apps/opencs/model/settings/support.hpp delete mode 100644 apps/opencs/model/settings/usersettings.cpp delete mode 100644 apps/opencs/model/settings/usersettings.hpp delete mode 100644 apps/opencs/view/settings/booleanview.cpp delete mode 100644 apps/opencs/view/settings/booleanview.hpp delete mode 100644 apps/opencs/view/settings/dialog.cpp delete mode 100644 apps/opencs/view/settings/dialog.hpp delete mode 100644 apps/opencs/view/settings/frame.cpp delete mode 100644 apps/opencs/view/settings/frame.hpp delete mode 100644 apps/opencs/view/settings/listview.cpp delete mode 100644 apps/opencs/view/settings/listview.hpp delete mode 100644 apps/opencs/view/settings/page.cpp delete mode 100644 apps/opencs/view/settings/page.hpp delete mode 100644 apps/opencs/view/settings/rangeview.cpp delete mode 100644 apps/opencs/view/settings/rangeview.hpp delete mode 100644 apps/opencs/view/settings/resizeablestackedwidget.cpp delete mode 100644 apps/opencs/view/settings/resizeablestackedwidget.hpp delete mode 100644 apps/opencs/view/settings/settingwindow.cpp delete mode 100644 apps/opencs/view/settings/settingwindow.hpp delete mode 100644 apps/opencs/view/settings/spinbox.cpp delete mode 100644 apps/opencs/view/settings/spinbox.hpp delete mode 100644 apps/opencs/view/settings/textview.cpp delete mode 100644 apps/opencs/view/settings/textview.hpp delete mode 100644 apps/opencs/view/settings/view.cpp delete mode 100644 apps/opencs/view/settings/view.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e76b5ce77b..0e9a49432b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -106,37 +106,10 @@ opencs_units_noqt (view/tools subviews ) -opencs_units (view/settings - settingwindow - dialog - page - view - booleanview - textview - listview - rangeview - resizeablestackedwidget - spinbox - ) - -opencs_units_noqt (view/settings - frame - ) - opencs_units (view/prefs dialogue pagebase page ) -opencs_units (model/settings - usersettings - setting - connector - ) - -opencs_hdrs_noqt (model/settings - support - ) - opencs_units (model/prefs state setting intsetting doublesetting boolsetting enumsetting coloursetting ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 78959fe095..92f1082b75 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -18,7 +18,7 @@ #endif CS::Editor::Editor () -: mSettingsState (mCfgMgr), mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), +: mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), mLock(), mMerge (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) @@ -27,9 +27,6 @@ CS::Editor::Editor () setupDataFiles (config.first); - CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); -// mSettings.setModel (CSMSettings::UserSettings::instance()); - NifOsg::Loader::setShowMarkers(true); mVFS.reset(new VFS::Manager(mFsStrict)); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index d7fc0b7156..b088e9a442 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -17,7 +17,6 @@ #include -#include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" #include "model/prefs/state.hpp" @@ -27,8 +26,6 @@ #include "view/doc/filedialog.hpp" #include "view/doc/newgame.hpp" -#include "view/settings/dialog.hpp" - #include "view/prefs/dialogue.hpp" #include "view/tools/merge.hpp" @@ -54,7 +51,6 @@ namespace CS Files::ConfigurationManager mCfgMgr; CSMPrefs::State mSettingsState; - CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 2fd54bd3e4..a27ee9f514 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -6,7 +6,6 @@ #include #include "../world/universalid.hpp" -#include "../settings/usersettings.hpp" #include "state.hpp" #include "stage.hpp" diff --git a/apps/opencs/model/settings/connector.cpp b/apps/opencs/model/settings/connector.cpp deleted file mode 100644 index 3cf21123c5..0000000000 --- a/apps/opencs/model/settings/connector.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "connector.hpp" -#include "../../view/settings/view.hpp" -#include "../../view/settings/page.hpp" - -CSMSettings::Connector::Connector(CSVSettings::View *master, - QObject *parent) - : QObject(parent), mMasterView (master) -{} - -void CSMSettings::Connector::addSlaveView (CSVSettings::View *view, - QList &masterProxyValues) -{ - mSlaveViews.append (view); - - mProxyListMap[view->viewKey()].append (masterProxyValues); -} - -QList CSMSettings::Connector::getSlaveViewValues() const -{ - QList list; - - foreach (const CSVSettings::View *view, mSlaveViews) - list.append (view->selectedValues()); - - return list; -} - -bool CSMSettings::Connector::proxyListsMatch ( - const QList &list1, - const QList &list2) const -{ - bool success = true; - - for (int i = 0; i < list1.size(); i++) - { - success = stringListsMatch (list1.at(i), list2.at(i)); - - if (!success) - break; - } - return success; -} - -void CSMSettings::Connector::slotUpdateMaster() const -{ - //list of the current values for each slave. - QList slaveValueList = getSlaveViewValues(); - - int masterColumn = -1; - - /* - * A row in the master view is one of the values in the - * master view's data model. This corresponds directly to the number of - * values in a proxy list contained in the ProxyListMap member. - * Thus, we iterate each "column" in the master proxy list - * (one for each vlaue in the master. Each column represents - * one master value's corresponding list of slave values. We examine - * each master value's list, comparing it to the current slave value list, - * stopping when we find a match using proxyListsMatch(). - * - * If no match is found, clear the master view's value - */ - - for (int i = 0; i < mMasterView->rowCount(); i++) - { - QList proxyValueList; - - foreach (const QString &settingKey, mProxyListMap.keys()) - { - // append the proxy value list stored in the i'th column - // for each setting key. A setting key is the id of the setting - // in page.name format. - proxyValueList.append (mProxyListMap.value(settingKey).at(i)); - } - - if (proxyListsMatch (slaveValueList, proxyValueList)) - { - masterColumn = i; - break; - } - } - - QString masterValue = mMasterView->value (masterColumn); - - mMasterView->setSelectedValue (masterValue); -} - -void CSMSettings::Connector::slotUpdateSlaves() const -{ - int row = mMasterView->currentIndex(); - - if (row == -1) - return; - - //iterate the proxy lists for the chosen master index - //and pass the list to each slave for updating - for (int i = 0; i < mSlaveViews.size(); i++) - { - QList proxyList = - mProxyListMap.value(mSlaveViews.at(i)->viewKey()); - - mSlaveViews.at(i)->setSelectedValues (proxyList.at(row)); - } -} - -bool CSMSettings::Connector::stringListsMatch ( - const QStringList &list1, - const QStringList &list2) const -{ - //returns a "sloppy" match, verifying that each list contains all the same - //items, though not necessarily in the same order. - - if (list1.size() != list2.size()) - return false; - - QStringList tempList(list2); - - //iterate each value in the list, removing one occurrence of the value in - //the other list. If no corresponding value is found, test fails - foreach (const QString &value, list1) - { - if (!tempList.contains(value)) - return false; - - tempList.removeOne(value); - } - return true; -} diff --git a/apps/opencs/model/settings/connector.hpp b/apps/opencs/model/settings/connector.hpp deleted file mode 100644 index aaf9936d54..0000000000 --- a/apps/opencs/model/settings/connector.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef CSMSETTINGS_CONNECTOR_HPP -#define CSMSETTINGS_CONNECTOR_HPP - -#include -#include -#include -#include - -#include "support.hpp" - -namespace CSVSettings { - class View; -} - -namespace CSMSettings { - - class Connector : public QObject - { - Q_OBJECT - - CSVSettings::View *mMasterView; - - ///map using the view pointer as a key to it's index value - QList mSlaveViews; - - ///list of proxy values for each master value. - ///value list order is indexed to the master value index. - QMap < QString, QList > mProxyListMap; - - public: - explicit Connector(CSVSettings::View *master, - QObject *parent = 0); - - ///Set the view which acts as a proxy for other setting views - void setMasterView (CSVSettings::View *view); - - ///Add a view to be updated / update to the master - void addSlaveView (CSVSettings::View *view, - QList &masterProxyValues); - - private: - - ///loosely matches lists of proxy values across registered slaves - ///against a proxy value list for a given master value - bool proxyListsMatch (const QList &list1, - const QList &list2) const; - - ///loosely matches two string lists - bool stringListsMatch (const QStringList &list1, - const QStringList &list2) const; - - ///retrieves current values of registered slave views - QList getSlaveViewValues() const; - - public slots: - - ///updates slave views with proxy values associated with current - ///master value - void slotUpdateSlaves() const; - - ///updates master value associated with the currently selected - ///slave values, if applicable. - void slotUpdateMaster() const; - }; -} - -#endif // CSMSETTINGS_CONNECTOR_HPP diff --git a/apps/opencs/model/settings/setting.cpp b/apps/opencs/model/settings/setting.cpp deleted file mode 100644 index 9e33ab9168..0000000000 --- a/apps/opencs/model/settings/setting.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "setting.hpp" -#include "support.hpp" - -CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, - const QString &pageName, const QString& label) -: mIsEditorSetting (true) -{ - buildDefaultSetting(); - - int settingType = static_cast (typ); - - //even-numbered setting types are multi-valued - if ((settingType % 2) == 0) - setProperty (Property_IsMultiValue, QVariant(true).toString()); - - //view type is related to setting type by an order of magnitude - setProperty (Property_SettingType, QVariant (settingType).toString()); - setProperty (Property_Page, pageName); - setProperty (Property_Name, settingName); - setProperty (Property_Label, label.isEmpty() ? settingName : label); -} - -void CSMSettings::Setting::buildDefaultSetting() -{ - int arrLen = sizeof(sPropertyDefaults) / sizeof (*sPropertyDefaults); - - for (int i = 0; i < arrLen; i++) - { - QStringList propertyList; - - if (i list; - - foreach (const QString &val, vals) - list << (QStringList() << val); - - mProxies [setting->page() + '/' + setting->name()] = list; -} - -void CSMSettings::Setting::addProxy (const Setting *setting, - const QList &list) -{ - if (serializable()) - setProperty (Property_Serializable, false); - - mProxies [setting->page() + '/' + setting->name()] = list; -} - -void CSMSettings::Setting::setColumnSpan (int value) -{ - setProperty (Property_ColumnSpan, value); -} - -int CSMSettings::Setting::columnSpan() const -{ - return property (Property_ColumnSpan).at(0).toInt(); -} - -void CSMSettings::Setting::setDeclaredValues (QStringList list) -{ - setProperty (Property_DeclaredValues, list); -} - -QStringList CSMSettings::Setting::declaredValues() const -{ - return property (Property_DeclaredValues); -} - -QStringList CSMSettings::Setting::property (SettingProperty prop) const -{ - if (prop >= mProperties.size()) - return QStringList(); - - return mProperties.at(prop); -} - -void CSMSettings::Setting::setDefaultValue (int value) -{ - setDefaultValues (QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setDefaultValue (double value) -{ - setDefaultValues (QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setDefaultValue (const QString &value) -{ - setDefaultValues (QStringList() << value); -} - -void CSMSettings::Setting::setDefaultValues (const QStringList &values) -{ - setProperty (Property_DefaultValues, values); -} - -QStringList CSMSettings::Setting::defaultValues() const -{ - return property (Property_DefaultValues); -} - -void CSMSettings::Setting::setDelimiter (const QString &value) -{ - setProperty (Property_Delimiter, value); -} - -QString CSMSettings::Setting::delimiter() const -{ - return property (Property_Delimiter).at(0); -} - -void CSMSettings::Setting::setEditorSetting(bool state) -{ - mIsEditorSetting = true; -} - -bool CSMSettings::Setting::isEditorSetting() const -{ - return mIsEditorSetting; -} -void CSMSettings::Setting::setIsMultiLine (bool state) -{ - setProperty (Property_IsMultiLine, state); -} - -bool CSMSettings::Setting::isMultiLine() const -{ - return (property (Property_IsMultiLine).at(0) == "true"); -} - -void CSMSettings::Setting::setIsMultiValue (bool state) -{ - setProperty (Property_IsMultiValue, state); -} - -bool CSMSettings::Setting::isMultiValue() const -{ - return (property (Property_IsMultiValue).at(0) == "true"); -} - -const CSMSettings::ProxyValueMap &CSMSettings::Setting::proxyLists() const -{ - return mProxies; -} - -void CSMSettings::Setting::setSerializable (bool state) -{ - setProperty (Property_Serializable, state); -} - -bool CSMSettings::Setting::serializable() const -{ - return (property (Property_Serializable).at(0) == "true"); -} - -void CSMSettings::Setting::setSpecialValueText(const QString &text) -{ - setProperty (Property_SpecialValueText, text); -} - -QString CSMSettings::Setting::specialValueText() const -{ - return property (Property_SpecialValueText).at(0); -} - -void CSMSettings::Setting::setName (const QString &value) -{ - setProperty (Property_Name, value); -} - -QString CSMSettings::Setting::name() const -{ - return property (Property_Name).at(0); -} - -void CSMSettings::Setting::setPage (const QString &value) -{ - setProperty (Property_Page, value); -} - -QString CSMSettings::Setting::page() const -{ - return property (Property_Page).at(0); -} - -void CSMSettings::Setting::setStyleSheet (const QString &value) -{ - setProperty (Property_StyleSheet, value); -} - -QString CSMSettings::Setting::styleSheet() const -{ - return property (Property_StyleSheet).at(0); -} - -void CSMSettings::Setting::setPrefix (const QString &value) -{ - setProperty (Property_Prefix, value); -} - -QString CSMSettings::Setting::prefix() const -{ - return property (Property_Prefix).at(0); -} - -void CSMSettings::Setting::setRowSpan (const int value) -{ - setProperty (Property_RowSpan, value); -} - -int CSMSettings::Setting::rowSpan () const -{ - return property (Property_RowSpan).at(0).toInt(); -} - -void CSMSettings::Setting::setSingleStep (int value) -{ - setProperty (Property_SingleStep, value); -} - -void CSMSettings::Setting::setSingleStep (double value) -{ - setProperty (Property_SingleStep, value); -} - -QString CSMSettings::Setting::singleStep() const -{ - return property (Property_SingleStep).at(0); -} - -void CSMSettings::Setting::setSuffix (const QString &value) -{ - setProperty (Property_Suffix, value); -} - -QString CSMSettings::Setting::suffix() const -{ - return property (Property_Suffix).at(0); -} - -void CSMSettings::Setting::setTickInterval (int value) -{ - setProperty (Property_TickInterval, value); -} - -int CSMSettings::Setting::tickInterval () const -{ - return property (Property_TickInterval).at(0).toInt(); -} - -void CSMSettings::Setting::setTicksAbove (bool state) -{ - setProperty (Property_TicksAbove, state); -} - -bool CSMSettings::Setting::ticksAbove() const -{ - return (property (Property_TicksAbove).at(0) == "true"); -} - -void CSMSettings::Setting::setTicksBelow (bool state) -{ - setProperty (Property_TicksBelow, state); -} - -bool CSMSettings::Setting::ticksBelow() const -{ - return (property (Property_TicksBelow).at(0) == "true"); -} - -void CSMSettings::Setting::setType (int settingType) -{ - setProperty (Property_SettingType, settingType); -} - -CSMSettings::SettingType CSMSettings::Setting::type() const -{ - return static_cast ( property ( - Property_SettingType).at(0).toInt()); -} - -void CSMSettings::Setting::setRange (int min, int max) -{ - setProperty (Property_Minimum, min); - setProperty (Property_Maximum, max); -} - -void CSMSettings::Setting::setRange (double min, double max) -{ - setProperty (Property_Minimum, min); - setProperty (Property_Maximum, max); -} - -QString CSMSettings::Setting::maximum() const -{ - return property (Property_Maximum).at(0); -} - -QString CSMSettings::Setting::minimum() const -{ - return property (Property_Minimum).at(0); -} - -CSVSettings::ViewType CSMSettings::Setting::viewType() const -{ - return static_cast ( property ( - Property_SettingType).at(0).toInt() / 10); -} - -void CSMSettings::Setting::setViewColumn (int value) -{ - setProperty (Property_ViewColumn, value); -} - -int CSMSettings::Setting::viewColumn() const -{ - return property (Property_ViewColumn).at(0).toInt(); -} - -void CSMSettings::Setting::setViewLocation (int row, int column) -{ - setViewRow (row); - setViewColumn (column); -} - -void CSMSettings::Setting::setViewRow (int value) -{ - setProperty (Property_ViewRow, value); -} - -int CSMSettings::Setting::viewRow() const -{ - return property (Property_ViewRow).at(0).toInt(); -} - -void CSMSettings::Setting::setWidgetWidth (int value) -{ - setProperty (Property_WidgetWidth, value); -} - -int CSMSettings::Setting::widgetWidth() const -{ - return property (Property_WidgetWidth).at(0).toInt(); -} - -void CSMSettings::Setting::setWrapping (bool state) -{ - setProperty (Property_Wrapping, state); -} - -bool CSMSettings::Setting::wrapping() const -{ - return (property (Property_Wrapping).at(0) == "true"); -} - -void CSMSettings::Setting::setLabel (const QString& label) -{ - setProperty (Property_Label, label); -} - -QString CSMSettings::Setting::getLabel() const -{ - return property (Property_Label).at (0); -} - -void CSMSettings::Setting::setToolTip (const QString& toolTip) -{ - setProperty (Property_ToolTip, toolTip); -} - -QString CSMSettings::Setting::getToolTip() const -{ - return property (Property_ToolTip).at (0); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, bool value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, int value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, double value) -{ - setProperty (prop, QStringList() << QVariant (value).toString()); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, - const QString &value) -{ - setProperty (prop, QStringList() << value); -} - -void CSMSettings::Setting::setProperty (SettingProperty prop, - const QStringList &value) -{ - if (prop < mProperties.size()) - mProperties.replace (prop, value); -} diff --git a/apps/opencs/model/settings/setting.hpp b/apps/opencs/model/settings/setting.hpp deleted file mode 100644 index be51a531a9..0000000000 --- a/apps/opencs/model/settings/setting.hpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef CSMSETTINGS_SETTING_HPP -#define CSMSETTINGS_SETTING_HPP - -#include -#include -#include "support.hpp" - -namespace CSMSettings -{ - //QString is the setting id in the form of "page/name" - //QList is a list of stringlists of proxy values. - //Order is important! Proxy stringlists are matched against - //master values by their position in the QList. - typedef QMap > ProxyValueMap; - - ///Setting class is the interface for the User Settings. It contains - ///a great deal of boiler plate to provide the core API functions, as - ///well as the property() functions which use enumeration to be iterable. - ///This makes the Setting class capable of being manipulated by script. - ///See CSMSettings::support.hpp for enumerations / string values. - class Setting - { - QList mProperties; - QStringList mDefaults; - - bool mIsEditorSetting; - - ProxyValueMap mProxies; - - public: - - Setting(SettingType typ, const QString &settingName, - const QString &pageName, const QString& label = ""); - - void addProxy (const Setting *setting, const QStringList &vals); - void addProxy (const Setting *setting, const QList &list); - - const QList &properties() const { return mProperties; } - const ProxyValueMap &proxies() const { return mProxies; } - - void setColumnSpan (int value); - int columnSpan() const; - - void setDeclaredValues (QStringList list); - QStringList declaredValues() const; - - void setDefaultValue (int value); - void setDefaultValue (double value); - void setDefaultValue (const QString &value); - - void setDefaultValues (const QStringList &values); - QStringList defaultValues() const; - - void setDelimiter (const QString &value); - QString delimiter() const; - - void setEditorSetting (bool state); - bool isEditorSetting() const; - - void setIsMultiLine (bool state); - bool isMultiLine() const; - - void setIsMultiValue (bool state); - bool isMultiValue() const; - - void setMask (const QString &value); - QString mask() const; - - void setRange (int min, int max); - void setRange (double min, double max); - - QString maximum() const; - - QString minimum() const; - - void setName (const QString &value); - QString name() const; - - void setPage (const QString &value); - QString page() const; - - void setStyleSheet (const QString &value); - QString styleSheet() const; - - void setPrefix (const QString &value); - QString prefix() const; - - void setRowSpan (const int value); - int rowSpan() const; - - const ProxyValueMap &proxyLists() const; - - void setSerializable (bool state); - bool serializable() const; - - void setSpecialValueText (const QString &text); - QString specialValueText() const; - - void setSingleStep (int value); - void setSingleStep (double value); - QString singleStep() const; - - void setSuffix (const QString &value); - QString suffix() const; - - void setTickInterval (int value); - int tickInterval() const; - - void setTicksAbove (bool state); - bool ticksAbove() const; - - void setTicksBelow (bool state); - bool ticksBelow() const; - - void setViewColumn (int value); - int viewColumn() const; - - void setViewLocation (int row = -1, int column = -1); - - void setViewRow (int value); - int viewRow() const; - - void setType (int settingType); - CSMSettings::SettingType type() const; - - CSVSettings::ViewType viewType() const; - - void setWrapping (bool state); - bool wrapping() const; - - void setWidgetWidth (int value); - int widgetWidth() const; - - /// This is the text the user gets to see. - void setLabel (const QString& label); - QString getLabel() const; - - void setToolTip (const QString& toolTip); - QString getToolTip() const; - - ///returns the specified property value - QStringList property (SettingProperty prop) const; - - ///boilerplate code to convert setting values of common types - void setProperty (SettingProperty prop, bool value); - void setProperty (SettingProperty prop, int value); - void setProperty (SettingProperty prop, double value); - void setProperty (SettingProperty prop, const QString &value); - void setProperty (SettingProperty prop, const QStringList &value); - - void addProxy (Setting* setting, - QMap &proxyMap); - - protected: - void buildDefaultSetting(); - }; -} - -#endif // CSMSETTINGS_SETTING_HPP diff --git a/apps/opencs/model/settings/support.hpp b/apps/opencs/model/settings/support.hpp deleted file mode 100644 index ab0e5088ce..0000000000 --- a/apps/opencs/model/settings/support.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef SETTING_SUPPORT_HPP -#define SETTING_SUPPORT_HPP - -#include -#include -#include -#include -#include - -//Enums -namespace CSMSettings -{ - ///Enumerated properties for scripting - enum SettingProperty - { - Property_Name = 0, - Property_Page = 1, - Property_SettingType = 2, - Property_IsMultiValue = 3, - Property_IsMultiLine = 4, - Property_WidgetWidth = 5, - Property_ViewRow = 6, - Property_ViewColumn = 7, - Property_Delimiter = 8, - Property_Serializable = 9, - Property_ColumnSpan = 10, - Property_RowSpan = 11, - Property_Minimum = 12, - Property_Maximum = 13, - Property_SpecialValueText = 14, - Property_Prefix = 15, - Property_Suffix = 16, - Property_SingleStep = 17, - Property_Wrapping = 18, - Property_TickInterval = 19, - Property_TicksAbove = 20, - Property_TicksBelow = 21, - Property_StyleSheet = 22, - Property_Label = 23, - Property_ToolTip = 24, - - //Stringlists should always be the last items - Property_DefaultValues = 25, - Property_DeclaredValues = 26, - Property_DefinedValues = 27, - Property_Proxies = 28 - }; - - ///Basic setting widget types. - enum SettingType - { - /* - * 0 - 9 - Boolean widgets - * 10-19 - List widgets - * 21-29 - Range widgets - * 31-39 - Text widgets - * - * Each range corresponds to a View_Type enum by a factor of 10. - * - * Even-numbered values are single-value widgets - * Odd-numbered values are multi-valued widgets - */ - - Type_CheckBox = 0, - Type_RadioButton = 1, - Type_ListView = 10, - Type_ComboBox = 11, - Type_SpinBox = 21, - Type_DoubleSpinBox = 23, - Type_Slider = 25, - Type_Dial = 27, - Type_TextArea = 30, - Type_LineEdit = 31, - Type_Undefined = 40 - }; - -} - -namespace CSVSettings -{ - ///Categorical view types which encompass the setting widget types - enum ViewType - { - ViewType_Boolean = 0, - ViewType_List = 1, - ViewType_Range = 2, - ViewType_Text = 3, - ViewType_Undefined = 4 - }; -} - - -namespace CSMSettings -{ - ///used to construct default settings in the Setting class - struct PropertyDefaultValues - { - int id; - QString name; - QVariant value; - }; - - ///strings which correspond to setting values. These strings represent - ///the script language keywords which would be used to declare setting - ///views for 3rd party addons - const QString sPropertyNames[] = - { - "name", "page", "setting_type", "is_multi_value", - "is_multi_line", "widget_width", "view_row", "view_column", "delimiter", - "is_serializable","column_span", "row_span", "minimum", "maximum", - "special_value_text", "prefix", "suffix", "single_step", "wrapping", - "tick_interval", "ticks_above", "ticks_below", "stylesheet", - "defaults", "declarations", "definitions", "proxies" - }; - - ///Default values for a setting. Used in setting creation. - const QString sPropertyDefaults[] = - { - "", //name - "", //page - "40", //setting type - "false", //multivalue - "false", //multiline - "7", //widget width - "-1", //view row - "-1", //view column - ",", //delimiter - "true", //serialized - "1", //column span - "1", //row span - "0", //value range - "0", //value minimum - "0", //value maximum - "", //special text - "", //prefix - "", //suffix - "false", //wrapping - "1", //tick interval - "false", //ticks above - "true", //ticks below - "", //StyleSheet - "", //default values - "", //declared values - "", //defined values - "" //proxy values - }; -} - -#endif // VIEW_SUPPORT_HPP diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp deleted file mode 100644 index 8e5ab3d874..0000000000 --- a/apps/opencs/model/settings/usersettings.cpp +++ /dev/null @@ -1,824 +0,0 @@ -#include "usersettings.hpp" - -#include -#include - -#include -#include -#include - -#include "setting.hpp" -#include "support.hpp" -#include -#include - -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - -CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0; - - CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager) - : mCfgMgr (configurationManager) - , mSettingDefinitions(NULL) -{ - assert(!sUserSettingsInstance); - sUserSettingsInstance = this; - - buildSettingModelDefaults(); -} - -void CSMSettings::UserSettings::buildSettingModelDefaults() -{ - /* - declareSection ("3d-render", "3D Rendering"); - { - Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance"); - farClipDist->setDefaultValue (300000); - farClipDist->setRange (0, 1000000); - farClipDist->setToolTip ("The maximum distance objects are still rendered at."); - - QString defaultValue = "None"; - Setting *antialiasing = createSetting (Type_ComboBox, "antialiasing", "Antialiasing"); - antialiasing->setDeclaredValues (QStringList() - << defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16"); - antialiasing->setDefaultValue (defaultValue); - } - */ - - /* - declareSection ("scene-input", "Scene Input"); - { - Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor", - "Fast movement factor"); - fastFactor->setDefaultValue (4); - fastFactor->setRange (1, 100); - fastFactor->setToolTip ( - "Factor by which movement is speed up while the shift key is held down."); - } - */ - - declareSection ("window", "Window"); - { - Setting *preDefined = createSetting (Type_ComboBox, "pre-defined", - "Default window size"); - preDefined->setEditorSetting (false); - preDefined->setDeclaredValues ( - QStringList() << "640 x 480" << "800 x 600" << "1024 x 768" << "1440 x 900"); - preDefined->setViewLocation (1, 1); - preDefined->setColumnSpan (2); - preDefined->setToolTip ("Newly opened top-level windows will open with this size " - "(picked from a list of pre-defined values)"); - - Setting *width = createSetting (Type_LineEdit, "default-width", - "Default window width"); - width->setDefaultValues (QStringList() << "1024"); - width->setViewLocation (2, 1); - width->setColumnSpan (1); - width->setToolTip ("Newly opened top-level windows will open with this width."); - preDefined->addProxy (width, QStringList() << "640" << "800" << "1024" << "1440"); - - Setting *height = createSetting (Type_LineEdit, "default-height", - "Default window height"); - height->setDefaultValues (QStringList() << "768"); - height->setViewLocation (2, 2); - height->setColumnSpan (1); - height->setToolTip ("Newly opened top-level windows will open with this height."); - preDefined->addProxy (height, QStringList() << "480" << "600" << "768" << "900"); - - Setting *reuse = createSetting (Type_CheckBox, "reuse", "Reuse Subviews"); - reuse->setDefaultValue ("true"); - reuse->setToolTip ("When a new subview is requested and a matching subview already " - " exist, do not open a new subview and use the existing one instead."); - - Setting *statusBar = createSetting (Type_CheckBox, "show-statusbar", "Show Status Bar"); - statusBar->setDefaultValue ("true"); - statusBar->setToolTip ("If a newly open top level window is showing status bars or not. " - " Note that this does not affect existing windows."); - - Setting *maxSubView = createSetting (Type_SpinBox, "max-subviews", - "Maximum number of subviews per top-level window"); - maxSubView->setDefaultValue (256); - maxSubView->setRange (1, 256); - maxSubView->setToolTip ("If the maximum number is reached and a new subview is opened " - "it will be placed into a new top-level window."); - - Setting *hide = createSetting (Type_CheckBox, "hide-subview", "Hide single subview"); - hide->setDefaultValue ("false"); - hide->setToolTip ("When a view contains only a single subview, hide the subview title " - "bar and if this subview is closed also close the view (unless it is the last " - "view for this document)"); - - Setting *minWidth = createSetting (Type_SpinBox, "minimum-width", - "Minimum subview width"); - minWidth->setDefaultValue (325); - minWidth->setRange (50, 10000); - minWidth->setToolTip ("Minimum width of subviews."); - - QString defaultScroll = "Scrollbar Only"; - QStringList scrollValues = QStringList() << defaultScroll << "Grow Only" << "Grow then Scroll"; - - Setting *mainwinScroll = createSetting (Type_RadioButton, "mainwindow-scrollbar", - "Add a horizontal scrollbar to the main view window."); - mainwinScroll->setDefaultValue (defaultScroll); - mainwinScroll->setDeclaredValues (scrollValues); - mainwinScroll->setToolTip ("Scrollbar Only: Simple addition of scrollbars, the view window does not grow" - " automatically.\n" - "Grow Only: Original Editor behaviour. The view window grows as subviews are added. No scrollbars.\n" - "Grow then Scroll: The view window grows. The scrollbar appears once it cannot grow any further."); - - Setting *grow = createSetting (Type_CheckBox, "grow-limit", "Grow Limit Screen"); - grow->setDefaultValue ("false"); - grow->setToolTip ("When \"Grow then Scroll\" option is selected, the window size grows to" - " the width of the virtual desktop. \nIf this option is selected the the window growth" - "is limited to the current screen."); - } - - declareSection ("records", "Records"); - { - QString defaultValue = "Icon and Text"; - QStringList values = QStringList() << defaultValue << "Icon Only" << "Text Only"; - - Setting *rsd = createSetting (Type_RadioButton, "status-format", - "Modification status display format"); - rsd->setDefaultValue (defaultValue); - rsd->setDeclaredValues (values); - - Setting *ritd = createSetting (Type_RadioButton, "type-format", - "ID type display format"); - ritd->setDefaultValue (defaultValue); - ritd->setDeclaredValues (values); - } - - declareSection ("table-input", "ID Tables"); - { - QString inPlaceEdit ("Edit in Place"); - QString editRecord ("Edit Record"); - QString view ("View"); - QString editRecordAndClose ("Edit Record and Close"); - - QStringList values; - values - << "None" << inPlaceEdit << editRecord << view << "Revert" << "Delete" - << editRecordAndClose << "View and Close"; - - QString toolTip = "
      " - "
    • None
    • " - "
    • Edit in Place: Edit the clicked cell
    • " - "
    • Edit Record: Open a dialogue subview for the clicked record
    • " - "
    • View: Open a scene subview for the clicked record (not available everywhere)
    • " - "
    • Revert: Revert record
    • " - "
    • Delete: Delete recordy
    • " - "
    • Edit Record and Close: Open a dialogue subview for the clicked record and close the table subview
    • " - "
    • View And Close: Open a scene subview for the clicked record and close the table subview
    • " - "
    "; - - Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); - doubleClick->setDeclaredValues (values); - doubleClick->setDefaultValue (inPlaceEdit); - doubleClick->setToolTip ("Action on double click in table:

    " + toolTip); - - Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", - "Shift Double Click"); - shiftDoubleClick->setDeclaredValues (values); - shiftDoubleClick->setDefaultValue (editRecord); - shiftDoubleClick->setToolTip ("Action on shift double click in table:

    " + toolTip); - - Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", - "Control Double Click"); - ctrlDoubleClick->setDeclaredValues (values); - ctrlDoubleClick->setDefaultValue (view); - ctrlDoubleClick->setToolTip ("Action on control double click in table:

    " + toolTip); - - Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", - "Shift Control Double Click"); - shiftCtrlDoubleClick->setDeclaredValues (values); - shiftCtrlDoubleClick->setDefaultValue (editRecordAndClose); - shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

    " + toolTip); - - QString defaultValue = "Jump and Select"; - QStringList jumpValues = QStringList() << defaultValue << "Jump Only" << "No Jump"; - - Setting *jumpToAdded = createSetting (Type_RadioButton, "jump-to-added", - "Jump to the added or cloned record."); - jumpToAdded->setDefaultValue (defaultValue); - jumpToAdded->setDeclaredValues (jumpValues); - - Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", - "Manually specify affected record types for an extended delete/revert"); - extendedConfig->setDefaultValue("false"); - extendedConfig->setToolTip("Delete and revert commands have an extended form that also affects " - "associated records.\n\n" - "If this option is enabled, types of affected records are selected " - "manually before a command execution.\nOtherwise, all associated " - "records are deleted/reverted immediately."); - } - - declareSection ("dialogues", "ID Dialogues"); - { - Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); - toolbar->setDefaultValue ("true"); - } - - declareSection ("report-input", "Reports"); - { - QString none ("None"); - QString edit ("Edit"); - QString remove ("Remove"); - QString editAndRemove ("Edit And Remove"); - - QStringList values; - values << none << edit << remove << editAndRemove; - - QString toolTip = "

      " - "
    • None
    • " - "
    • Edit: Open a table or dialogue suitable for addressing the listed report
    • " - "
    • Remove: Remove the report from the report table
    • " - "
    • Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table
    • " - "
    "; - - Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click"); - doubleClick->setDeclaredValues (values); - doubleClick->setDefaultValue (edit); - doubleClick->setToolTip ("Action on double click in report table:

    " + toolTip); - - Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s", - "Shift Double Click"); - shiftDoubleClick->setDeclaredValues (values); - shiftDoubleClick->setDefaultValue (remove); - shiftDoubleClick->setToolTip ("Action on shift double click in report table:

    " + toolTip); - - Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c", - "Control Double Click"); - ctrlDoubleClick->setDeclaredValues (values); - ctrlDoubleClick->setDefaultValue (editAndRemove); - ctrlDoubleClick->setToolTip ("Action on control double click in report table:

    " + toolTip); - - Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc", - "Shift Control Double Click"); - shiftCtrlDoubleClick->setDeclaredValues (values); - shiftCtrlDoubleClick->setDefaultValue (none); - shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

    " + toolTip); - } - - declareSection ("search", "Search & Replace"); - { - Setting *before = createSetting (Type_SpinBox, "char-before", - "Characters before search string"); - before->setDefaultValue (10); - before->setRange (0, 1000); - before->setToolTip ("Maximum number of character to display in search result before the searched text"); - - Setting *after = createSetting (Type_SpinBox, "char-after", - "Characters after search string"); - after->setDefaultValue (10); - after->setRange (0, 1000); - after->setToolTip ("Maximum number of character to display in search result after the searched text"); - - Setting *autoDelete = createSetting (Type_CheckBox, "auto-delete", "Delete row from result table after a successful replace"); - autoDelete->setDefaultValue ("true"); - } - - declareSection ("script-editor", "Scripts"); - { - Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); - lineNum->setDefaultValue ("true"); - lineNum->setToolTip ("Show line numbers to the left of the script editor window." - "The current row and column numbers of the text cursor are shown at the bottom."); - - Setting *monoFont = createSetting (Type_CheckBox, "mono-font", "Use monospace font"); - monoFont->setDefaultValue ("true"); - monoFont->setToolTip ("Whether to use monospaced fonts on script edit subview."); - - QString tooltip = - "\n#RGB (each of R, G, and B is a single hex digit)" - "\n#RRGGBB" - "\n#RRRGGGBBB" - "\n#RRRRGGGGBBBB" - "\nA name from the list of colors defined in the list of SVG color keyword names." - "\nX11 color names may also work."; - - QString modeNormal ("Normal"); - - QStringList modes; - modes << "Ignore" << modeNormal << "Strict"; - - Setting *warnings = createSetting (Type_ComboBox, "warnings", - "Warning Mode"); - warnings->setDeclaredValues (modes); - warnings->setDefaultValue (modeNormal); - warnings->setToolTip ("

      How to handle warning messages during compilation:

      " - "

    • Ignore: Do not report warning
    • " - "
    • Normal: Report warning as a warning
    • " - "
    • Strict: Promote warning to an error
    • " - "
    "); - - Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); - toolbar->setDefaultValue ("true"); - - Setting *delay = createSetting (Type_SpinBox, "compile-delay", - "Delay between updating of source errors"); - delay->setDefaultValue (100); - delay->setRange (0, 10000); - delay->setToolTip ("Delay in milliseconds"); - - Setting *errorHeight = createSetting (Type_SpinBox, "error-height", - "Initial height of the error panel"); - errorHeight->setDefaultValue (100); - errorHeight->setRange (100, 10000); - - Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); - formatInt->setDefaultValues (QStringList() << "Dark magenta"); - formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); - - Setting *formatFloat = createSetting (Type_LineEdit, "colour-float", "Highlight Colour: Float"); - formatFloat->setDefaultValues (QStringList() << "Magenta"); - formatFloat->setToolTip ("(Default: Magenta) Use one of the following formats:" + tooltip); - - Setting *formatName = createSetting (Type_LineEdit, "colour-name", "Highlight Colour: Name"); - formatName->setDefaultValues (QStringList() << "Gray"); - formatName->setToolTip ("(Default: Gray) Use one of the following formats:" + tooltip); - - Setting *formatKeyword = createSetting (Type_LineEdit, "colour-keyword", "Highlight Colour: Keyword"); - formatKeyword->setDefaultValues (QStringList() << "Red"); - formatKeyword->setToolTip ("(Default: Red) Use one of the following formats:" + tooltip); - - Setting *formatSpecial = createSetting (Type_LineEdit, "colour-special", "Highlight Colour: Special"); - formatSpecial->setDefaultValues (QStringList() << "Dark yellow"); - formatSpecial->setToolTip ("(Default: Dark yellow) Use one of the following formats:" + tooltip); - - Setting *formatComment = createSetting (Type_LineEdit, "colour-comment", "Highlight Colour: Comment"); - formatComment->setDefaultValues (QStringList() << "Green"); - formatComment->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); - - Setting *formatId = createSetting (Type_LineEdit, "colour-id", "Highlight Colour: Id"); - formatId->setDefaultValues (QStringList() << "Blue"); - formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); - } - - declareSection ("general-input", "General Input"); - { - Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous"); - cycle->setDefaultValue ("false"); - cycle->setToolTip ("When using next/previous functions at the last/first item of a " - "list go to the first/last item"); - } - - declareSection ("scene-input", "3D Scene Input"); - { - QString left ("Left Mouse-Button"); - QString cLeft ("Ctrl-Left Mouse-Button"); - QString right ("Right Mouse-Button"); - QString cRight ("Ctrl-Right Mouse-Button"); - QString middle ("Middle Mouse-Button"); - QString cMiddle ("Ctrl-Middle Mouse-Button"); - - QStringList values; - values << left << cLeft << right << cRight << middle << cMiddle; - - Setting *primaryNavigation = createSetting (Type_ComboBox, "p-navi", "Primary Camera Navigation Button"); - primaryNavigation->setDeclaredValues (values); - primaryNavigation->setDefaultValue (left); - - Setting *secondaryNavigation = createSetting (Type_ComboBox, "s-navi", "Secondary Camera Navigation Button"); - secondaryNavigation->setDeclaredValues (values); - secondaryNavigation->setDefaultValue (cLeft); - - Setting *primaryEditing = createSetting (Type_ComboBox, "p-edit", "Primary Editing Button"); - primaryEditing->setDeclaredValues (values); - primaryEditing->setDefaultValue (right); - - Setting *secondaryEditing = createSetting (Type_ComboBox, "s-edit", "Secondary Editing Button"); - secondaryEditing->setDeclaredValues (values); - secondaryEditing->setDefaultValue (cRight); - - Setting *primarySelection = createSetting (Type_ComboBox, "p-select", "Selection Button"); - primarySelection->setDeclaredValues (values); - primarySelection->setDefaultValue (middle); - - Setting *secondarySelection = createSetting (Type_ComboBox, "s-select", "Selection Button"); - secondarySelection->setDeclaredValues (values); - secondarySelection->setDefaultValue (cMiddle); - - Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection"); - contextSensitive->setDefaultValue ("false"); - - Setting *dragMouseSensitivity = createSetting (Type_DoubleSpinBox, "drag-factor", - "Mouse sensitivity during drag operations"); - dragMouseSensitivity->setDefaultValue (1.0); - dragMouseSensitivity->setRange (0.001, 100.0); - - Setting *dragWheelSensitivity = createSetting (Type_DoubleSpinBox, "drag-wheel-factor", - "Mouse wheel sensitivity during drag operations"); - dragWheelSensitivity->setDefaultValue (1.0); - dragWheelSensitivity->setRange (0.001, 100.0); - - Setting *dragShiftFactor = createSetting (Type_DoubleSpinBox, "drag-shift-factor", - "Acceleration factor during drag operations while holding down shift"); - dragShiftFactor->setDefaultValue (4.0); - dragShiftFactor->setRange (0.001, 100.0); - } - - declareSection ("tooltips", "Tooltips"); - { - Setting *scene = createSetting (Type_CheckBox, "scene", "Show Tooltips in 3D scenes"); - scene->setDefaultValue ("true"); - - Setting *sceneHideBasic = createSetting (Type_CheckBox, "scene-hide-basic", "Hide basic 3D scenes tooltips"); - sceneHideBasic->setDefaultValue ("false"); - - Setting *sceneDelay = createSetting (Type_SpinBox, "scene-delay", - "Tooltip delay in milliseconds"); - sceneDelay->setDefaultValue (500); - sceneDelay->setRange (1, 10000); - } - - { - /****************************************************************** - * There are three types of values: - * - * Declared values - * - * Pre-determined values, typically for - * combobox drop downs and boolean (radiobutton / checkbox) labels. - * These values represent the total possible list of values that - * may define a setting. No other values are allowed. - * - * Defined values - * - * Values which represent the actual, current value of - * a setting. For settings with declared values, this must be one - * or several declared values, as appropriate. - * - * Proxy values - * Values the proxy master updates the proxy slave when - * it's own definition is set / changed. These are definitions for - * proxy slave settings, but must match any declared values the - * proxy slave has, if any. - *******************************************************************/ -/* - //create setting objects, specifying the basic widget type, - //the page name, and the view name - - Setting *masterBoolean = createSetting (Type_RadioButton, section, - "Master Proxy"); - - Setting *slaveBoolean = createSetting (Type_CheckBox, section, - "Proxy Checkboxes"); - - Setting *slaveSingleText = createSetting (Type_LineEdit, section, - "Proxy TextBox 1"); - - Setting *slaveMultiText = createSetting (Type_LineEdit, section, - "ProxyTextBox 2"); - - Setting *slaveAlphaSpinbox = createSetting (Type_SpinBox, section, - "Alpha Spinbox"); - - Setting *slaveIntegerSpinbox = createSetting (Type_SpinBox, section, - "Int Spinbox"); - - Setting *slaveDoubleSpinbox = createSetting (Type_DoubleSpinBox, - section, "Double Spinbox"); - - Setting *slaveSlider = createSetting (Type_Slider, section, "Slider"); - - Setting *slaveDial = createSetting (Type_Dial, section, "Dial"); - - //set declared values for selected views - masterBoolean->setDeclaredValues (QStringList() - << "Profile One" << "Profile Two" - << "Profile Three" << "Profile Four"); - - slaveBoolean->setDeclaredValues (QStringList() - << "One" << "Two" << "Three" << "Four" << "Five"); - - slaveAlphaSpinbox->setDeclaredValues (QStringList() - << "One" << "Two" << "Three" << "Four"); - - - masterBoolean->addProxy (slaveBoolean, QList () - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three" << "Five") - << (QStringList() << "Two" << "Four") - ); - - masterBoolean->addProxy (slaveSingleText, QList () - << (QStringList() << "Text A") - << (QStringList() << "Text B") - << (QStringList() << "Text A") - << (QStringList() << "Text C") - ); - - masterBoolean->addProxy (slaveMultiText, QList () - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three") - << (QStringList() << "One" << "Three" << "Five") - << (QStringList() << "Two" << "Four") - ); - - masterBoolean->addProxy (slaveAlphaSpinbox, QList () - << (QStringList() << "Four") - << (QStringList() << "Three") - << (QStringList() << "Two") - << (QStringList() << "One")); - - masterBoolean->addProxy (slaveIntegerSpinbox, QList () - << (QStringList() << "0") - << (QStringList() << "7") - << (QStringList() << "14") - << (QStringList() << "21")); - - masterBoolean->addProxy (slaveDoubleSpinbox, QList () - << (QStringList() << "0.17") - << (QStringList() << "0.34") - << (QStringList() << "0.51") - << (QStringList() << "0.68")); - - masterBoolean->addProxy (slaveSlider, QList () - << (QStringList() << "25") - << (QStringList() << "50") - << (QStringList() << "75") - << (QStringList() << "100") - ); - - masterBoolean->addProxy (slaveDial, QList () - << (QStringList() << "25") - << (QStringList() << "50") - << (QStringList() << "75") - << (QStringList() << "100") - ); - - //settings with proxies are not serialized by default - //other settings non-serialized for demo purposes - slaveBoolean->setSerializable (false); - slaveSingleText->setSerializable (false); - slaveMultiText->setSerializable (false); - slaveAlphaSpinbox->setSerializable (false); - slaveIntegerSpinbox->setSerializable (false); - slaveDoubleSpinbox->setSerializable (false); - slaveSlider->setSerializable (false); - slaveDial->setSerializable (false); - - slaveBoolean->setDefaultValues (QStringList() - << "One" << "Three" << "Five"); - - slaveSingleText->setDefaultValue ("Text A"); - - slaveMultiText->setDefaultValues (QStringList() - << "One" << "Three" << "Five"); - - slaveSingleText->setWidgetWidth (24); - slaveMultiText->setWidgetWidth (24); - - slaveAlphaSpinbox->setDefaultValue ("Two"); - slaveAlphaSpinbox->setWidgetWidth (20); - //slaveAlphaSpinbox->setPrefix ("No. "); - //slaveAlphaSpinbox->setSuffix ("!"); - slaveAlphaSpinbox->setWrapping (true); - - slaveIntegerSpinbox->setDefaultValue (14); - slaveIntegerSpinbox->setMinimum (0); - slaveIntegerSpinbox->setMaximum (58); - slaveIntegerSpinbox->setPrefix ("$"); - slaveIntegerSpinbox->setSuffix (".00"); - slaveIntegerSpinbox->setWidgetWidth (10); - slaveIntegerSpinbox->setSpecialValueText ("Nothing!"); - - slaveDoubleSpinbox->setDefaultValue (0.51); - slaveDoubleSpinbox->setSingleStep(0.17); - slaveDoubleSpinbox->setMaximum(4.0); - - slaveSlider->setMinimum (0); - slaveSlider->setMaximum (100); - slaveSlider->setDefaultValue (75); - slaveSlider->setWidgetWidth (100); - slaveSlider->setTicksAbove (true); - slaveSlider->setTickInterval (25); - - slaveDial->setMinimum (0); - slaveDial->setMaximum (100); - slaveDial->setSingleStep (5); - slaveDial->setDefaultValue (75); - slaveDial->setTickInterval (25); -*/ - } -} - -CSMSettings::UserSettings::~UserSettings() -{ - sUserSettingsInstance = 0; -} - -void CSMSettings::UserSettings::loadSettings (const QString &fileName) -{ - QString userFilePath = QString::fromUtf8 - (mCfgMgr.getUserConfigPath().string().c_str()); - - QString globalFilePath = QString::fromUtf8 - (mCfgMgr.getGlobalPath().string().c_str()); - - QString otherFilePath = globalFilePath; - - //test for local only if global fails (uninstalled copy) - if (!QFile (globalFilePath + fileName).exists()) - { - //if global is invalid, use the local path - otherFilePath = QString::fromUtf8 - (mCfgMgr.getLocalPath().string().c_str()); - } - - QSettings::setPath - (QSettings::IniFormat, QSettings::UserScope, userFilePath); - - QSettings::setPath - (QSettings::IniFormat, QSettings::SystemScope, otherFilePath); - - mSettingDefinitions = new QSettings - (QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this); -} - -// if the key is not found create one with a default value -QString CSMSettings::UserSettings::setting(const QString &viewKey, const QString &value) -{ - if(mSettingDefinitions->contains(viewKey)) - return settingValue(viewKey); - else if(value != QString()) - { - mSettingDefinitions->setValue (viewKey, QStringList() << value); - return value; - } - - return QString(); -} - -bool CSMSettings::UserSettings::hasSettingDefinitions (const QString &viewKey) const -{ - return (mSettingDefinitions->contains (viewKey)); -} - -void CSMSettings::UserSettings::setDefinitions - (const QString &key, const QStringList &list) -{ - mSettingDefinitions->setValue (key, list); -} - -void CSMSettings::UserSettings::saveDefinitions() const -{ - mSettingDefinitions->sync(); -} - -QString CSMSettings::UserSettings::settingValue (const QString &settingKey) -{ - QStringList defs; - - if (!mSettingDefinitions->contains (settingKey)) - return QString(); - - defs = mSettingDefinitions->value (settingKey).toStringList(); - - if (defs.isEmpty()) - return QString(); - - return defs.at(0); -} - -CSMSettings::UserSettings& CSMSettings::UserSettings::instance() -{ - assert(sUserSettingsInstance); - return *sUserSettingsInstance; -} - -void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, - const QStringList &list) -{ - mSettingDefinitions->setValue (settingKey ,list); - - emit userSettingUpdated (settingKey, list); -} - -CSMSettings::Setting *CSMSettings::UserSettings::findSetting - (const QString &pageName, const QString &settingName) -{ - foreach (Setting *setting, mSettings) - { - if (setting->name() == settingName) - { - if (setting->page() == pageName) - return setting; - } - } - return 0; -} - -void CSMSettings::UserSettings::removeSetting - (const QString &pageName, const QString &settingName) -{ - if (mSettings.isEmpty()) - return; - - QList ::iterator removeIterator = mSettings.begin(); - - while (removeIterator != mSettings.end()) - { - if ((*removeIterator)->name() == settingName) - { - if ((*removeIterator)->page() == pageName) - { - mSettings.erase (removeIterator); - break; - } - } - removeIterator++; - } -} - -CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const -{ - SettingPageMap pageMap; - - foreach (Setting *setting, mSettings) - { - SettingPageMap::iterator iter = pageMap.find (setting->page()); - - if (iter==pageMap.end()) - { - QPair > value; - - std::map::const_iterator iter2 = - mSectionLabels.find (setting->page()); - - value.first = iter2!=mSectionLabels.end() ? iter2->second : ""; - - iter = pageMap.insert (setting->page(), value); - } - - iter->second.append (setting); - } - - return pageMap; -} - -CSMSettings::Setting *CSMSettings::UserSettings::createSetting - (CSMSettings::SettingType type, const QString &name, const QString& label) -{ - Setting *setting = new Setting (type, name, mSection, label); - - // set useful defaults - int row = 1; - - if (!mSettings.empty()) - row = mSettings.back()->viewRow()+1; - - setting->setViewLocation (row, 1); - - setting->setColumnSpan (3); - - int width = 10; - - if (type==Type_CheckBox) - width = 40; - - setting->setWidgetWidth (width); - - if (type==Type_CheckBox) - setting->setStyleSheet ("QGroupBox { border: 0px; }"); - - if (type==Type_CheckBox) - setting->setDeclaredValues(QStringList() << "true" << "false"); - - if (type==Type_CheckBox) - setting->setSpecialValueText (setting->getLabel()); - - //add declaration to the model - mSettings.append (setting); - - return setting; -} - -void CSMSettings::UserSettings::declareSection (const QString& page, const QString& label) -{ - mSection = page; - mSectionLabels[page] = label; -} - -QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const -{ - if (mSettingDefinitions->contains (viewKey)) - return mSettingDefinitions->value (viewKey).toStringList(); - - return QStringList(); -} diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp deleted file mode 100644 index 5188a98429..0000000000 --- a/apps/opencs/model/settings/usersettings.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef USERSETTINGS_HPP -#define USERSETTINGS_HPP - -#include - -#include -#include -#include -#include -#include - -#include -#include "support.hpp" - -#ifndef Q_MOC_RUN -#include -#endif - -namespace Files { typedef std::vector PathContainer; - struct ConfigurationManager;} - -class QFile; -class QSettings; - -namespace CSMSettings { - - class Setting; - typedef QMap > > SettingPageMap; - - class UserSettings: public QObject - { - - Q_OBJECT - - static UserSettings *sUserSettingsInstance; - const Files::ConfigurationManager& mCfgMgr; - - QSettings *mSettingDefinitions; - QList mSettings; - QString mSection; - std::map mSectionLabels; - - public: - - /// Singleton implementation - static UserSettings& instance(); - - UserSettings (const Files::ConfigurationManager& configurationManager); - ~UserSettings(); - - UserSettings (UserSettings const &); //not implemented - UserSettings& operator= (UserSettings const &); //not implemented - - /// Retrieves the settings file at all three levels (global, local and user). - void loadSettings (const QString &fileName); - - /// Updates QSettings and syncs with the ini file - void setDefinitions (const QString &key, const QStringList &defs); - - QString settingValue (const QString &settingKey); - - ///retrieve a setting object from a given page and setting name - Setting *findSetting - (const QString &pageName, const QString &settingName = QString()); - - ///remove a setting from the list - void removeSetting - (const QString &pageName, const QString &settingName); - - ///Retrieve a map of the settings, keyed by page name - SettingPageMap settingPageMap() const; - - ///Returns a string list of defined vlaues for the specified setting - ///in "page/name" format. - QStringList definitions (const QString &viewKey) const; - - ///Test to indicate whether or not a setting has any definitions - bool hasSettingDefinitions (const QString &viewKey) const; - - ///Save any unsaved changes in the QSettings object - void saveDefinitions() const; - - QString setting(const QString &viewKey, const QString &value = QString()); - - private: - - void buildSettingModelDefaults(); - - ///add a new setting to the model and return it - Setting *createSetting (CSMSettings::SettingType type, const QString &name, - const QString& label); - - /// Set the section for createSetting calls. - /// - /// Sections can be declared multiple times. - void declareSection (const QString& page, const QString& label); - - signals: - - void userSettingUpdated (const QString &, const QStringList &); - - public slots: - - void updateUserSetting (const QString &, const QStringList &); - }; -} -#endif // USERSETTINGS_HPP diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 426e10ecbd..b1300a991f 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -16,7 +16,6 @@ #include #include "../widget/scenetoolmode.hpp" -#include "../../model/settings/usersettings.hpp" #include "lighting.hpp" diff --git a/apps/opencs/view/settings/booleanview.cpp b/apps/opencs/view/settings/booleanview.cpp deleted file mode 100644 index 8c759cabb0..0000000000 --- a/apps/opencs/view/settings/booleanview.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include - -#include -#include -#include - -#include - -#include "booleanview.hpp" -#include "../../model/settings/setting.hpp" - -CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting, - Page *parent) - : View (setting, parent), mType(setting->type()) -{ - foreach (const QString &value, setting->declaredValues()) - { - QAbstractButton *button = 0; - - switch (mType) - { - case CSMSettings::Type_CheckBox: { - if(mButtons.empty()) // show only one for checkboxes - { - button = new QCheckBox (value, this); - button->setChecked (setting->defaultValues().at(0) == "true" ? true : false); - - // special visual treatment option for checkboxes - if(setting->specialValueText() != "") { - Frame::setTitle(""); - button->setText(setting->specialValueText()); - } - } - } - break; - - case CSMSettings::Type_RadioButton: - button = new QRadioButton (value, this); - break; - - default: - break; - } - - if(button && (mType != CSMSettings::Type_CheckBox || mButtons.empty())) - { - connect (button, SIGNAL (clicked (bool)), - this, SLOT (slotToggled (bool))); - - button->setObjectName (value); - - addWidget (button); - - mButtons[value] = button; - } - } -} - -void CSVSettings::BooleanView::slotToggled (bool state) -{ - //test only for true to avoid multiple selection updates with radiobuttons - if (!isMultiValue() && !state) - return; - - QStringList values; - - foreach (QString key, mButtons.keys()) - { - // checkbox values are true/false unlike radio buttons - if(mType == CSMSettings::Type_CheckBox) - values.append(mButtons.value(key)->isChecked() ? "true" : "false"); - else - { - if (mButtons.value(key)->isChecked()) - values.append (key); - } - } - setSelectedValues (values, false); - - View::updateView(); -} - -void CSVSettings::BooleanView::updateView (bool signalUpdate) const -{ - - QStringList values = selectedValues(); - - foreach (const QString &buttonName, mButtons.keys()) - { - QAbstractButton *button = mButtons[buttonName]; - - //if the value is not found in the list, the widget is checked false - bool buttonValue = values.contains(buttonName); - - //skip if the butotn value will not change - if (button->isChecked() == buttonValue) - continue; - - //disable autoexclusive if it's enabled and we're setting - //the button value to false - bool switchExclusive = (!buttonValue && button->autoExclusive()); - - if (switchExclusive) - button->setAutoExclusive (false); - - button->setChecked (buttonValue); - - if (switchExclusive) - button->setAutoExclusive(true); - } - View::updateView (signalUpdate); -} - -CSVSettings::BooleanView *CSVSettings::BooleanViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new BooleanView (setting, parent); -} diff --git a/apps/opencs/view/settings/booleanview.hpp b/apps/opencs/view/settings/booleanview.hpp deleted file mode 100644 index 53198234a5..0000000000 --- a/apps/opencs/view/settings/booleanview.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CSVSETTINGS_BOOLEANVIEW_HPP -#define CSVSETTINGS_BOOLEANVIEW_HPP - -#include -#include - -#include "view.hpp" -#include "../../model/settings/support.hpp" - -class QStringListModel; - -namespace CSVSettings -{ - class BooleanView : public View - { - Q_OBJECT - - QMap mButtons; - enum CSMSettings::SettingType mType; - - public: - explicit BooleanView (CSMSettings::Setting *setting, - Page *parent); - - protected: - void updateView (bool signalUpdate = true) const; - - private slots: - void slotToggled (bool state); - }; - - class BooleanViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit BooleanViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - BooleanView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_BOOLEANVIEW_HPP diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp deleted file mode 100644 index 38eb7bbc7f..0000000000 --- a/apps/opencs/view/settings/dialog.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "dialog.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../../model/settings/usersettings.hpp" - -#include "page.hpp" - - -CSVSettings::Dialog::Dialog(QMainWindow *parent) - : SettingWindow (parent), mStackedWidget (0), mDebugMode (false) -{ - setWindowTitle(QString::fromUtf8 ("User Settings")); - - setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - setMinimumSize (600, 400); - - setupDialog(); - - connect (mPageListWidget, - SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), - this, - SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); -} - -void CSVSettings::Dialog::slotChangePage - (QListWidgetItem *cur, QListWidgetItem *prev) -{ - mStackedWidget->changePage - (mPageListWidget->row (cur), mPageListWidget->row (prev)); -} - -void CSVSettings::Dialog::setupDialog() -{ - QSplitter *centralWidget = new QSplitter (this); - centralWidget->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - setCentralWidget (centralWidget); - - buildPageListWidget (centralWidget); - buildStackedWidget (centralWidget); -} - -void CSVSettings::Dialog::buildPages() -{ - SettingWindow::createPages (); - - QFontMetrics fm (QApplication::font()); - - int maxWidth = 1; - - foreach (Page *page, SettingWindow::pages()) - { - maxWidth = std::max (maxWidth, fm.width(page->getLabel())); - - new QListWidgetItem (page->getLabel(), mPageListWidget); - - mStackedWidget->addWidget (page); - } - - mPageListWidget->setMaximumWidth (maxWidth + 10); - - resize (mStackedWidget->sizeHint()); -} - -void CSVSettings::Dialog::buildPageListWidget (QSplitter *centralWidget) -{ - mPageListWidget = new QListWidget (centralWidget); - mPageListWidget->setMinimumWidth(50); - mPageListWidget->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - - mPageListWidget->setSelectionBehavior (QAbstractItemView::SelectItems); - - centralWidget->addWidget(mPageListWidget); -} - -void CSVSettings::Dialog::buildStackedWidget (QSplitter *centralWidget) -{ - mStackedWidget = new ResizeableStackedWidget (centralWidget); - mStackedWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); - - centralWidget->addWidget (mStackedWidget); -} - -void CSVSettings::Dialog::closeEvent (QCloseEvent *event) -{ - //SettingWindow::closeEvent() must be called first to ensure - //model is updated - SettingWindow::closeEvent (event); - - saveSettings(); -} - -void CSVSettings::Dialog::show() -{ - if (pages().isEmpty()) - { - buildPages(); - setViewValues(); - } - - QWidget *currView = QApplication::activeWindow(); - if(currView) - { - // place at the center of the window with focus - QSize size = currView->size(); - move(currView->geometry().x()+(size.width() - frameGeometry().width())/2, - currView->geometry().y()+(size.height() - frameGeometry().height())/2); - } - else - { - // something's gone wrong, place at the center of the screen - QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); - move(screenCenter - QPoint(frameGeometry().width()/2, - frameGeometry().height()/2)); - } - QWidget::show(); -} diff --git a/apps/opencs/view/settings/dialog.hpp b/apps/opencs/view/settings/dialog.hpp deleted file mode 100644 index e3a3f575ac..0000000000 --- a/apps/opencs/view/settings/dialog.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef CSVSETTINGS_DIALOG_H -#define CSVSETTINGS_DIALOG_H - -#include "settingwindow.hpp" -#include "resizeablestackedwidget.hpp" - -class QStackedWidget; -class QListWidget; -class QListWidgetItem; -class QSplitter; - -namespace CSVSettings { - - class Page; - - class Dialog : public SettingWindow - { - Q_OBJECT - - QListWidget *mPageListWidget; - ResizeableStackedWidget *mStackedWidget; - bool mDebugMode; - - public: - - explicit Dialog (QMainWindow *parent = 0); - - protected: - - /// Settings are written on close - void closeEvent (QCloseEvent *event); - - void setupDialog(); - - private: - - void buildPages(); - void buildPageListWidget (QSplitter *centralWidget); - void buildStackedWidget (QSplitter *centralWidget); - - public slots: - - void show(); - - private slots: - - void slotChangePage (QListWidgetItem *, QListWidgetItem *); - }; -} -#endif // CSVSETTINGS_DIALOG_H diff --git a/apps/opencs/view/settings/frame.cpp b/apps/opencs/view/settings/frame.cpp deleted file mode 100644 index 454d3fefa4..0000000000 --- a/apps/opencs/view/settings/frame.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "frame.hpp" - -#include - -const QString CSVSettings::Frame::sInvisibleBoxStyle = - QString::fromUtf8("Frame { border:2px; padding: 2px; margin: 2px;}"); - -CSVSettings::Frame::Frame (bool isVisible, const QString &title, - QWidget *parent) - : QGroupBox (title, parent), mIsHorizontal (true), - mLayout (new SettingLayout()) -{ - setFlat (true); - mVisibleBoxStyle = styleSheet(); - - if (!isVisible) - { - // must be Page, not a View - setStyleSheet (sInvisibleBoxStyle); - } - - setLayout (mLayout); -} - -void CSVSettings::Frame::hideWidgets() -{ - for (int i = 0; i < children().size(); i++) - { - QObject *obj = children().at(i); - - Frame *widgFrame = dynamic_cast (obj); - - if (widgFrame) - { - widgFrame->hideWidgets(); - continue; - } - - QWidget *widg = static_cast (obj); - if (widg->property("sizePolicy").isValid()) - widg->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - } - - layout()->activate(); - setFixedSize(minimumSizeHint()); - -} - -void CSVSettings::Frame::showWidgets() -{ - for (int i = 0; i < children().size(); i++) - { - QObject *obj = children().at(i); - - Frame *widgFrame = dynamic_cast (obj); - - if (widgFrame) - { - widgFrame->showWidgets(); - continue; - } - - QWidget *widg = static_cast (obj); - - if (widg->property("sizePolicy").isValid()) - { - widg->setSizePolicy - (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - } - } - layout()->activate(); - setFixedSize(minimumSizeHint()); -} - -void CSVSettings::Frame::addWidget (QWidget *widget, int row, int column, - int rowSpan, int columnSpan) -{ - if (row == -1) - row = getNextRow(); - - if (column == -1) - column = getNextColumn(); - - mLayout->addWidget (widget, row, column, rowSpan, columnSpan); - //, Qt::AlignLeft | Qt::AlignTop); - - widget->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored); -} - -int CSVSettings::Frame::getNextRow () const -{ - int row = mLayout->rowCount(); - - if (mIsHorizontal && row > 0) - row--; - - return row; -} - -int CSVSettings::Frame::getNextColumn () const -{ - int column = 0; - - if (mIsHorizontal) - column = mLayout->columnCount(); - - return column; -} diff --git a/apps/opencs/view/settings/frame.hpp b/apps/opencs/view/settings/frame.hpp deleted file mode 100644 index bbb92f34f7..0000000000 --- a/apps/opencs/view/settings/frame.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CSVSETTINGS_FRAME_HPP -#define CSVSETTINGS_FRAME_HPP - -#include -#include -#include -#include "../../model/settings/support.hpp" - -namespace CSVSettings -{ - class SettingLayout : public QGridLayout - { - public: - explicit SettingLayout (QWidget *parent = 0) - : QGridLayout (parent) - { - setContentsMargins(0,0,0,0); - setAlignment(Qt::AlignLeft | Qt::AlignTop); - } - }; - - /// Custom implementation of QGroupBox to act as a base for view classes - class Frame : public QGroupBox - { - static const QString sInvisibleBoxStyle; - - QString mVisibleBoxStyle; - - bool mIsHorizontal; - - SettingLayout *mLayout; - - public: - explicit Frame (bool isVisible, const QString &title = "", - QWidget *parent = 0); - - ///Adds a widget to the grid layout, setting the position - ///relative to the last added widgets, or absolutely for positive - ///row / column values - void addWidget (QWidget *widget, int row = -1, int column = -1, - int rowSpan = 1, int columnSpan = 1); - - ///Force the grid to lay out in horizontal or vertical alignments - void setHLayout() { mIsHorizontal = true; } - void setVLayout() { mIsHorizontal = false; } - - ///show / hide widgets (when stacked widget page changes) - void showWidgets(); - void hideWidgets(); - - private: - - ///functions which return the index for the next layout row / column - int getNextColumn() const; - int getNextRow() const; - - }; -} - -#endif // CSVSETTINGS_FRAME_HPP diff --git a/apps/opencs/view/settings/listview.cpp b/apps/opencs/view/settings/listview.cpp deleted file mode 100644 index 0876b39820..0000000000 --- a/apps/opencs/view/settings/listview.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "listview.hpp" -#include "../../model/settings/setting.hpp" - -#include -#include -#include - -CSVSettings::ListView::ListView(CSMSettings::Setting *setting, - Page *parent) - : View(setting, parent), mAbstractItemView (0), mComboBox (0) -{ - QWidget *widget = - buildWidget(setting->isMultiLine(), setting->widgetWidth()); - - addWidget (widget, setting->viewRow(), setting->viewColumn()); - - if (mComboBox) - buildComboBoxModel(); - - else if (mAbstractItemView) - buildAbstractItemViewModel(); -} - -void CSVSettings::ListView::buildComboBoxModel() -{ - mComboBox->setModel (dataModel()); - mComboBox->setModelColumn (0); - mComboBox->view()->setSelectionModel (selectionModel()); - - int curIdx = -1; - - if (!selectionModel()->selection().isEmpty()) - curIdx = selectionModel()->selectedIndexes().at(0).row(); - - mComboBox->setCurrentIndex (curIdx); - - connect (mComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(emitItemViewUpdate(int))); -} - -void CSVSettings::ListView::buildAbstractItemViewModel() -{ - mAbstractItemView->setModel (dataModel()); - mAbstractItemView->setSelectionModel (selectionModel()); - - //connection needs to go here for list view update to signal to - //the outside -} - -void CSVSettings::ListView::emitItemViewUpdate (int idx) -{ - updateView(); -} - -QWidget *CSVSettings::ListView::buildWidget(bool isMultiLine, int width) -{ - QWidget *widget = 0; - - if (isMultiLine) - { - mAbstractItemView = new QListView (this); - widget = mAbstractItemView; - - if (width > 0) - widget->setFixedWidth (widgetWidth (width)); - } - else - { - mComboBox = new QComboBox (this); - widget = mComboBox; - - if (width > 0) - mComboBox->setMinimumContentsLength (width); - } - - return widget; -} - -void CSVSettings::ListView::showEvent ( QShowEvent * event ) -{ - View::showEvent (event); -} - -void CSVSettings::ListView::updateView (bool signalUpdate) const -{ - QStringList values = selectedValues(); - - if (mComboBox) - { - int idx = -1; - - if (values.size() > 0) - idx = (mComboBox->findText(values.at(0))); - - mComboBox->setCurrentIndex (idx); - } - - View::updateView (signalUpdate); -} - -CSVSettings::ListView *CSVSettings::ListViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new ListView(setting, parent); -} diff --git a/apps/opencs/view/settings/listview.hpp b/apps/opencs/view/settings/listview.hpp deleted file mode 100644 index c2860d769a..0000000000 --- a/apps/opencs/view/settings/listview.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef CSVSETTINGS_LISTVIEW_HPP -#define CSVSETTINGS_LISTVIEW_HPP - -#include "view.hpp" - - -class QStringListModel; -class QComboBox; -class QAbstractItemView; - -namespace CSVSettings -{ - class ListView : public View - { - Q_OBJECT - - QAbstractItemView *mAbstractItemView; - QComboBox *mComboBox; - - public: - explicit ListView (CSMSettings::Setting *setting, - Page *parent); - - protected: - - void updateView (bool signalUpdate = true) const; - void showEvent ( QShowEvent * event ); - - ///Receives signal from widget and signals viwUpdated() - void slotTextEdited (QString value); - - private: - - ///Helper function to construct a model for an AbstractItemView - void buildAbstractItemViewModel(); - - ///Helper function to construct a model for a combobox - void buildComboBoxModel(); - - ///Helper function to build the view widget - QWidget *buildWidget (bool isMultiLine, int width); - - private slots: - - ///Receives updates from single-select widgets (like combobox) and - ///signals viewUpdated with the selected values. - void emitItemViewUpdate (int idx); - }; - - class ListViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit ListViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - ListView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_LISTVIEW_HPP diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp deleted file mode 100644 index c009cdd7a5..0000000000 --- a/apps/opencs/view/settings/page.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "page.hpp" - -#include - -#include "view.hpp" -#include "booleanview.hpp" -#include "textview.hpp" -#include "listview.hpp" -#include "rangeview.hpp" - -#include "../../model/settings/usersettings.hpp" -#include "../../model/settings/connector.hpp" -#include "../../model/settings/support.hpp" - -#include "settingwindow.hpp" - -QMap - CSVSettings::Page::mViewFactories; - -CSVSettings::Page::Page (const QString &pageName, QList settingList, - SettingWindow *parent, const QString& label) -: Frame(false, "", parent), mParent(parent), mIsEditorPage (false), mLabel (label) -{ - setObjectName (pageName); - - if (mViewFactories.size() == 0) - buildFactories(); - - setVLayout(); - setupViews (settingList); -} - -void CSVSettings::Page::setupViews - (QList &settingList) -{ - foreach (CSMSettings::Setting *setting, settingList) - addView (setting); -} - -void CSVSettings::Page::addView (CSMSettings::Setting *setting) -{ - if (setting->viewType() == ViewType_Undefined) - { - if(setting->specialValueText() != "") - { - // hack to put a label - addWidget(new QLabel(setting->specialValueText()), - setting->viewRow(), setting->viewColumn(), - setting->rowSpan(), setting->columnSpan()); - return; - } - else - return; - } - - View *view = mViewFactories[setting->viewType()]->createView(setting, this); - - if (!view) - return; - - mViews.append (view); - - addWidget (view, setting->viewRow(), setting->viewColumn(), - setting->rowSpan(), setting->columnSpan() ); - - //if this page is an editor page, connect each of it's views up to the - //UserSettings singleton for signaling back to OpenCS - if (setting->isEditorSetting()) { - connect (view, SIGNAL (viewUpdated(const QString&, const QStringList&)), - &CSMSettings::UserSettings::instance(), - SLOT (updateUserSetting (const QString &, const QStringList &))); - } -} - -CSVSettings::View *CSVSettings::Page::findView (const QString &page, - const QString &setting) const -{ - - //if this is not the page we're looking for, - //appeal to the parent setting window to find the appropriate view - if (page != objectName()) - return mParent->findView (page, setting); - - //otherwise, return the matching view - for (int i = 0; i < mViews.size(); i++) - { - View *view = mViews.at(i); - - if (view->parentPage()->objectName() != page) - continue; - - if (view->objectName() == setting) - return view; - } - - return 0; -} - -void CSVSettings::Page::buildFactories() -{ - mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this); - mViewFactories[ViewType_Text] = new TextViewFactory (this); - mViewFactories[ViewType_List] = new ListViewFactory (this); - mViewFactories[ViewType_Range] = new RangeViewFactory (this); -} - -QString CSVSettings::Page::getLabel() const -{ - return mLabel; -} diff --git a/apps/opencs/view/settings/page.hpp b/apps/opencs/view/settings/page.hpp deleted file mode 100644 index caf2eec3fe..0000000000 --- a/apps/opencs/view/settings/page.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef CSVSETTINGS_PAGE_HPP -#define CSVSETTINGS_PAGE_HPP - -#include -#include -#include - -#include "frame.hpp" - -#include "../../model/settings/support.hpp" - -namespace CSMSettings { class Setting; } - -namespace CSVSettings -{ - class View; - class IViewFactory; - class SettingWindow; - - class Page : public Frame - { - Q_OBJECT - - QList mViews; - SettingWindow *mParent; - static QMap mViewFactories; - bool mIsEditorPage; - QString mLabel; - - public: - Page (const QString &pageName, QList settingList, - SettingWindow *parent, const QString& label); - - ///Creates a new view based on the passed setting and adds it to - ///the page. - void addView (CSMSettings::Setting *setting); - - ///Iterates the views created for this page based on the passed setting - ///and returns it. - View *findView (const QString &page, const QString &setting) const; - - ///returns the list of views associated with the page - const QList &views () const { return mViews; } - - QString getLabel() const; - - private: - - ///Creates views based on the passed setting list - void setupViews (QList &settingList); - - ///Creates factory objects for view construction - void buildFactories(); - }; -} -#endif // CSVSETTINGS_PAGE_HPP diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp deleted file mode 100644 index 5893c5d0da..0000000000 --- a/apps/opencs/view/settings/rangeview.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "rangeview.hpp" -#include "spinbox.hpp" -#include "../../model/settings/setting.hpp" -#include "../../model/settings/support.hpp" - -CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, - Page *parent) - : View (setting, parent), mRangeWidget (0), mRangeType (setting->type()) -{ - - mRangeWidget = 0; - - if (isMultiValue()) - return; - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - case CSMSettings::Type_DoubleSpinBox: - buildSpinBox (setting); - break; - - case CSMSettings::Type_Dial: - case CSMSettings::Type_Slider: - buildSlider (setting); - break; - - default: - break; - } - - if(mRangeWidget) - { - mRangeWidget->setFixedWidth (widgetWidth (setting->widgetWidth())); - mRangeWidget->setObjectName (setting->name()); - } - - addWidget (mRangeWidget); -} - -void CSVSettings::RangeView::buildSlider (CSMSettings::Setting *setting) -{ - switch (setting->type()) - { - case CSMSettings::Type_Slider: - mRangeWidget = new QSlider (Qt::Horizontal, this); - mRangeWidget->setProperty ("tickInterval", setting->tickInterval()); - - if (setting->ticksAbove()) - { - if (setting->ticksBelow()) - mRangeWidget->setProperty ("tickPosition", QSlider::TicksBothSides); - else - mRangeWidget->setProperty ("tickPosition", QSlider::TicksAbove); - } - else if (setting->ticksBelow()) - mRangeWidget->setProperty ("tickPosition", QSlider::TicksBelow); - else - mRangeWidget->setProperty ("tickPosition", QSlider::NoTicks); - - break; - - case CSMSettings::Type_Dial: - mRangeWidget = new QDial (this); - mRangeWidget->setProperty ("wrapping", setting->wrapping()); - mRangeWidget->setProperty ("notchesVisible", - (setting->ticksAbove() || setting->ticksBelow())); - break; - - default: - break; - } - - if(mRangeWidget) - { - mRangeWidget->setProperty ("minimum", setting->minimum()); - mRangeWidget->setProperty ("maximum", setting->maximum()); - mRangeWidget->setProperty ("tracking", false); - mRangeWidget->setProperty ("singleStep", setting->singleStep()); - - connect (mRangeWidget, SIGNAL (valueChanged (int)), - this, SLOT (slotUpdateView (int))); - } -} - -void CSVSettings::RangeView::buildSpinBox (CSMSettings::Setting *setting) -{ - SpinBox *sb = 0; - - switch (setting->type()) - { - case CSMSettings::Type_SpinBox: - - sb = new SpinBox (this); - - if (!setting->declaredValues().isEmpty()) - sb->setValueList (setting->declaredValues()); - - mRangeWidget = sb; - - connect (mRangeWidget, SIGNAL (valueChanged (int)), - this, SLOT (slotUpdateView (int))); - break; - - case CSMSettings::Type_DoubleSpinBox: - mRangeWidget = new QDoubleSpinBox (this); - - connect (mRangeWidget, SIGNAL (valueChanged (double)), - this, SLOT (slotUpdateView (double))); - break; - - default: - return; - } - - //min / max values are set automatically in AlphaSpinBox - if (setting->declaredValues().isEmpty()) - { - mRangeWidget->setProperty ("minimum", setting->minimum()); - mRangeWidget->setProperty ("maximum", setting->maximum()); - mRangeWidget->setProperty ("singleStep", setting->singleStep()); - } - - mRangeWidget->setProperty ("prefix", setting->prefix()); - mRangeWidget->setProperty ("suffix", setting->suffix()); - mRangeWidget->setProperty ("wrapping", setting->wrapping()); - dynamic_cast (mRangeWidget)->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - - if(setting->type() == CSMSettings::Type_SpinBox && setting->declaredValues().isEmpty()) - dynamic_cast (mRangeWidget)->setValue (setting->defaultValues().at(0).toInt()); -} - -void CSVSettings::RangeView::slotUpdateView (int value) -{ - QString textValue = ""; - QStringList list; - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - list = static_cast (mRangeWidget)->valueList(); - if (!list.isEmpty()) - textValue = list.at(value); - break; - - default: - break; - } - - if (textValue.isEmpty()) - textValue = QVariant (value).toString(); - - setSelectedValue (textValue, false); - - View::updateView(); -} - -void CSVSettings::RangeView::slotUpdateView (double value) -{ - setSelectedValue (QVariant(value).toString(), false); - - View::updateView(); -} - -void CSVSettings::RangeView::updateView (bool signalUpdate) const -{ - QString value; - - if (!selectedValues().isEmpty()) - value = selectedValues().at(0); - - switch (mRangeType) - { - case CSMSettings::Type_SpinBox: - static_cast (mRangeWidget)->setValue (value); - break; - - case CSMSettings::Type_DoubleSpinBox: - static_cast (mRangeWidget)->setValue (value.toDouble()); - break; - - case CSMSettings::Type_Slider: - case CSMSettings::Type_Dial: - mRangeWidget->setProperty ("value", value.toInt()); - mRangeWidget->setProperty ("sliderPosition", value.toInt()); - break; - - default: - break; - - } - - View::updateView (signalUpdate); -} - -CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new RangeView (setting, parent); -} diff --git a/apps/opencs/view/settings/rangeview.hpp b/apps/opencs/view/settings/rangeview.hpp deleted file mode 100644 index 2ab343f1f9..0000000000 --- a/apps/opencs/view/settings/rangeview.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CSVSETTINGS_RANGEVIEW_HPP -#define CSVSETTINGS_RANGEVIEW_HPP - -#include "view.hpp" -#include "../../model/settings/support.hpp" - -class QStringListModel; -class QAbstractSpinBox; - -namespace CSVSettings -{ - class RangeView : public View - { - Q_OBJECT - - QWidget *mRangeWidget; - CSMSettings::SettingType mRangeType; - - public: - explicit RangeView (CSMSettings::Setting *setting, - Page *parent); - - protected: - - ///virtual function called through View - void updateView (bool signalUpdate = true) const; - - ///construct a slider-based view - void buildSlider (CSMSettings::Setting *setting); - - ///construct a spinbox-based view - void buildSpinBox (CSMSettings::Setting *setting); - - private slots: - - ///responds to valueChanged signals - void slotUpdateView (int value); - void slotUpdateView (double value); - - }; - - class RangeViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit RangeViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - RangeView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_RANGEVIEW_HPP diff --git a/apps/opencs/view/settings/resizeablestackedwidget.cpp b/apps/opencs/view/settings/resizeablestackedwidget.cpp deleted file mode 100644 index 0e87a25062..0000000000 --- a/apps/opencs/view/settings/resizeablestackedwidget.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "resizeablestackedwidget.hpp" -#include "page.hpp" - -#include - -CSVSettings::ResizeableStackedWidget::ResizeableStackedWidget(QWidget *parent) : - QStackedWidget(parent) -{} - -void CSVSettings::ResizeableStackedWidget::addWidget(QWidget* pWidget) -{ - QStackedWidget::addWidget(pWidget); -} - -void CSVSettings::ResizeableStackedWidget::changePage - (int current, int previous) -{ - if (current == previous) - return; - - Page *prevPage = 0; - Page *curPage = 0; - - if (previous > -1) - prevPage = static_cast (widget (previous)); - - if (current > -1) - curPage = static_cast (widget (current)); - - if (prevPage) - prevPage->hideWidgets(); - - if (curPage) - curPage->showWidgets(); - - layout()->activate(); - - setCurrentIndex (current); -} diff --git a/apps/opencs/view/settings/resizeablestackedwidget.hpp b/apps/opencs/view/settings/resizeablestackedwidget.hpp deleted file mode 100644 index 2d0c71a23a..0000000000 --- a/apps/opencs/view/settings/resizeablestackedwidget.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP -#define CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP - -#include - -class QListWidgetItem; - -namespace CSVSettings -{ - class ResizeableStackedWidget : public QStackedWidget - { - Q_OBJECT - - public: - explicit ResizeableStackedWidget(QWidget *parent = 0); - - ///add a widget to the stacked widget - void addWidget(QWidget* pWidget); - - ///called whenever the stacked widget page is changed - void changePage (int, int); - }; -} - -#endif // CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP diff --git a/apps/opencs/view/settings/settingwindow.cpp b/apps/opencs/view/settings/settingwindow.cpp deleted file mode 100644 index 76ea9dc4fe..0000000000 --- a/apps/opencs/view/settings/settingwindow.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include - -#include "../../model/settings/setting.hpp" -#include "../../model/settings/connector.hpp" -#include "../../model/settings/usersettings.hpp" -#include "settingwindow.hpp" -#include "page.hpp" -#include "view.hpp" - -CSVSettings::SettingWindow::SettingWindow(QWidget *parent) - : QMainWindow(parent), mModel(NULL) -{} - -void CSVSettings::SettingWindow::createPages() -{ - CSMSettings::SettingPageMap pageMap = mModel->settingPageMap(); - - QList connectedSettings; - - foreach (const QString &pageName, pageMap.keys()) - { - QList pageSettings = pageMap.value (pageName).second; - - mPages.append (new Page (pageName, pageSettings, this, pageMap.value (pageName).first)); - - for (int i = 0; i < pageSettings.size(); i++) - { - CSMSettings::Setting *setting = pageSettings.at(i); - - if (!setting->proxyLists().isEmpty()) - connectedSettings.append (setting); - } - } - - if (!connectedSettings.isEmpty()) - createConnections(connectedSettings); -} - -void CSVSettings::SettingWindow::createConnections - (const QList &list) -{ - foreach (const CSMSettings::Setting *setting, list) - { - View *masterView = findView (setting->page(), setting->name()); - - CSMSettings::Connector *connector = - new CSMSettings::Connector (masterView, this); - - connect (masterView, - SIGNAL (viewUpdated(const QString &, const QStringList &)), - connector, - SLOT (slotUpdateSlaves()) - ); - - const CSMSettings::ProxyValueMap &proxyMap = setting->proxyLists(); - - foreach (const QString &key, proxyMap.keys()) - { - QStringList keyPair = key.split('/'); - - if (keyPair.size() != 2) - continue; - - View *slaveView = findView (keyPair.at(0), keyPair.at(1)); - - if (!slaveView) - { - qWarning () << "Unable to create connection for view " - << key; - continue; - } - - QList proxyList = proxyMap.value (key); - connector->addSlaveView (slaveView, proxyList); - - connect (slaveView, - SIGNAL (viewUpdated(const QString &, const QStringList &)), - connector, - SLOT (slotUpdateMaster())); - } - } -} - -void CSVSettings::SettingWindow::setViewValues() -{ - //iterate each page and view, setting their definitions - //if they exist in the model - foreach (const Page *page, mPages) - { - foreach (const View *view, page->views()) - { - //testing beforehand prevents overwriting a proxy setting - if (!mModel->hasSettingDefinitions (view->viewKey())) - continue; - - QStringList defs = mModel->definitions (view->viewKey()); - - view->setSelectedValues(defs); - } - } -} - -CSVSettings::View *CSVSettings::SettingWindow::findView - (const QString &pageName, const QString &setting) -{ - foreach (const Page *page, mPages) - { - if (page->objectName() == pageName) - return page->findView (pageName, setting); - } - return 0; -} - -void CSVSettings::SettingWindow::saveSettings() -{ - //setting the definition in the model automatically syncs with the file - foreach (const Page *page, mPages) - { - foreach (const View *view, page->views()) - { - if (!view->serializable()) - continue; - - mModel->setDefinitions (view->viewKey(), view->selectedValues()); - } - } - - mModel->saveDefinitions(); -} - diff --git a/apps/opencs/view/settings/settingwindow.hpp b/apps/opencs/view/settings/settingwindow.hpp deleted file mode 100644 index 11bceee96b..0000000000 --- a/apps/opencs/view/settings/settingwindow.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef CSVSETTINGS_SETTINGWINDOW_HPP -#define CSVSETTINGS_SETTINGWINDOW_HPP - -#include -#include - -#include "../../model/settings/support.hpp" - -namespace CSMSettings { - class Setting; - class UserSettings; -} - -namespace CSVSettings { - - class Page; - class View; - - typedef QList PageList; - - class SettingWindow : public QMainWindow - { - Q_OBJECT - - PageList mPages; - CSMSettings::UserSettings *mModel; - - public: - explicit SettingWindow(QWidget *parent = 0); - - ///retrieve a reference to a view based on it's page and setting name - View *findView (const QString &pageName, const QString &setting); - - ///set the model the view uses (instance of UserSettings) - void setModel (CSMSettings::UserSettings &model) { mModel = &model; } - - protected: - - ///construct the pages to be displayed in the dialog - void createPages(); - - ///return the list of constructed pages - const PageList &pages() const { return mPages; } - - ///save settings from the GUI to file - void saveSettings(); - - ///sets the defined values for the views that have been created - void setViewValues(); - - private: - - ///create connections between settings (used for proxy settings) - void createConnections (const QList &list); - }; -} - -#endif // CSVSETTINGS_SETTINGWINDOW_HPP diff --git a/apps/opencs/view/settings/spinbox.cpp b/apps/opencs/view/settings/spinbox.cpp deleted file mode 100644 index 043107bb76..0000000000 --- a/apps/opencs/view/settings/spinbox.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "spinbox.hpp" - -#include - -CSVSettings::SpinBox::SpinBox(QWidget *parent) - : QSpinBox(parent), mValueList(QStringList()) -{ - setRange (0, 0); -} - -QString CSVSettings::SpinBox::textFromValue(int val) const -{ - if (mValueList.isEmpty()) - return QVariant (val).toString(); - - QString value; - - if (val < mValueList.size()) - value = mValueList.at (val); - - return value; -} - -int CSVSettings::SpinBox::valueFromText(const QString &text) const -{ - if (mValueList.isEmpty()) - return text.toInt(); // TODO: assumed integer, untested error handling for alpha types - - if (mValueList.contains (text)) - return mValueList.indexOf(text); - - return -1; -} - -void CSVSettings::SpinBox::setValue (const QString &value) -{ - if (!mValueList.isEmpty()) - { - lineEdit()->setText (value); - QSpinBox::setValue(valueFromText(value)); - } - else - QSpinBox::setValue (value.toInt()); -} - -void CSVSettings::SpinBox::setValueList (const QStringList &list) -{ - mValueList = list; - setMaximum (list.size() - 1); -} diff --git a/apps/opencs/view/settings/spinbox.hpp b/apps/opencs/view/settings/spinbox.hpp deleted file mode 100644 index e887e8c937..0000000000 --- a/apps/opencs/view/settings/spinbox.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CSVSETTINGS_SPINBOX_HPP -#define CSVSETTINGS_SPINBOX_HPP - -#include -#include -#include - -namespace CSVSettings -{ - class SpinBox : public QSpinBox - { - Q_OBJECT - - QStringList mValueList; - - public: - explicit SpinBox(QWidget *parent = 0); - - ///set the value displayed in the spin box - void setValue (const QString &value); - - ///set the stringlist that's used as a list of pre-defined values - ///to be displayed as the user scrolls - void setValueList (const QStringList &list); - - ///returns the pre-defined value list. - const QStringList &valueList() const { return mValueList; } - - protected: - - ///converts an index value to corresponding text to be displayed - QString textFromValue (int val) const; - - ///converts a text value to a corresponding index - int valueFromText (const QString &text) const; - }; -} -#endif // CSVSETTINGS_SPINBOX_HPP diff --git a/apps/opencs/view/settings/textview.cpp b/apps/opencs/view/settings/textview.cpp deleted file mode 100644 index a6ab657fe2..0000000000 --- a/apps/opencs/view/settings/textview.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -#include "textview.hpp" -#include "../../model/settings/setting.hpp" - -CSVSettings::TextView::TextView(CSMSettings::Setting *setting, Page *parent) - : View (setting, parent), mDelimiter (setting->delimiter()) - -{ - if (setting->isMultiLine()) - mTextWidget = new QTextEdit ("", this); - else - mTextWidget = new QLineEdit ("", this); - - if (setting->widgetWidth() > 0) - mTextWidget->setFixedWidth (widgetWidth (setting->widgetWidth())); - - connect (mTextWidget, SIGNAL (textEdited (QString)), - this, SLOT (slotTextEdited (QString))); - - addWidget (mTextWidget, setting->viewRow(), setting->viewColumn()); -} - -bool CSVSettings::TextView::isEquivalent - (const QString &lhs, const QString &rhs) const -{ - return (lhs.trimmed() == rhs.trimmed()); -} - -void CSVSettings::TextView::slotTextEdited (QString value) -{ - QStringList values = value.split (mDelimiter, QString::SkipEmptyParts); - - QStringList returnValues; - - foreach (const QString &splitValue, values) - returnValues.append (splitValue.trimmed()); - - setSelectedValues (returnValues, false); - - View::updateView(); -} - -void CSVSettings::TextView::updateView(bool signalUpdate) const -{ - QString values = selectedValues().join (mDelimiter); - - if (isEquivalent (mTextWidget->property("text").toString(), values)) - return; - - mTextWidget->setProperty("text", values); - - View::updateView (signalUpdate); -} - -CSVSettings::TextView *CSVSettings::TextViewFactory::createView - (CSMSettings::Setting *setting, - Page *parent) -{ - return new TextView (setting, parent); -} - diff --git a/apps/opencs/view/settings/textview.hpp b/apps/opencs/view/settings/textview.hpp deleted file mode 100644 index f4cd03d2f6..0000000000 --- a/apps/opencs/view/settings/textview.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef CSVSETTINGS_TEXTVIEW_HPP -#define CSVSETTINGS_TEXTVIEW_HPP - -#include "view.hpp" -#include "../../model/settings/setting.hpp" - -namespace CSVSettings -{ - class TextView : public View - { - Q_OBJECT - - QWidget *mTextWidget; - - QString mDelimiter; - - public: - explicit TextView (CSMSettings::Setting *setting, - Page *parent = 0); - - protected: - - /// virtual function called through View - void updateView (bool signalUpdate = true) const; - - protected slots: - - ///Receives updates to the widget for signalling - void slotTextEdited (QString value); - - private: - - ///Comparison function that returns true if the trimmed() strings - ///are equal - bool isEquivalent (const QString &lhs, const QString &rhs) const; - }; - - class TextViewFactory : public QObject, public IViewFactory - { - Q_OBJECT - - public: - explicit TextViewFactory (QWidget *parent = 0) - : QObject (parent) - {} - - TextView *createView (CSMSettings::Setting *setting, - Page *parent); - }; -} -#endif // CSVSETTINGS_TEXTVIEW_HPP diff --git a/apps/opencs/view/settings/view.cpp b/apps/opencs/view/settings/view.cpp deleted file mode 100644 index 21cf55fddd..0000000000 --- a/apps/opencs/view/settings/view.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include -#include -#include - -#include "view.hpp" -#include "../../model/settings/support.hpp" -#include "../../model/settings/setting.hpp" -#include "page.hpp" - -CSVSettings::View::View(CSMSettings::Setting *setting, - Page *parent) - - : Frame(true, setting->getLabel(), parent), - mParentPage (parent), mDataModel(0), - mHasFixedValues (!setting->declaredValues().isEmpty()), - mIsMultiValue (setting->isMultiValue()), - mViewKey (setting->page() + '/' + setting->name()), - mSerializable (setting->serializable()) -{ - if (!setting->getToolTip().isEmpty()) - setToolTip (setting->getToolTip()); - - setObjectName (setting->name()); - buildView(); - buildModel (setting); - // apply stylesheet to view's frame if exists - if(setting->styleSheet() != "") - Frame::setStyleSheet (setting->styleSheet()); -} - -void CSVSettings::View::buildModel (const CSMSettings::Setting *setting) -{ - QStringList values = setting->defaultValues(); - - if (mHasFixedValues) - buildFixedValueModel (setting->declaredValues()); - else - buildUpdatableValueModel (values); - - mSelectionModel = new QItemSelectionModel (mDataModel, this); - - setSelectedValues (values, false); -} - -void CSVSettings::View::buildFixedValueModel (const QStringList &values) -{ - //fixed value models are simple string list models, since they are read-only - mDataModel = new QStringListModel (values, this); -} - -void CSVSettings::View::buildUpdatableValueModel (const QStringList &values) -{ - //updateable models are standard item models because they support - //replacing entire columns - QList itemList; - - foreach (const QString &value, values) - itemList.append (new QStandardItem(value)); - - QStandardItemModel *model = new QStandardItemModel (this); - model->appendColumn (itemList); - - mDataModel = model; -} - -void CSVSettings::View::buildView() -{ - setFlat (true); - setHLayout(); -} - -int CSVSettings::View::currentIndex () const -{ - if (selectedValues().isEmpty()) - return -1; - - QString currentValue = selectedValues().at(0); - - for (int i = 0; i < mDataModel->rowCount(); i++) - if (value(i) == currentValue) - return i; - - return -1; -} - -void CSVSettings::View::refresh() const -{ - select (mSelectionModel->selection()); - updateView(); -} - -int CSVSettings::View::rowCount() const -{ - return mDataModel->rowCount(); -} - -void CSVSettings::View::select (const QItemSelection &selection) const -{ - mSelectionModel->clear(); - mSelectionModel->select(selection, QItemSelectionModel::Select); -} - -QStringList CSVSettings::View::selectedValues() const -{ - QStringList selValues; - - foreach (const QModelIndex &idx, mSelectionModel->selectedIndexes()) - selValues.append (value(idx.row())); - - return selValues; -} - -void CSVSettings::View::setSelectedValue (const QString &value, - bool doViewUpdate, bool signalUpdate) -{ - setSelectedValues (QStringList() << value, doViewUpdate, signalUpdate); -} - -void CSVSettings::View::setSelectedValues (const QStringList &list, - bool doViewUpdate, bool signalUpdate) const -{ - QItemSelection selection; - - if (stringListsMatch (list, selectedValues())) - return; - - if (!mHasFixedValues) - { - QStandardItemModel *model = - static_cast (mDataModel); - - model->clear(); - model->appendColumn (toStandardItemList (list)); - - for (int i = 0; i < model->rowCount(); i++) - { - QModelIndex idx = model->index(i, 0); - selection.append (QItemSelectionRange (idx, idx)); - } - } - else - { - for (int i = 0; i < mDataModel->rowCount(); i++) - { - if (list.contains(value(i))) - { - QModelIndex idx = mDataModel->index(i, 0); - selection.append(QItemSelectionRange (idx, idx)); - } - } - } - select (selection); - - //update the view if the selection was set from the model side, not by the - //user - if (doViewUpdate) - updateView (signalUpdate); -} - -void CSVSettings::View::showEvent ( QShowEvent * event ) -{ - refresh(); -} - -bool CSVSettings::View::stringListsMatch ( - const QStringList &list1, - const QStringList &list2) const -{ - //returns a "sloppy" match, verifying that each list contains all the same - //items, though not necessarily in the same order. - - if (list1.size() != list2.size()) - return false; - - QStringList tempList(list2); - - //iterate each value in the list, removing one occurrence of the value in - //the other list. If no corresponding value is found, test fails - foreach (const QString &value, list1) - { - if (!tempList.contains(value)) - return false; - - tempList.removeOne(value); - } - return true; -} - -QList CSVSettings::View::toStandardItemList - (const QStringList &list) const -{ - QList itemList; - - foreach (const QString &value, list) - itemList.append (new QStandardItem (value)); - - return itemList; -} - -void CSVSettings::View::updateView (bool signalUpdate) const -{ - if (signalUpdate) - emit viewUpdated(viewKey(), selectedValues()); -} - -QString CSVSettings::View::value (int row) const -{ - if (row > -1 && row < mDataModel->rowCount()) - return mDataModel->data (mDataModel->index(row, 0)).toString(); - - return QString(); -} - -int CSVSettings::View::widgetWidth(int characterCount) const -{ - QString widthToken = QString().fill ('m', characterCount); - QFontMetrics fm (QApplication::font()); - - return (fm.width (widthToken)); -} diff --git a/apps/opencs/view/settings/view.hpp b/apps/opencs/view/settings/view.hpp deleted file mode 100644 index 84ad62759e..0000000000 --- a/apps/opencs/view/settings/view.hpp +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef CSVSETTINGS_VIEW_HPP -#define CSVSETTINGS_VIEW_HPP - -#include -#include - -#include "frame.hpp" -#include "../../model/settings/support.hpp" - -class QGroupBox; -class QStringList; -class QStandardItem; -class QItemSelection; -class QAbstractItemModel; -class QItemSelectionModel; - -namespace CSMSettings { class Setting; } - -namespace CSVSettings -{ - class Page; - - class View : public Frame - { - Q_OBJECT - - ///Pointer to the owning Page instance - Page *mParentPage; - - ///Pointer to the selection model for the view - QItemSelectionModel *mSelectionModel; - - ///Pointer to the data model for the view's selection model - QAbstractItemModel *mDataModel; - - ///State indicating whether or not the setting has a pre-defined list - ///of values, limiting possible definitions - bool mHasFixedValues; - - ///State indicating whether the view will allow multiple values - bool mIsMultiValue; - - ///'pagename.settingname' form of the view's id - QString mViewKey; - - ///indicates whether or not the setting is written to file - bool mSerializable; - - public: - - explicit View (CSMSettings::Setting *setting, Page *parent); - - ///Returns the index / row of the passed value, -1 if not found. - int currentIndex () const; - - ///Returns the number of rows in the view's data model - int rowCount() const; - - ///Returns bool indicating the data in this view should / should not - ///be serialized to a config file - bool serializable() const { return mSerializable; } - - ///Returns a pointer to the view's owning parent page - const Page *parentPage() const { return mParentPage; } - - ///Returns the selected items in the selection model as a QStringList - QStringList selectedValues() const; - - ///Sets the selected items in the selection model based on passed list. - ///Bools allow opt-out of updating the view - ///or signaling the view was updatedto avoid viscious cylcing. - void setSelectedValues (const QStringList &values, - bool updateView = true, - bool signalUpdate = true) const; - - void setSelectedValue (const QString &value, - bool updateView = true, - bool signalUpdate = true); - - - ///Returns the value of the data model at the specified row - QString value (int row) const; - - QString viewKey() const { return mViewKey; } - - protected: - - /// Returns the model which provides data for the selection model - QAbstractItemModel *dataModel() { return mDataModel; } - - ///Accessor function for subclasses - bool isMultiValue() { return mIsMultiValue; } - - ///Returns the view selection model - QItemSelectionModel *selectionModel() { return mSelectionModel;} - - ///Global callback for basic view initialization - void showEvent ( QShowEvent * event ); - - ///Virtual for updating a specific View subclass - ///bool indicates whether viewUpdated() signal is emitted - virtual void updateView (bool signalUpdate = true) const; - - ///Returns the pixel width corresponding to the specified number of - ///characters. - int widgetWidth(int characterCount) const; - - private: - - ///Constructs the view layout - void buildView(); - - ///Constructs the data and selection models - void buildModel (const CSMSettings::Setting *setting); - - ///In cases where the view has a pre-defined list of possible values, - ///a QStringListModel is created using those values. - ///View changes operate on the selection model only. - void buildFixedValueModel (const QStringList &definitions); - - ///In cases where the view does not have a pre-defined list of possible - ///values, a QStandardItemModel is created, containing the actual - ///setting definitions. View changes first update the data in the - ///model to match the data in the view. The selection model always - ///selects all values. - void buildUpdatableValueModel (const QStringList &definitions); - - ///Refreshes the view - void refresh() const; - - ///Convenince function for selection model's select() method. Also - ///clears out the model beforehand to ensure complete selection. - void select (const QItemSelection &selection) const; - - ///Compares two string lists "loosely", ensuring that all values in - ///one list are contained entirely in the other, and that neither list - ///has more values than the other. List order is not considered. - bool stringListsMatch (const QStringList &list1, - const QStringList &list2) const; - - ///Converts a string list to a list of QStandardItem pointers. - QList toStandardItemList(const QStringList &) const; - - signals: - - ///Signals that the view has been changed. - void viewUpdated(const QString &, const QStringList &) const; - - }; - - class IViewFactory - { - public: - - ///Creation interface for view factories - virtual View *createView (CSMSettings::Setting *setting, - Page *parent) = 0; - }; -} -#endif // CSVSETTINGS_VIEW_HPP diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 0aec13bcfd..12d5453391 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -4,7 +4,6 @@ #include #include -#include "../../model/settings/usersettings.hpp" #include "../../model/world/columns.hpp" CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, From d6bd2cb1f054a19de4a23f847e30847e5a5ad3d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 14:51:25 +0100 Subject: [PATCH 1708/1812] changed name of openmw-cs user settings file --- CMakeLists.txt | 10 +++++----- apps/opencs/model/prefs/state.cpp | 4 ++-- files/{opencs.ini => openmw-cs.cfg} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename files/{opencs.ini => openmw-cs.cfg} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index db8bcc4f75..fbae0e405f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,8 +347,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini - "${OpenMW_BINARY_DIR}/opencs.ini") +configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg + "${OpenMW_BINARY_DIR}/openmw-cs.cfg") configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) @@ -448,7 +448,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources @@ -481,7 +481,7 @@ if(WIN32) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".") @@ -746,7 +746,7 @@ if (APPLE) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 738a509677..8b827d0a2b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -23,7 +23,7 @@ void CSMPrefs::State::load() else if (boost::filesystem::exists (global)) mSettings.loadDefault (global.string()); else - throw std::runtime_error ("No default settings file found! Make sure the file \"opencs.ini\" was properly installed."); + throw std::runtime_error ("No default settings file found! Make sure the file \"openmw-cs.cfg\" was properly installed."); // user settings file boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; @@ -329,7 +329,7 @@ void CSMPrefs::State::setDefault (const std::string& key, const std::string& def } CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) -: mConfigFile ("opencs.ini"), mConfigurationManager (configurationManager), +: mConfigFile ("openmw-cs.cfg"), mConfigurationManager (configurationManager), mCurrentCategory (mCategories.end()) { if (sThis) diff --git a/files/opencs.ini b/files/openmw-cs.cfg similarity index 100% rename from files/opencs.ini rename to files/openmw-cs.cfg From be19da189abfff78acc85fb9551cbf9a573fad38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Dec 2015 14:56:29 +0100 Subject: [PATCH 1709/1812] fixed user settings not being saved when last document window is closed while user settings window is still open --- apps/opencs/view/prefs/dialogue.cpp | 6 ++++++ apps/opencs/view/prefs/dialogue.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 97a36306ff..f040926530 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -71,6 +71,12 @@ CSVPrefs::Dialogue::Dialogue() buildContentArea (main); } +CSVPrefs::Dialogue::~Dialogue() +{ + if (isVisible()) + CSMPrefs::State::get().save(); +} + void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event) { QMainWindow::closeEvent (event); diff --git a/apps/opencs/view/prefs/dialogue.hpp b/apps/opencs/view/prefs/dialogue.hpp index 3965800db3..fc66892c8b 100644 --- a/apps/opencs/view/prefs/dialogue.hpp +++ b/apps/opencs/view/prefs/dialogue.hpp @@ -31,6 +31,8 @@ namespace CSVPrefs Dialogue(); + virtual ~Dialogue(); + protected: void closeEvent (QCloseEvent *event); From 6a749e77f291174eddc7783bf910760358ff8eee Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 15:12:48 +0100 Subject: [PATCH 1710/1812] Fix crash when running out of sound sources --- apps/openmw/mwsound/soundmanagerimp.cpp | 38 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d1a90759b1..220c6e8857 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -410,10 +410,17 @@ namespace MWSound { MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - SoundLoudnessPair &old = mActiveSaySounds[ptr]; - if(old.first.get()) mOutput->finishStream(old.first); - old = std::make_pair(playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())), - loudness); + + SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr); + if (oldIt != mActiveSaySounds.end()) + { + mOutput->finishStream(oldIt->second.first); + mActiveSaySounds.erase(oldIt); + } + + MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); + + mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness))); } } catch(std::exception &e) @@ -452,9 +459,15 @@ namespace MWSound mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); else { - SoundLoudnessPair &old = mActiveSaySounds[MWWorld::Ptr()]; - if(old.first.get()) mOutput->finishStream(old.first); - old = std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness); + SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::Ptr()); + if (oldIt != mActiveSaySounds.end()) + { + mOutput->finishStream(oldIt->second.first); + mActiveSaySounds.erase(oldIt); + } + + mActiveSaySounds.insert(std::make_pair(MWWorld::Ptr(), + std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness))); } } catch(std::exception &e) @@ -908,8 +921,13 @@ namespace MWSound MWBase::SoundStreamPtr sound; MWWorld::Ptr ptr = penditer->first; - SoundLoudnessPair &old = mActiveSaySounds[ptr]; - if(old.first.get()) mOutput->finishStream(old.first); + SaySoundMap::iterator old = mActiveSaySounds.find(ptr); + if (old != mActiveSaySounds.end()) + { + mOutput->finishStream(old->second.first); + mActiveSaySounds.erase(old); + } + if(ptr == MWWorld::Ptr()) sound = playVoice(decoder, osg::Vec3f(), true); else @@ -918,7 +936,7 @@ namespace MWSound const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); } - old = std::make_pair(sound, loudness); + mActiveSaySounds.insert(std::make_pair(ptr, std::make_pair(sound, loudness))); } catch(std::exception &e) { std::cerr<< "Sound Error: "< Date: Tue, 15 Dec 2015 19:32:42 +0100 Subject: [PATCH 1711/1812] CSMPrefs: fix deadlock in toColor() --- apps/opencs/model/prefs/setting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/setting.cpp b/apps/opencs/model/prefs/setting.cpp index 89924ae29d..75b58322d9 100644 --- a/apps/opencs/model/prefs/setting.cpp +++ b/apps/opencs/model/prefs/setting.cpp @@ -71,7 +71,7 @@ bool CSMPrefs::Setting::isTrue() const QColor CSMPrefs::Setting::toColor() const { - QMutexLocker lock (mMutex); + // toString() handles lock return QColor (QString::fromUtf8 (toString().c_str())); } From 78a733a12c45b91233bf2dc5f0c120d2414dccfc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:13:41 +0100 Subject: [PATCH 1712/1812] Fix initialization of InputWrapper::mWindowHasFocus --- components/sdlutil/sdlinputwrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 200d19bd8c..647a65005c 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -33,6 +33,10 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mMouseInWindow(true) { _setupOISKeys(); + + Uint32 flags = SDL_GetWindowFlags(mSDLWindow); + mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS); + mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS); } InputWrapper::~InputWrapper() From 4af376133b9b825960a5cb0fb7cdd0a9c14087c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:41:00 +0100 Subject: [PATCH 1713/1812] Don't tick effects when duration is zero --- apps/openmw/mwmechanics/actors.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 185364fae7..58fedf2fd9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -486,14 +486,17 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + if (duration > 0) { - // tickable effects (i.e. effects having a lasting impact after expiry) - effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + // tickable effects (i.e. effects having a lasting impact after expiry) + effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); - // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities - CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + } } // attributes From 375caf037d48c1b401547cee5aa9dee972dd3600 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:46:05 +0100 Subject: [PATCH 1714/1812] Don't applyInstantEffect when magnitude is zero --- apps/openmw/mwmechanics/actors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 58fedf2fd9..ed6ace57d5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -494,8 +494,11 @@ namespace MWMechanics effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); // instant effects are already applied on spell impact in spellcasting.cpp, but may also come from permanent abilities - CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + if (it->second.getMagnitude() > 0) + { + CastSpell cast(ptr, ptr); + cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + } } } From ccbba5e9266488ed161c9b8a57121c4bb3537d26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:52:23 +0100 Subject: [PATCH 1715/1812] LoadingScreen: remove indicateProgress, not used --- apps/openmw/mwgui/loadingscreen.cpp | 11 ----------- apps/openmw/mwgui/loadingscreen.hpp | 3 --- components/loadinglistener/loadinglistener.hpp | 3 --- 3 files changed, 17 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 321d5e6645..56b4e75d04 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -224,17 +224,6 @@ namespace MWGui draw(); } - void LoadingScreen::indicateProgress() - { - float time = (static_cast(mTimer.time_m()) % 2001) / 1000.f; - if (time > 1) - time = (time-2)*-1; - - mProgressBar->setTrackSize(50); - mProgressBar->setScrollPosition(static_cast(time * (mProgressBar->getScrollRange() - 1))); - draw(); - } - bool LoadingScreen::needToDrawLoadingScreen() { if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index f0f3542233..d7a822aced 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -35,9 +35,6 @@ namespace MWGui virtual void setLabel (const std::string& label); - /// Indicate that some progress has been made, without specifying how much - virtual void indicateProgress (); - virtual void loadingOn(); virtual void loadingOff(); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 558111b342..e9a8cd3c7e 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -12,9 +12,6 @@ namespace Loading virtual void loadingOn() {} virtual void loadingOff() {} - /// Indicate that some progress has been made, without specifying how much - virtual void indicateProgress () {} - virtual void setProgressRange (size_t range) {} virtual void setProgress (size_t value) {} virtual void increaseProgress (size_t increase = 1) {} From 152f1d625d3b55058de5dd0c8582325083247698 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 20:54:21 +0100 Subject: [PATCH 1716/1812] LoadingScreen: remove unused declarations --- apps/openmw/mwgui/loadingscreen.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index d7a822aced..92a3d9355e 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -44,9 +44,6 @@ namespace MWGui virtual void setVisible(bool visible); - void setLoadingProgress (const std::string& stage, int depth, int current, int total); - void loadingDone(); - private: void findSplashScreens(); bool needToDrawLoadingScreen(); From 625644e917ceadc7d61238089f1c849cf6636cbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:03:56 +0100 Subject: [PATCH 1717/1812] LoadingScreen: documentation updates --- apps/openmw/mwgui/loadingscreen.hpp | 3 +-- components/loadinglistener/loadinglistener.hpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 92a3d9355e..ce9f0f6dc2 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -33,11 +33,10 @@ namespace MWGui LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer); virtual ~LoadingScreen(); + /// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details virtual void setLabel (const std::string& label); - virtual void loadingOn(); virtual void loadingOff(); - virtual void setProgressRange (size_t range); virtual void setProgress (size_t value); virtual void increaseProgress (size_t increase=1); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index e9a8cd3c7e..04e50dd28c 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -1,23 +1,32 @@ #ifndef COMPONENTS_LOADINGLISTENER_H #define COMPONENTS_LOADINGLISTENER_H +#include + namespace Loading { class Listener { public: + /// Set a text label to show on the loading screen. virtual void setLabel (const std::string& label) {} - // Use ScopedLoad instead of using these directly + /// Start a loading sequence. Must call loadingOff() when done. + /// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically. + /// @note It is best to use the ScopedLoad object instead of using loadingOn()/loadingOff() directly, + /// so that the loading is exception safe. virtual void loadingOn() {} virtual void loadingOff() {} + /// Set the total range of progress (e.g. the number of objects to load). virtual void setProgressRange (size_t range) {} + /// Set current progress. Valid range is [0, progressRange) virtual void setProgress (size_t value) {} + /// Increase current progress, default by 1. virtual void increaseProgress (size_t increase = 1) {} }; - // Used for stopping a loading sequence when the object goes out of scope + /// @brief Used for stopping a loading sequence when the object goes out of scope struct ScopedLoad { ScopedLoad(Listener* l) : mListener(l) { mListener->loadingOn(); } From 67883feaae6ef15c3e537ebd0e4fee5bff6231e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:05:35 +0100 Subject: [PATCH 1718/1812] LoadingScreen: ensure values are within progress range --- apps/openmw/mwgui/loadingscreen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 56b4e75d04..e82d78bfed 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -209,6 +209,7 @@ namespace MWGui // skip expensive update if there isn't enough visible progress if (value - mProgress < mProgressBar->getScrollRange()/200.f) return; + value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); @@ -219,6 +220,7 @@ namespace MWGui { mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; + value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); From d5a2586f38029a7848bb55e3a44d365c5666de41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 Dec 2015 21:14:25 +0100 Subject: [PATCH 1719/1812] LoadingScreen: add support for important labels Used in saveGame so the player can be sure whether or not the game was saved. Fixes #3074 --- apps/openmw/mwgui/loadingscreen.cpp | 18 +++++++++++++++++- apps/openmw/mwgui/loadingscreen.hpp | 4 +++- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/loadinglistener/loadinglistener.hpp | 7 ++++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e82d78bfed..e32140cb35 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -36,6 +36,7 @@ namespace MWGui , mLastWallpaperChangeTime(0.0) , mLastRenderTime(0.0) , mLoadingOnTime(0.0) + , mImportantLabel(false) , mProgress(0) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); @@ -82,8 +83,10 @@ namespace MWGui std::cerr << "No splash screens found!" << std::endl; } - void LoadingScreen::setLabel(const std::string &label) + void LoadingScreen::setLabel(const std::string &label, bool important) { + mImportantLabel = important; + mLoadingText->setCaptionWithReplacing(label); int padding = mLoadingBox->getWidth() - mLoadingText->getWidth(); MyGUI::IntSize size(mLoadingText->getTextSize().width+padding, mLoadingBox->getHeight()); @@ -176,6 +179,19 @@ namespace MWGui void LoadingScreen::loadingOff() { + if (mLastRenderTime < mLoadingOnTime) + { + // the loading was so fast that we didn't show loading screen at all + // we may still want to show the label if the caller requested it + if (mImportantLabel) + { + MWBase::Environment::get().getWindowManager()->messageBox(mLoadingText->getCaption()); + mImportantLabel = false; + } + } + else + mImportantLabel = false; // label was already shown on loading screen + //std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl; setVisible(false); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index ce9f0f6dc2..a7f7d3619c 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -34,7 +34,7 @@ namespace MWGui virtual ~LoadingScreen(); /// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details - virtual void setLabel (const std::string& label); + virtual void setLabel (const std::string& label, bool important); virtual void loadingOn(); virtual void loadingOff(); virtual void setProgressRange (size_t range); @@ -57,6 +57,8 @@ namespace MWGui osg::Timer mTimer; double mLoadingOnTime; + bool mImportantLabel; + size_t mProgress; MyGUI::Widget* mLoadingBox; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index b5426bc77b..9931cf9672 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -242,7 +242,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); // Using only Cells for progress information, since they typically have the largest records by far listener.setProgressRange(MWBase::Environment::get().getWorld()->countSavedGameCells()); - listener.setLabel("#{sNotifyMessage4}"); + listener.setLabel("#{sNotifyMessage4}", true); Loading::ScopedLoad load(&listener); diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 04e50dd28c..1d48cce0b9 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -9,7 +9,12 @@ namespace Loading { public: /// Set a text label to show on the loading screen. - virtual void setLabel (const std::string& label) {} + /// @param label The label + /// @param important Is the label considered important to show? + /// @note "non-important" labels may not show on screen if the loading process went so fast + /// that the implementation decided not to show a loading screen at all. "important" labels + /// will show in a separate message-box if the loading screen was not shown. + virtual void setLabel (const std::string& label, bool important=false) {} /// Start a loading sequence. Must call loadingOff() when done. /// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically. From 8222c78cf2ac202970122832bc5fa4da07db8a20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Dec 2015 01:30:04 +0100 Subject: [PATCH 1720/1812] Do not filter creature dialogue by NPC-only conditions (Fixes #3086) --- apps/openmw/mwdialogue/filter.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d41820b71c..084941b460 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -41,7 +41,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mRace.empty()) { if (isCreature) - return false; + return true; MWWorld::LiveCellRef *cellRef = mActor.get(); @@ -53,7 +53,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mClass.empty()) { if (isCreature) - return false; + return true; MWWorld::LiveCellRef *cellRef = mActor.get(); @@ -65,7 +65,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (!info.mFaction.empty()) { if (isCreature) - return false; + return true; if (!Misc::StringUtils::ciEqual(mActor.getClass().getPrimaryFaction(mActor), info.mFaction)) return false; @@ -77,7 +77,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const else if (info.mData.mRank != -1) { if (isCreature) - return false; + return true; // Rank requirement, but no faction given. Use the actor's faction, if there is one. // check rank @@ -156,10 +156,8 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) // If the actor is a creature, we do not test the conditions applicable - // only to NPCs. Such conditions can never be satisfied, apart - // inverted ones (NotClass, NotRace, NotFaction return true - // because creatures are not of any race, class or faction). - return select.getType() == SelectWrapper::Type_Inverted; + // only to NPCs. + return true; switch (select.getType()) { From 31c33247054cfacb65e0904feccfe291f1c872a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:04:36 +0100 Subject: [PATCH 1721/1812] Don't assume the emitter node is a Group (Fixes #3082) This would be a correct assumption by default, but is no longer true when the NifLoader::optimize() function optimizes the graph. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- components/nifosg/nifloader.cpp | 2 +- components/nifosg/particle.cpp | 12 ++++++++---- components/nifosg/particle.hpp | 7 ++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index eebfddaab3..7b4b936782 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -580,7 +580,7 @@ namespace MWPhysics int recIndex = it->first; int shapeIndex = it->second; - NifOsg::FindRecIndexVisitor visitor(recIndex); + NifOsg::FindGroupByRecIndex visitor(recIndex); mPtr.getRefData().getBaseNode()->accept(visitor); if (!visitor.mFound) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 0489e07e62..9a017a4975 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -887,7 +887,7 @@ namespace NifOsg // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - FindRecIndexVisitor find (partctrl->emitter->recIndex); + FindGroupByRecIndex find (partctrl->emitter->recIndex); rootNode->accept(find); if (!find.mFound) { diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index e3162bcd95..5003397222 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -276,7 +276,7 @@ void Emitter::emitParticles(double dt) int randomRecIndex = mTargets[(std::rand() / (static_cast(RAND_MAX)+1.0)) * mTargets.size()]; // we could use a map here for faster lookup - FindRecIndexVisitor visitor(randomRecIndex); + FindGroupByRecIndex visitor(randomRecIndex); getParent(0)->accept(visitor); if (!visitor.mFound) @@ -306,21 +306,25 @@ void Emitter::emitParticles(double dt) } } -FindRecIndexVisitor::FindRecIndexVisitor(int recIndex) +FindGroupByRecIndex::FindGroupByRecIndex(int recIndex) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mFound(NULL) , mRecIndex(recIndex) { } -void FindRecIndexVisitor::apply(osg::Node &searchNode) +void FindGroupByRecIndex::apply(osg::Node &searchNode) { if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) { NodeUserData* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); if (holder && holder->mIndex == mRecIndex) { - mFound = static_cast(&searchNode); + osg::Group* group = searchNode.asGroup(); + if (!group) + group = searchNode.getParent(0); + + mFound = group; mFoundPath = getNodePath(); return; } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index d86408254b..a1ed3f3d0f 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -172,11 +172,12 @@ namespace NifOsg osg::Vec3f mCachedWorldDirection; }; - // NodeVisitor to find a child node with the given record index, stored in the node's user data container. - class FindRecIndexVisitor : public osg::NodeVisitor + // NodeVisitor to find a Group node with the given record index, stored in the node's user data container. + // Alternatively, returns the node's parent Group if that node is not a Group (i.e. a leaf node). + class FindGroupByRecIndex : public osg::NodeVisitor { public: - FindRecIndexVisitor(int recIndex); + FindGroupByRecIndex(int recIndex); virtual void apply(osg::Node &searchNode); From 0731595c2bce8cbbf0f425f87e9697c6e436c6e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:38:38 +0100 Subject: [PATCH 1722/1812] Wrap a Texture2D in a ref_ptr --- components/nifosg/nifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9a017a4975..98512ca5c2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1364,7 +1364,7 @@ namespace NifOsg int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; - osg::Texture2D* texture2d = textureManager->getTexture2D(filename, + osg::ref_ptr texture2d = textureManager->getTexture2D(filename, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); From 0a723ab075ab79cff041d6fed5fa0aeaa9687630 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:48:11 +0100 Subject: [PATCH 1723/1812] Animation: do not assume the object root is a Group --- apps/openmw/mwrender/animation.cpp | 33 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c285ba434d..114c1a5db9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -975,20 +975,27 @@ namespace MWRender mAccumCtrl = NULL; if (!forceskeleton) - mObjectRoot = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + { + osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model, mInsert); + mObjectRoot = created->asGroup(); + if (!mObjectRoot) + { + mObjectRoot = new osg::Group; + mObjectRoot->addChild(created); + } + } else { - osg::ref_ptr newObjectRoot = mResourceSystem->getSceneManager()->createInstance(model); - mSkeleton = dynamic_cast(newObjectRoot.get()); - if (!mSkeleton) + osg::ref_ptr created = mResourceSystem->getSceneManager()->createInstance(model); + osg::ref_ptr skel = dynamic_cast(created.get()); + if (!skel) { - osg::ref_ptr skel = new SceneUtil::Skeleton; - mSkeleton = skel.get(); - skel->addChild(newObjectRoot); - newObjectRoot = skel; + skel = new SceneUtil::Skeleton; + skel->addChild(created); } - mInsert->addChild(newObjectRoot); - mObjectRoot = newObjectRoot; + mSkeleton = skel.get(); + mObjectRoot = skel; + mInsert->addChild(mObjectRoot); } if (previousStateset) @@ -1017,17 +1024,17 @@ namespace MWRender osg::Group* Animation::getObjectRoot() { - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); } osg::Group* Animation::getOrCreateObjectRoot() { if (mObjectRoot) - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); mObjectRoot = new osg::Group; mInsert->addChild(mObjectRoot); - return static_cast(mObjectRoot.get()); + return mObjectRoot.get(); } void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 04df10a380..213e33f673 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -208,7 +208,7 @@ protected: osg::ref_ptr mInsert; - osg::ref_ptr mObjectRoot; + osg::ref_ptr mObjectRoot; SceneUtil::Skeleton* mSkeleton; // The node expected to accumulate movement during movement animations. From fce43854bc7e8e1003a42d0568561ee1f5c74de3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 03:49:18 +0100 Subject: [PATCH 1724/1812] Fix last commit --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 114c1a5db9..85eefb3299 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -980,8 +980,10 @@ namespace MWRender mObjectRoot = created->asGroup(); if (!mObjectRoot) { + mInsert->removeChild(created); mObjectRoot = new osg::Group; mObjectRoot->addChild(created); + mInsert->addChild(mObjectRoot); } } else From 723c392a73d918f0de7d0a5d455aa76df6eb459f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 04:05:39 +0100 Subject: [PATCH 1725/1812] NifLoader: fall back to the first UV set when encountering invalid UV set references --- components/nifosg/nifloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 98512ca5c2..5c28bbc7e6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -963,7 +963,9 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; + std::cerr << "Warning: out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; + if (data->uvlist.size()) + geometry->setTexCoordArray(textureStage, data->uvlist[0]); continue; } From 6b626c29545a83ffd21b5b3b1609655792dd8265 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Dec 2015 13:06:37 +0100 Subject: [PATCH 1726/1812] spelling fixes --- apps/opencs/model/world/tablemimedata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index 101bbf9ba2..1268a7389d 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -179,7 +179,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::Univers } } - throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the sought type"); } CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnBase::Display type) const @@ -201,7 +201,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnB } } - throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the sought type"); } bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) const From d6bcb7906de20ca78869de3c96252ecefafb33b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 16:10:55 +0100 Subject: [PATCH 1727/1812] Fix crash in a warning message --- apps/openmw/mwworld/cellstore.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 164ce55331..f8d53bbd92 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -810,19 +810,21 @@ namespace MWWorld if (!visitor.mFound) { - std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl; + std::cerr << "Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)" << std::endl; continue; } + MWWorld::LiveCellRefBase* movedRef = visitor.mFound; + CellStore* otherCell = callback->getCellStore(movedTo); if (otherCell == NULL) { - std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() + std::cerr << "Dropping moved ref tag for " << movedRef->mRef.getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl; // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. // Restore original coordinates: - visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition()); + movedRef->mData.setPosition(movedRef->mRef.getPosition()); continue; } @@ -833,7 +835,7 @@ namespace MWWorld continue; } - moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell); + moveTo(MWWorld::Ptr(movedRef, this), otherCell); } updateMergedRefs(); From 689dea4cb3ab2bf34e31a437cbb7452ade929956 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Dec 2015 19:33:39 +0100 Subject: [PATCH 1728/1812] Add instant spell effects to the actor's magic effect list Via http://forum.openmw.org/viewtopic.php?f=2&t=3212&start=20#p36208 --- apps/openmw/mwmechanics/actors.cpp | 7 ++- apps/openmw/mwmechanics/spellcasting.cpp | 74 +++++++++++++----------- apps/openmw/mwworld/inventorystore.cpp | 5 -- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed6ace57d5..ee114dff22 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -497,7 +497,12 @@ namespace MWMechanics if (it->second.getMagnitude() > 0) { CastSpell cast(ptr, ptr); - cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude()); + if (cast.applyInstantEffect(ptr, ptr, it->first, it->second.getMagnitude())) + { + creatureStats.getActiveSpells().purgeEffect(it->first.mId); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first.mId); + } } } } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a2d32b3245..ab8784beb1 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -452,42 +452,18 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); - if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) + if (!target.getClass().isActor()) { - ActiveSpells::ActiveEffect effect; - effect.mEffectId = effectIt->mEffectID; - effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = static_cast(effectIt->mDuration); - effect.mMagnitude = magnitude; - - targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); - - appliedLastingEffects.push_back(effect); - - // For absorb effects, also apply the effect to the caster - but with a negative - // magnitude, since we're transfering stats from the target to the caster - if (!caster.isEmpty() && caster.getClass().isActor()) - { - for (int i=0; i<5; ++i) - { - if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) - { - std::vector effects; - ActiveSpells::ActiveEffect effect_ = effect; - effect_.mMagnitude *= -1; - effects.push_back(effect_); - // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, - effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); - } - } - } + // non-actor objects have no list of active magic effects, so have to apply instantly + if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) + continue; } - else + else // target.getClass().isActor() == true { - if (hasDuration && target.getClass().isActor()) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (hasDuration && effectIt->mDuration == 0) { + // duration 0 means apply full magnitude instantly bool wasDead = target.getClass().getCreatureStats(target).isDead(); effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude); bool isDead = target.getClass().getCreatureStats(target).isDead(); @@ -495,8 +471,38 @@ namespace MWMechanics if (!wasDead && isDead) MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); } - else if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) - continue; + else + { + // add to list of active effects, to apply in next frame + ActiveSpells::ActiveEffect effect; + effect.mEffectId = effectIt->mEffectID; + effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; + effect.mDuration = static_cast(effectIt->mDuration); + effect.mMagnitude = magnitude; + + targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); + + appliedLastingEffects.push_back(effect); + + // For absorb effects, also apply the effect to the caster - but with a negative + // magnitude, since we're transfering stats from the target to the caster + if (!caster.isEmpty() && caster.getClass().isActor()) + { + for (int i=0; i<5; ++i) + { + if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) + { + std::vector effects; + ActiveSpells::ActiveEffect effect_ = effect; + effect_.mMagnitude *= -1; + effects.push_back(effect_); + // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, + effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + } + } + } + } } // Re-casting a summon effect will remove the creature from previous castings of that effect. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index ebba4ae30d..da591487e6 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -410,11 +410,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // the items should appear as if they'd always been equipped. mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip, !mFirstAutoEquip && effectIt == enchantment.mEffects.mList.begin()); - - // Apply instant effects - MWMechanics::CastSpell cast(actor, actor); - if (magnitude) - cast.applyInstantEffect(actor, actor, effectIt->mEffectID, magnitude); } if (magnitude) From deb7f3caf64f2f3d3ef1b4d80b82d3d4d4ca71f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:15:44 +0100 Subject: [PATCH 1729/1812] Print deletion state in ObjectReferenceInfo --- apps/openmw/mwscript/miscextensions.cpp | 5 +++++ components/compiler/extensions0.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8375cf8aee..9c63511b27 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1051,6 +1051,11 @@ namespace MWScript msg << "RefNum: " << ptr.getCellRef().getRefNum().mIndex << std::endl; } + if (ptr.getRefData().isDeletedByContentFile()) + msg << "[Deleted by content file]" << std::endl; + if (!ptr.getRefData().getCount()) + msg << "[Deleted]" << std::endl; + msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl; if (ptr.isInCell()) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 6e65c31838..8f7650191a 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -310,7 +310,7 @@ namespace Compiler extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); extensions.registerInstruction ("betacomment", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); extensions.registerInstruction ("bc", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); - extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); + extensions.registerInstruction ("ori", "/S", opcodeBetaComment, opcodeBetaCommentExplicit); // 'ori' stands for 'ObjectReferenceInfo' extensions.registerInstruction ("addtolevcreature", "ccl", opcodeAddToLevCreature); extensions.registerInstruction ("removefromlevcreature", "ccl", opcodeRemoveFromLevCreature); extensions.registerInstruction ("addtolevitem", "ccl", opcodeAddToLevItem); From e564c2631494b5f52b673cdbc18672c386b56fb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:17:53 +0100 Subject: [PATCH 1730/1812] Fix deleted objects being accessible in the Cells cache --- apps/openmw/mwworld/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 1094479599..11b76df4e1 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -173,7 +173,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, Ptr ptr = cell.search (name); - if (!ptr.isEmpty()) + if (!ptr.isEmpty() && ptr.getRefData().getCount()) return ptr; if (searchInContainers) From 04b6571d7dd359ee5da25b8a4fe5c17857fefd48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 20:34:50 +0100 Subject: [PATCH 1731/1812] Fix logic for scripting access of deleted objects --- apps/openmw/mwworld/cellreflist.hpp | 11 ----------- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 49197d1671..4d503dcc8d 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -24,17 +24,6 @@ namespace MWWorld /// all methods are known. void load (ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore); - LiveRef *find (const std::string& name) - { - for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (!iter->mData.isDeletedByContentFile() - && (iter->mRef.hasContentFile() || iter->mData.getCount() > 0) - && iter->mRef.getRefId() == name) - return &*iter; - - return 0; - } - LiveRef &insert (const LiveRef &item) { mList.push_back(item); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 11b76df4e1..75d908db83 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -173,7 +173,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, Ptr ptr = cell.search (name); - if (!ptr.isEmpty() && ptr.getRefData().getCount()) + if (!ptr.isEmpty() && MWWorld::CellStore::isAccessible(ptr.getRefData(), ptr.getCellRef())) return ptr; if (searchInContainers) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 5d1685c280..8f37b6681f 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -122,7 +122,7 @@ namespace MWWorld for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (iter->mData.isDeletedByContentFile()) + if (!isAccessible(iter->mData, iter->mRef)) continue; if (!visitor (MWWorld::Ptr(&*iter, this))) return false; @@ -164,6 +164,15 @@ namespace MWWorld public: + /// Should this reference be accessible to the outside world (i.e. to scripts / game logic)? + /// Determined based on the deletion flags. By default, objects deleted by content files are never accessible; + /// objects deleted by setCount(0) are still accessible *if* they came from a content file (needed for vanilla + /// scripting compatibility, and the fact that objects may be "un-deleted" in the original game). + static bool isAccessible(const MWWorld::RefData& refdata, const MWWorld::CellRef& cref) + { + return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0); + } + /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) /// @note throws exception if cellToMoveTo == this @@ -239,7 +248,7 @@ namespace MWWorld for (unsigned int i=0; imData.isDeletedByContentFile()) + if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef)) continue; if (!visitor(MWWorld::Ptr(mMergedRefs[i], this))) @@ -267,7 +276,7 @@ namespace MWWorld LiveCellRefBase* base = &*it; if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end()) continue; - if (base->mData.isDeletedByContentFile()) + if (!isAccessible(base->mData, base->mRef)) continue; if (!visitor(MWWorld::Ptr(base, this))) return false; From 2fe2f53b02a36f2d2aff2d510b63228ac7c29e03 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 22:37:18 +0100 Subject: [PATCH 1732/1812] Set the changed flag in CellStore::search (Fixes #3089) --- apps/openmw/mwworld/cellstore.cpp | 15 ++++++++++----- apps/openmw/mwworld/cellstore.hpp | 6 ++++++ apps/openmw/mwworld/refdata.cpp | 14 ++++++++++---- apps/openmw/mwworld/worldimp.cpp | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f8d53bbd92..2429a83a7d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -347,7 +347,7 @@ namespace MWWorld return std::binary_search (mIds.begin(), mIds.end(), id); /// \todo address const-issues - return const_cast (this)->search (id).isEmpty(); + return searchConst (id).isEmpty(); } struct SearchVisitor @@ -367,16 +367,21 @@ namespace MWWorld Ptr CellStore::search (const std::string& id) { - bool oldState = mHasState; - SearchVisitor searchVisitor; searchVisitor.mIdToFind = id; forEach(searchVisitor); - - mHasState = oldState; return searchVisitor.mFound; } + Ptr CellStore::searchConst (const std::string& id) const + { + bool oldState = mHasState; + /// \todo address const-issues + Ptr result = const_cast(this)->search(id); + const_cast(this)->mHasState = oldState; + return result; + } + Ptr CellStore::searchViaActorId (int id) { if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8f37b6681f..7047682fa5 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -212,6 +212,12 @@ namespace MWWorld Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. + /// @note Triggers CellStore hasState flag. + + Ptr searchConst (const std::string& id) const; + ///< Will return an empty Ptr if cell is not loaded. Does not check references in + /// containers. + /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 56abba1657..f20e104e78 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -166,14 +166,20 @@ namespace MWWorld void RefData::enable() { - mChanged = !mEnabled; - mEnabled = true; + if (!mEnabled) + { + mChanged = true; + mEnabled = true; + } } void RefData::disable() { - mChanged = mEnabled; - mEnabled = false; + if (mEnabled) + { + mChanged = true; + mEnabled = false; + } } void RefData::setPosition(const ESM::Position& pos) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c9971c6f06..0969df6caf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2828,7 +2828,7 @@ namespace MWWorld checkedCells.insert( *i ); if ( !next ) continue; - closestMarker = next->search( id ); + closestMarker = next->searchConst( id ); if ( !closestMarker.isEmpty() ) { return closestMarker; From c9d02c67c0664eac8dfbd7d8b92b57641426506f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:33:31 +0100 Subject: [PATCH 1733/1812] Remove unneeded const_cast in TerrainStorage --- apps/openmw/mwrender/terrainstorage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index a98084709c..ed1d8b6779 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -20,7 +20,7 @@ namespace MWRender MWWorld::Store::iterator it = esmStore.get().begin(); for (; it != esmStore.get().end(); ++it) { - ESM::Land* land = const_cast(&*it); // TODO: fix store interface + const ESM::Land* land = &*it; land->loadData(ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX); } } From d4eba794c387521af6919b5ddd83e2027b58f140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:34:52 +0100 Subject: [PATCH 1734/1812] Add ConstPtr --- apps/openmw/mwworld/ptr.cpp | 22 ++++++++++ apps/openmw/mwworld/ptr.hpp | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 4d74c3c581..3f2ef80b65 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -52,3 +52,25 @@ MWWorld::Ptr::operator const void *() { return mRef; } + +// ------------------------------------------------------------------------------- + +const std::string &MWWorld::ConstPtr::getTypeName() const +{ + if(mRef != 0) + return mRef->mClass->getTypeName(); + throw std::runtime_error("Can't get type name from an empty object."); +} + +const MWWorld::LiveCellRefBase *MWWorld::ConstPtr::getBase() const +{ + if (!mRef) + throw std::runtime_error ("Can't access cell ref pointed to by null Ptr"); + + return mRef; +} + +MWWorld::ConstPtr::operator const void *() +{ + return mRef; +} diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index c97d2e6d1e..9d370c4cbe 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -85,6 +85,87 @@ namespace MWWorld ///< Return a 0-pointer, if Ptr is empty; return a non-0-pointer, if Ptr is not empty }; + /// \brief Pointer to a const LiveCellRef + /// @note a Ptr can be implicitely converted to a ConstPtr, but you can not convert a ConstPtr to a Ptr. + class ConstPtr + { + public: + + const MWWorld::LiveCellRefBase *mRef; + const CellStore *mCell; + const ContainerStore *mContainerStore; + + public: + ConstPtr(const MWWorld::LiveCellRefBase *liveCellRef=0, const CellStore *cell=0) + : mRef(liveCellRef), mCell(cell), mContainerStore(0) + { + } + + ConstPtr(const MWWorld::Ptr& ptr) + : mRef(ptr.mRef), mCell(ptr.mCell), mContainerStore(ptr.mContainerStore) + { + } + + bool isEmpty() const + { + return mRef == 0; + } + + const std::string& getTypeName() const; + + const Class& getClass() const + { + if(mRef != 0) + return *(mRef->mClass); + throw std::runtime_error("Cannot get class of an empty object"); + } + + template + const MWWorld::LiveCellRef *get() const + { + const MWWorld::LiveCellRef *ref = dynamic_cast*>(mRef); + if(ref) return ref; + + std::stringstream str; + str<< "Bad LiveCellRef cast to "<mRef; + } + + const RefData& getRefData() const + { + assert(mRef); + return mRef->mData; + } + + const CellStore *getCell() const + { + assert(mCell); + return mCell; + } + + bool isInCell() const + { + return (mContainerStore == 0) && (mCell != 0); + } + + const ContainerStore *getContainerStore() const; + ///< May return a 0-pointer, if reference is not in a container. + + operator const void *(); + ///< Return a 0-pointer, if Ptr is empty; return a non-0-pointer, if Ptr is not empty + }; + inline bool operator== (const Ptr& left, const Ptr& right) { return left.mRef==right.mRef; From 19d87c78f272f4f78b35d1e2e5fd2e515a835b47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Dec 2015 23:59:18 +0100 Subject: [PATCH 1735/1812] Add CellStore::forEachConst --- apps/openmw/mwworld/cellstore.cpp | 18 +++++++++--------- apps/openmw/mwworld/cellstore.hpp | 30 +++++++++++++++++++++++++----- apps/openmw/mwworld/worldimp.cpp | 14 +++++++------- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 2429a83a7d..c4ab9f316f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -350,11 +350,12 @@ namespace MWWorld return searchConst (id).isEmpty(); } + template struct SearchVisitor { - MWWorld::Ptr mFound; + PtrType mFound; std::string mIdToFind; - bool operator()(const MWWorld::Ptr& ptr) + bool operator()(const PtrType& ptr) { if (ptr.getCellRef().getRefId() == mIdToFind) { @@ -367,19 +368,18 @@ namespace MWWorld Ptr CellStore::search (const std::string& id) { - SearchVisitor searchVisitor; + SearchVisitor searchVisitor; searchVisitor.mIdToFind = id; forEach(searchVisitor); return searchVisitor.mFound; } - Ptr CellStore::searchConst (const std::string& id) const + ConstPtr CellStore::searchConst (const std::string& id) const { - bool oldState = mHasState; - /// \todo address const-issues - Ptr result = const_cast(this)->search(id); - const_cast(this)->mHasState = oldState; - return result; + SearchVisitor searchVisitor; + searchVisitor.mIdToFind = id; + forEachConst(searchVisitor); + return searchVisitor.mFound; } Ptr CellStore::searchViaActorId (int id) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 7047682fa5..f2cef1859e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -214,7 +214,7 @@ namespace MWWorld /// containers. /// @note Triggers CellStore hasState flag. - Ptr searchConst (const std::string& id) const; + ConstPtr searchConst (const std::string& id) const; ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! @@ -240,8 +240,9 @@ namespace MWWorld void preload (); ///< Build ID list from content file. - /// Call visitor (ref) for each reference. visitor must return a bool. Returning + /// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning /// false will abort the iteration. + /// \note Prefer using forEachConst when possible. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template @@ -263,6 +264,28 @@ namespace MWWorld return true; } + /// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning + /// false will abort the iteration. + /// \attention This function also lists deleted (count 0) objects! + /// \return Iteration completed? + template + bool forEachConst (Visitor& visitor) const + { + if (mState != State_Loaded) + return false; + + for (unsigned int i=0; imData, mMergedRefs[i]->mRef)) + continue; + + if (!visitor(MWWorld::ConstPtr(mMergedRefs[i], this))) + return false; + } + return true; + } + + /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! @@ -298,9 +321,6 @@ namespace MWWorld return true; } - /// \todo add const version of forEach - - // NOTE: does not account for moved references // Should be phased out when we have const version of forEach inline const CellRefList& getReadOnlyDoors() const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0969df6caf..56fe2fc3dd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2805,7 +2805,7 @@ namespace MWWorld return false; } - MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) + MWWorld::ConstPtr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { if ( ptr.getCell()->isExterior() ) { return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); @@ -2817,7 +2817,7 @@ namespace MWWorld std::set< std::string >checkedCells; std::set< std::string >currentCells; std::set< std::string >nextCells; - MWWorld::Ptr closestMarker; + MWWorld::ConstPtr closestMarker; nextCells.insert( ptr.getCell()->getCell()->mName ); while ( !nextCells.empty() ) { @@ -2861,8 +2861,8 @@ namespace MWWorld return MWWorld::Ptr(); } - MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { - MWWorld::Ptr closestMarker; + MWWorld::ConstPtr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { + MWWorld::ConstPtr closestMarker; float closestDistance = std::numeric_limits::max(); std::vector markers; @@ -2887,7 +2887,7 @@ namespace MWWorld void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { - MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + MWWorld::ConstPtr closestMarker = getClosestMarker( ptr, id ); if ( closestMarker.isEmpty() ) { @@ -3047,13 +3047,13 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + MWWorld::ConstPtr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); if ( prisonMarker.isEmpty() ) { std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; return; } - std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + std::string prisonName = prisonMarker.getCellRef().getDestCell(); if ( prisonName.empty() ) { std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7132132874..7d67395cfd 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -165,8 +165,8 @@ namespace MWWorld float feetToGameUnits(float feet); - MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); - MWWorld::Ptr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); + MWWorld::ConstPtr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::ConstPtr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); public: From eb51e2838f03cf31d40ab25252b4e1a5386805bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:07:13 +0100 Subject: [PATCH 1736/1812] Utilize the mHasCustomData flag in writeAdditionalState --- apps/openmw/mwclass/container.cpp | 8 +++++++- apps/openmw/mwclass/creature.cpp | 2 -- apps/openmw/mwclass/creaturelevlist.cpp | 10 +++++++++- apps/openmw/mwclass/door.cpp | 8 +++++++- apps/openmw/mwclass/npc.cpp | 2 -- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c9f9f3740e..aa5142cbdf 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -299,6 +299,8 @@ namespace MWClass void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; const ESM::ContainerState& state2 = dynamic_cast (state); if (!ptr.getRefData().getCustomData()) @@ -316,7 +318,11 @@ namespace MWClass { ESM::ContainerState& state2 = dynamic_cast (state); - ensureCustomData (ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. writeState (state2.mInventory); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d6270077d6..4954ac54de 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -735,8 +735,6 @@ namespace MWClass return; } - ensureCustomData (ptr); - CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index c015d53d6a..231a4ee37f 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -104,6 +104,9 @@ namespace MWClass void CreatureLevList::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::CreatureLevListState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -117,7 +120,12 @@ namespace MWClass { ESM::CreatureLevListState& state2 = dynamic_cast (state); - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index fffa8d1fd1..cf11dfedbf 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -343,6 +343,8 @@ namespace MWClass void Door::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; ensureCustomData(ptr); DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); @@ -352,7 +354,11 @@ namespace MWClass void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 60ab73e04d..08743cb4f0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1187,8 +1187,6 @@ namespace MWClass return; } - ensureCustomData (ptr); - NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); From b48445dea7c061042946f3b07afbeb760dbf0e20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:12:03 +0100 Subject: [PATCH 1737/1812] Accept a ConstPtr in getScript --- apps/openmw/mwclass/activator.cpp | 4 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 5 ++--- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 36 files changed, 53 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 17757cb6b7..8b41eec13c 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -66,9 +66,9 @@ namespace MWClass return ref->mBase->mName; } - std::string Activator::getScript (const MWWorld::Ptr& ptr) const + std::string Activator::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 646bb79bb2..6280587b1e 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 07bf250860..b4d293cb83 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -64,10 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const + std::string Apparatus::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 94e998e488..071bf83bd3 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -31,7 +31,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 631ddd9129..e51ea11e06 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -83,10 +83,9 @@ namespace MWClass return ref->mBase->mData.mHealth; } - std::string Armor::getScript (const MWWorld::Ptr& ptr) const + std::string Armor::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index ec32908783..a7e63d6af3 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9ea9e659b6..1d645931dc 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -78,10 +78,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRead(ptr)); } - std::string Book::getScript (const MWWorld::Ptr& ptr) const + std::string Book::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 8dcae731a2..90cb4d7627 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 7250e1837e..616f9676bb 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -66,10 +66,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Clothing::getScript (const MWWorld::Ptr& ptr) const + std::string Clothing::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index adb3491580..0489f0b314 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index aa5142cbdf..648a232c8e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -209,10 +209,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asContainerCustomData().mContainerStore; } - std::string Container::getScript (const MWWorld::Ptr& ptr) const + std::string Container::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3541937d12..d9c7daa079 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -40,7 +40,7 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 4954ac54de..55bb895b71 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -444,9 +444,9 @@ namespace MWClass return isFlagBitSet(ptr, ESM::Creature::Weapon); } - std::string Creature::getScript (const MWWorld::Ptr& ptr) const + std::string Creature::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 55127eefcf..fc1421d24b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -74,7 +74,7 @@ namespace MWClass virtual bool hasInventoryStore (const MWWorld::Ptr &ptr) const; - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getCapacity (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index cf11dfedbf..5d5e695b8a 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -217,10 +217,9 @@ namespace MWClass return true; } - std::string Door::getScript (const MWWorld::Ptr& ptr) const + std::string Door::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index db5a7f32a3..b06ee12df1 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -49,7 +49,7 @@ namespace MWClass virtual bool canLock(const MWWorld::Ptr &ptr) const; - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr static void registerSelf(); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index db2f2410b6..b7d1cf3d93 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -70,10 +70,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const + std::string Ingredient::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 69dd70743f..00862a2203 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index fe51490775..615f9fac02 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -96,10 +96,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Light::getScript (const MWWorld::Ptr& ptr) const + std::string Light::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 6161f18997..b7ef199b08 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -34,7 +34,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 63f75a845c..3fae74be9d 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -65,10 +65,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const + std::string Lockpick::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 3f2c004f8f..7e7ee78d54 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a14ab33302..e5836bd964 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -78,10 +78,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Miscellaneous::getScript (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 394c9ffc01..e3215a6ad2 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 08743cb4f0..bbcee8d27c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -799,10 +799,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore; } - std::string Npc::getScript (const MWWorld::Ptr& ptr) const + std::string Npc::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index c2d2ca8fa6..aa8b7e78ac 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -80,7 +80,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual float getSpeed (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 20a849019f..9816c3cbc4 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -68,9 +68,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Potion::getScript (const MWWorld::Ptr& ptr) const + std::string Potion::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 091d291953..a38205257f 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 79f423b30d..0e3de75d4b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -64,9 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Probe::getScript (const MWWorld::Ptr& ptr) const + std::string Probe::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index e39e43c270..a6da5ab9d0 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 78ec2adcca..700db167a2 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -64,9 +64,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - std::string Repair::getScript (const MWWorld::Ptr& ptr) const + std::string Repair::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 295b9d4f15..3ec617bd3e 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual int getValue (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 5665bf1c45..cc5d8ed597 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -84,9 +84,9 @@ namespace MWClass return ref->mBase->mData.mHealth; } - std::string Weapon::getScript (const MWWorld::Ptr& ptr) const + std::string Weapon::getScript (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mScript; diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 47c1157a02..88282f5a3c 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -40,7 +40,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual std::string getScript (const MWWorld::Ptr& ptr) const; + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 30fd42527b..e57f8b2990 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -158,7 +158,7 @@ namespace MWWorld return -1; } - std::string Class::getScript (const Ptr& ptr) const + std::string Class::getScript (const ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index b2d3453af6..2bbc450830 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -171,7 +171,7 @@ namespace MWWorld ///< Returns the remaining duration of the object, such as an equippable light /// source. (default implementation: -1, i.e. infinite) - virtual std::string getScript (const Ptr& ptr) const; + virtual std::string getScript (const ConstPtr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string). From ed3486e81692135609c621630a9169ab3da377bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 00:18:06 +0100 Subject: [PATCH 1738/1812] Improve const-correctness in writeAdditionalState --- apps/openmw/mwclass/container.cpp | 4 ++-- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 6 ++---- apps/openmw/mwclass/creaturelevlist.cpp | 4 ++-- apps/openmw/mwclass/creaturelevlist.hpp | 6 ++---- apps/openmw/mwclass/door.cpp | 4 ++-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 4 ++-- apps/openmw/mwworld/containerstore.hpp | 5 ++--- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- apps/openmw/mwworld/livecellref.cpp | 3 +-- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ 19 files changed, 33 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 648a232c8e..79efc253e0 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -313,7 +313,7 @@ namespace MWClass readState (state2.mInventory); } - void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const + void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::ContainerState& state2 = dynamic_cast (state); @@ -323,7 +323,7 @@ namespace MWClass return; } - dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. writeState (state2.mInventory); } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d9c7daa079..0c24ae03dc 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -63,7 +63,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 55bb895b71..9aa9871bbe 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -724,7 +724,7 @@ namespace MWClass customData.mCreatureStats.readState (state2.mCreatureStats); } - void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void Creature::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::CreatureState& state2 = dynamic_cast (state); @@ -735,7 +735,7 @@ namespace MWClass return; } - CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); + const CreatureCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index fc1421d24b..70ffb3ba6b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -117,12 +117,10 @@ namespace MWClass /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. virtual int getBaseGold(const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 231a4ee37f..2e4aef2fae 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -115,7 +115,7 @@ namespace MWClass customData.mSpawn = state2.mSpawn; } - void CreatureLevList::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void CreatureLevList::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::CreatureLevListState& state2 = dynamic_cast (state); @@ -126,7 +126,7 @@ namespace MWClass return; } - CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); + const CreatureLevListCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 177aa72359..7e1b7828a0 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -23,12 +23,10 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5d5e695b8a..7c3176d520 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -351,14 +351,14 @@ namespace MWClass customData.mDoorState = state2.mDoorState; } - void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const + void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { if (!ptr.getRefData().getCustomData()) { state.mHasCustomState = false; return; } - const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); + const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b06ee12df1..c67c96e3eb 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -66,7 +66,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. }; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bbcee8d27c..bac555d1b6 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1175,7 +1175,7 @@ namespace MWClass static_cast (customData.mNpcStats).readState (state2.mCreatureStats); } - void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + void Npc::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const { ESM::NpcState& state2 = dynamic_cast (state); @@ -1186,7 +1186,7 @@ namespace MWClass return; } - NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); + const NpcCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index aa8b7e78ac..48277eb521 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -145,7 +145,7 @@ namespace MWClass const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e57f8b2990..f8d4fbde41 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -397,7 +397,7 @@ namespace MWWorld void Class::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const {} - void Class::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const {} + void Class::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const {} int Class::getBaseGold(const MWWorld::Ptr& ptr) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2bbc450830..38ca7fcc14 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -313,7 +313,7 @@ namespace MWWorld const; ///< Read additional state from \a state into \a ptr. - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b45e7ef833..4b4c515478 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -94,7 +94,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object } template -void MWWorld::ContainerStore::storeStates (CellRefList& collection, +void MWWorld::ContainerStore::storeStates (const CellRefList& collection, ESM::InventoryState& inventory, int& index, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -707,7 +707,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const { state.mItems.clear(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 876821f94d..e103e16a1d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,7 +86,7 @@ namespace MWWorld void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template - void storeStates (CellRefList& collection, + void storeStates (const CellRefList& collection, ESM::InventoryState& inventory, int& index, bool equipable = false) const; @@ -169,8 +169,7 @@ namespace MWWorld Ptr search (const std::string& id); - /// \todo make this method const once const-correct ContainerStoreIterators are available - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index da591487e6..bfc33507ac 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -752,7 +752,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 95c16c115e..2c1be9b038 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -207,7 +207,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index dcd6da431f..0f83cd9c2a 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -54,8 +54,7 @@ void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const { mRef.writeState(state); - /// \todo get rid of this cast once const-correct Ptr are available - Ptr ptr (const_cast (this)); + ConstPtr ptr (this); mData.write (state, mClass->getScript (ptr)); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f20e104e78..6c89f6d6f4 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -205,6 +205,11 @@ namespace MWWorld return mCustomData; } + const CustomData *RefData::getCustomData() const + { + return mCustomData; + } + bool RefData::hasChanged() const { return mChanged; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 5421ea9634..d02e05c987 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -116,6 +116,8 @@ namespace MWWorld CustomData *getCustomData(); ///< May return a 0-pointer. The ownership of the return data object is not transferred. + const CustomData *getCustomData() const; + bool hasChanged() const; ///< Has this RefData changed since it was originally loaded? }; From a3441832472b08c66dffc18ab9224f1da92f42fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:34:42 +0100 Subject: [PATCH 1739/1812] Comment fix --- apps/openmw/mwworld/cellstore.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c4ab9f316f..a6389ee0ce 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -346,7 +346,6 @@ namespace MWWorld if (mState==State_Preloaded) return std::binary_search (mIds.begin(), mIds.end(), id); - /// \todo address const-issues return searchConst (id).isEmpty(); } From 1c8244276d91ba093c343af20350b6145e9a2f0e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:36:34 +0100 Subject: [PATCH 1740/1812] Exception handling improvements (Bug #3090) --- apps/openmw/mwmechanics/summoning.cpp | 47 ++++++++++++++++----------- apps/openmw/mwrender/animation.cpp | 11 ++++++- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 541026ee18..d248b34baf 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -34,7 +34,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, "", ptr.getRefData().getPosition().asVec3()); } - else + else if (creatureActorId != -1) { // We didn't find the creature. It's probably in an inactive cell. // Add to graveyard so we can delete it when the cell becomes active. @@ -132,25 +132,34 @@ namespace MWMechanics if (!creatureID.empty()) { MWWorld::CellStore* store = mActor.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - - MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); - - // Make the summoned creature follow its master and help in fights - AiFollow package(mActor.getCellRef().getRefId()); - summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); - int creatureActorId = summonedCreatureStats.getActorId(); - - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); - if (anim) + int creatureActorId = -1; + try { - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_Start"); - if (fx) - anim->addEffect("meshes\\" + fx->mModel, -1, false); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); + ref.getPtr().getCellRef().setPosition(ipos); + + MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); + + // Make the summoned creature follow its master and help in fights + AiFollow package(mActor.getCellRef().getRefId()); + summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); + creatureActorId = summonedCreatureStats.getActorId(); + + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); + if (anim) + { + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_Start"); + if (fx) + anim->addEffect("meshes\\" + fx->mModel, -1, false); + } + } + catch (std::exception& e) + { + std::cerr << "Failed to spawn summoned creature: " << e.what() << std::endl; + // still insert into creatureMap so we don't try to spawn again every frame, that would spam the warning log } creatureMap.insert(std::make_pair(*it, creatureActorId)); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85eefb3299..68a073731d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -518,7 +518,16 @@ namespace MWRender } if (mTextKeyListener) - mTextKeyListener->handleTextKey(groupname, key, map); + { + try + { + mTextKeyListener->handleTextKey(groupname, key, map); + } + catch (std::exception& e) + { + std::cerr << "Error handling text key " << evt << ": " << e.what() << std::endl; + } + } } void Animation::play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, From b2add6470b19b603d4bdab4143c8494bf1d36fe1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 02:58:38 +0100 Subject: [PATCH 1741/1812] Missing include fix --- apps/openmw/mwmechanics/summoning.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index d248b34baf..636e199074 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -1,5 +1,7 @@ #include "summoning.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" From 37a72d1ea62dd40940bc3bb9bddaced05a848611 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 Dec 2015 12:38:45 +0100 Subject: [PATCH 1742/1812] reject unsuitable drops to WorldspaceWidget earlier --- apps/opencs/view/render/worldspacewidget.cpp | 39 ++++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 46e2bc2e01..2d0ef79eee 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -317,12 +317,38 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { - event->accept(); + const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); + if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped + return; + + if (mime->fromDocument (mDocument)) + { + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + // These drops are handled through the subview object. + event->accept(); + } + } } void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) { - event->accept(); + const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); + if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped + return; + + if (mime->fromDocument (mDocument)) + { + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + // These drops are handled through the subview object. + event->accept(); + } + } } @@ -428,8 +454,13 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) if (mime->fromDocument (mDocument)) { - emit dataDropped(mime->getData()); - } //not handling drops from different documents at the moment + if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) || + mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) || + mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile)) + { + emit dataDropped(mime->getData()); + } + } } void CSVRender::WorldspaceWidget::runRequest (const std::string& profile) From 102397067cecb5655219426eab567837c2448e92 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 Dec 2015 14:04:53 +0100 Subject: [PATCH 1743/1812] added interface for per edit-mode drop handling --- apps/opencs/view/render/editmode.cpp | 6 ++++++ apps/opencs/view/render/editmode.hpp | 13 +++++++++++++ apps/opencs/view/render/worldspacewidget.cpp | 7 ++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index a77ef21a5d..b325e31fb0 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -64,3 +64,9 @@ void CSVRender::EditMode::dragCompleted() {} void CSVRender::EditMode::dragAborted() {} void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {} + +void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {} + +void CSVRender::EditMode::dropEvent (QDropEvent* event) {} + +void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 9a8ac9a3a3..3ba97cf007 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -5,6 +5,10 @@ #include "../widget/modebutton.hpp" +class QDragEnterEvent; +class QDropEvent; +class QDragMoveEvent; + namespace CSVRender { class WorldspaceWidget; @@ -79,6 +83,15 @@ namespace CSVRender /// Default-implementation: ignored virtual void dragWheel (int diff, double speedFactor); + + /// Default-implementation: ignored + virtual void dragEnterEvent (QDragEnterEvent *event); + + /// Default-implementation: ignored + virtual void dropEvent (QDropEvent* event); + + /// Default-implementation: ignored + virtual void dragMoveEvent (QDragMoveEvent *event); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2d0ef79eee..f0d3986414 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -330,6 +330,8 @@ void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) // These drops are handled through the subview object. event->accept(); } + else + dynamic_cast (*mEditMode->getCurrent()).dragEnterEvent (event); } } @@ -348,10 +350,11 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) // These drops are handled through the subview object. event->accept(); } + else + dynamic_cast (*mEditMode->getCurrent()).dragMoveEvent (event); } } - bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting) { if (setting->getParent()->getKey()!="3D Scene Input") @@ -460,6 +463,8 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { emit dataDropped(mime->getData()); } + else + dynamic_cast (*mEditMode->getCurrent()).dropEvent (event); } } From bc50587e71d6330df8436674b90483e795c88d6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 14:33:15 +0100 Subject: [PATCH 1744/1812] Remove comment --- apps/openmw/mwworld/cellstore.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f2cef1859e..27fe9ec036 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -217,7 +217,7 @@ namespace MWWorld ConstPtr searchConst (const std::string& id) const; ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. - /// @note Does not trigger CellStore hasState flag. Do not modify the returned Ptr! + /// @note Does not trigger CellStore hasState flag. Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. From d9bbd83b098ae8d49ce3be156fec027ef530f1cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:27:06 +0100 Subject: [PATCH 1745/1812] Accept a ConstPtr in getToolTipInfo Accept a ConstPtr in functions used by getToolTipInfo --- apps/openmw/mwclass/activator.cpp | 10 ++++---- apps/openmw/mwclass/activator.hpp | 4 ++-- apps/openmw/mwclass/apparatus.cpp | 15 +++++------- apps/openmw/mwclass/apparatus.hpp | 6 ++--- apps/openmw/mwclass/armor.cpp | 32 ++++++++++--------------- apps/openmw/mwclass/armor.hpp | 12 +++++----- apps/openmw/mwclass/book.cpp | 15 +++++------- apps/openmw/mwclass/book.hpp | 6 ++--- apps/openmw/mwclass/clothing.cpp | 20 +++++++--------- apps/openmw/mwclass/clothing.hpp | 8 +++---- apps/openmw/mwclass/container.cpp | 10 ++++---- apps/openmw/mwclass/container.hpp | 4 ++-- apps/openmw/mwclass/creature.cpp | 10 ++++---- apps/openmw/mwclass/creature.hpp | 4 ++-- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.hpp | 2 +- apps/openmw/mwclass/door.cpp | 10 ++++---- apps/openmw/mwclass/door.hpp | 4 ++-- apps/openmw/mwclass/ingredient.cpp | 15 +++++------- apps/openmw/mwclass/ingredient.hpp | 6 ++--- apps/openmw/mwclass/itemlevlist.cpp | 2 +- apps/openmw/mwclass/itemlevlist.hpp | 2 +- apps/openmw/mwclass/light.cpp | 19 +++++++-------- apps/openmw/mwclass/light.hpp | 8 +++---- apps/openmw/mwclass/lockpick.cpp | 20 +++++++--------- apps/openmw/mwclass/lockpick.hpp | 8 +++---- apps/openmw/mwclass/misc.cpp | 22 +++++++---------- apps/openmw/mwclass/misc.hpp | 10 ++++---- apps/openmw/mwclass/npc.cpp | 16 ++++++++----- apps/openmw/mwclass/npc.hpp | 4 ++-- apps/openmw/mwclass/potion.cpp | 15 +++++------- apps/openmw/mwclass/potion.hpp | 6 ++--- apps/openmw/mwclass/probe.cpp | 20 +++++++--------- apps/openmw/mwclass/probe.hpp | 8 +++---- apps/openmw/mwclass/repair.cpp | 20 +++++++--------- apps/openmw/mwclass/repair.hpp | 8 +++---- apps/openmw/mwclass/static.cpp | 2 +- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 25 ++++++++----------- apps/openmw/mwclass/weapon.hpp | 12 +++++----- apps/openmw/mwworld/class.cpp | 14 +++++------ apps/openmw/mwworld/class.hpp | 20 ++++++++-------- apps/openmw/mwworld/customdata.cpp | 7 ++++++ apps/openmw/mwworld/customdata.hpp | 1 + 44 files changed, 212 insertions(+), 254 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 8b41eec13c..1ca1150dfb 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -58,10 +58,9 @@ namespace MWClass return ""; } - std::string Activator::getName (const MWWorld::Ptr& ptr) const + std::string Activator::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -89,10 +88,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 6280587b1e..4e371d8ddf 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -21,14 +21,14 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index b4d293cb83..3caf68aae6 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -50,10 +50,9 @@ namespace MWClass return ""; } - std::string Apparatus::getName (const MWWorld::Ptr& ptr) const + std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -71,10 +70,9 @@ namespace MWClass return ref->mBase->mScript; } - int Apparatus::getValue (const MWWorld::Ptr& ptr) const + int Apparatus::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -112,10 +110,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 071bf83bd3..32b58af07c 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,13 +34,13 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static void registerSelf(); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e51ea11e06..c9369e1ae6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -56,10 +56,9 @@ namespace MWClass return ""; } - std::string Armor::getName (const MWWorld::Ptr& ptr) const + std::string Armor::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -75,10 +74,9 @@ namespace MWClass return true; } - int Armor::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Armor::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mHealth; } @@ -92,8 +90,7 @@ namespace MWClass std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -124,10 +121,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Armor::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::string typeGmst; @@ -169,10 +165,9 @@ namespace MWClass return ESM::Skill::HeavyArmor; } - int Armor::getValue (const MWWorld::Ptr& ptr) const + int Armor::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -222,10 +217,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -289,9 +283,9 @@ namespace MWClass return record->mId; } - int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + int Armor::getEffectiveArmorRating(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &actor) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int armorSkillType = getEquipmentSkill(ptr); int armorSkill = actor.getClass().getSkill(actor, armorSkillType); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index a7e63d6af3..c989fcde0a 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -22,7 +22,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -33,7 +33,7 @@ namespace MWClass virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -43,17 +43,17 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -88,7 +88,7 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. - virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; + virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 1d645931dc..49b53c480c 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -53,10 +53,9 @@ namespace MWClass return ""; } - std::string Book::getName (const MWWorld::Ptr& ptr) const + std::string Book::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -85,10 +84,9 @@ namespace MWClass return ref->mBase->mScript; } - int Book::getValue (const MWWorld::Ptr& ptr) const + int Book::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -126,10 +124,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 90cb4d7627..a4f2302199 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,10 +34,10 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 616f9676bb..faa776e3ab 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -52,10 +52,9 @@ namespace MWClass return ""; } - std::string Clothing::getName (const MWWorld::Ptr& ptr) const + std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -113,10 +112,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Clothing::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType==ESM::Clothing::Shoes) return ESM::Skill::Unarmored; @@ -124,10 +122,9 @@ namespace MWClass return -1; } - int Clothing::getValue (const MWWorld::Ptr& ptr) const + int Clothing::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -179,10 +176,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 0489f0b314..30d16f0d7e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -35,17 +35,17 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 79efc253e0..9c39c9df15 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -193,10 +193,9 @@ namespace MWClass } } - std::string Container::getName (const MWWorld::Ptr& ptr) const + std::string Container::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -231,10 +230,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 0c24ae03dc..13593b1c07 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -34,7 +34,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9aa9871bbe..fceae4060c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -188,10 +188,9 @@ namespace MWClass return ""; } - std::string Creature::getName (const MWWorld::Ptr& ptr) const + std::string Creature::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -521,10 +520,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 70ffb3ba6b..efb4715af4 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,11 +47,11 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 2e4aef2fae..9bd5f95372 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -34,7 +34,7 @@ namespace MWClass return ptr.get()->mBase->mId; } - std::string CreatureLevList::getName (const MWWorld::Ptr& ptr) const + std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7e1b7828a0..4ada3cd863 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -14,7 +14,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 7c3176d520..47116cd7b5 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -91,10 +91,9 @@ namespace MWClass return ""; } - std::string Door::getName (const MWWorld::Ptr& ptr) const + std::string Door::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -239,10 +238,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index c67c96e3eb..384f38fa9a 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -24,7 +24,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -35,7 +35,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static std::string getDestination (const MWWorld::LiveCellRef& door); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index b7d1cf3d93..95cf00d948 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -56,10 +56,9 @@ namespace MWClass return ""; } - std::string Ingredient::getName (const MWWorld::Ptr& ptr) const + std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -77,10 +76,9 @@ namespace MWClass return ref->mBase->mScript; } - int Ingredient::getValue (const MWWorld::Ptr& ptr) const + int Ingredient::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -128,10 +126,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 00862a2203..a6740a3998 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& 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) diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index a70f311159..7690169c6f 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -9,7 +9,7 @@ namespace MWClass return ptr.get()->mBase->mId; } - std::string ItemLevList::getName (const MWWorld::Ptr& ptr) const + std::string ItemLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index 2b507135fd..8a95b9adbc 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -12,7 +12,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 615f9fac02..eb1c3bcc20 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -72,10 +72,9 @@ namespace MWClass return ""; } - std::string Light::getName (const MWWorld::Ptr& ptr) const + std::string Light::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mModel.empty()) return ""; @@ -116,10 +115,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Light::getValue (const MWWorld::Ptr& ptr) const + int Light::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -158,10 +156,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -201,9 +198,9 @@ namespace MWClass ptr.getCellRef().setChargeFloat(duration); } - float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const + float Light::getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ptr.getCellRef().getCharge() == -1) return static_cast(ref->mBase->mData.mTime); else diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index b7ef199b08..5e04fdb0ba 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -20,14 +20,14 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -62,7 +62,7 @@ namespace MWClass virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object. - virtual float getRemainingUsageTime (const MWWorld::Ptr& ptr) const; + virtual float getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const; ///< Returns the remaining duration of the object. virtual std::string getModel(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 3fae74be9d..858a01992c 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -51,10 +51,9 @@ namespace MWClass return ""; } - std::string Lockpick::getName (const MWWorld::Ptr& ptr) const + std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -81,10 +80,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Lockpick::getValue (const MWWorld::Ptr& ptr) const + int Lockpick::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -122,10 +120,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -173,10 +170,9 @@ namespace MWClass return (npcServices & ESM::NPC::Picks) != 0; } - int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Lockpick::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 7e7ee78d54..44333eb454 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -65,7 +65,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index e5836bd964..57d5a1b1f8 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -26,7 +26,7 @@ namespace MWClass { - bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const + bool Miscellaneous::isGold (const MWWorld::ConstPtr& ptr) const { return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") @@ -64,10 +64,9 @@ namespace MWClass return ""; } - std::string Miscellaneous::getName (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -85,10 +84,9 @@ namespace MWClass return ref->mBase->mScript; } - int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const + int Miscellaneous::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int value = ref->mBase->mData.mValue; if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1) @@ -140,10 +138,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -249,10 +246,9 @@ namespace MWClass return ref->mBase->mData.mWeight; } - bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const + bool Miscellaneous::isKey(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mIsKey != 0; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index e3215a6ad2..a8ee52657f 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -61,9 +61,9 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; - virtual bool isKey (const MWWorld::Ptr &ptr) const; + virtual bool isKey (const MWWorld::ConstPtr &ptr) const; - virtual bool isGold (const MWWorld::Ptr& ptr) const; + virtual bool isGold (const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bac555d1b6..0d0978d370 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -252,6 +252,10 @@ namespace MWClass { return *this; } + virtual const NpcCustomData& asNpcCustomData() const + { + return *this; + } }; MWWorld::CustomData *NpcCustomData::clone() const @@ -436,9 +440,9 @@ namespace MWClass } - std::string Npc::getName (const MWWorld::Ptr& ptr) const + std::string Npc::getName (const MWWorld::ConstPtr& ptr) const { - if(getNpcStats(ptr).isWerewolf()) + if(ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &store = world->getStore().get(); @@ -446,7 +450,7 @@ namespace MWClass return store.find("sWerewolfPopup")->getString(); } - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -921,15 +925,15 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp(); MWGui::ToolTipInfo info; info.caption = getName(ptr); - if(fullHelp && getNpcStats(ptr).isWerewolf()) + if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) { info.caption += " ("; info.caption += ref->mBase->mName; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 48277eb521..f5d9044a7e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -64,7 +64,7 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 9816c3cbc4..34f9922eac 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -54,10 +54,9 @@ namespace MWClass return ""; } - std::string Potion::getName (const MWWorld::Ptr& ptr) const + std::string Potion::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -76,10 +75,9 @@ namespace MWClass return ref->mBase->mScript; } - int Potion::getValue (const MWWorld::Ptr& ptr) const + int Potion::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -117,10 +115,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index a38205257f..10083a7cf7 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& 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; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0e3de75d4b..8882af507b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -51,10 +51,9 @@ namespace MWClass return ""; } - std::string Probe::getName (const MWWorld::Ptr& ptr) const + std::string Probe::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -81,10 +80,9 @@ namespace MWClass return std::make_pair (slots_, false); } - int Probe::getValue (const MWWorld::Ptr& ptr) const + int Probe::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -122,10 +120,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -173,10 +170,9 @@ namespace MWClass return (npcServices & ESM::NPC::Probes) != 0; } - int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Probe::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index a6da5ab9d0..69cf614fd6 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -41,7 +41,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -65,7 +65,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 700db167a2..b52b06baf4 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -50,10 +50,9 @@ namespace MWClass return ""; } - std::string Repair::getName (const MWWorld::Ptr& ptr) const + std::string Repair::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -72,10 +71,9 @@ namespace MWClass return ref->mBase->mScript; } - int Repair::getValue (const MWWorld::Ptr& ptr) const + int Repair::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -118,18 +116,16 @@ namespace MWClass return true; } - int Repair::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Repair::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mUses; } - MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3ec617bd3e..ed17ff5872 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); @@ -61,7 +61,7 @@ namespace MWClass virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? (default implementation: false) - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 86019a5ad6..f9d9f618a2 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -42,7 +42,7 @@ namespace MWClass return ""; } - std::string Static::getName (const MWWorld::Ptr& ptr) const + std::string Static::getName (const MWWorld::ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 3d78f949bc..1748f86c64 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index cc5d8ed597..e363c942e9 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -54,10 +54,9 @@ namespace MWClass return ""; } - std::string Weapon::getName (const MWWorld::Ptr& ptr) const + std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mName; } @@ -76,10 +75,9 @@ namespace MWClass return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } - int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const + int Weapon::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mHealth; } @@ -116,10 +114,9 @@ namespace MWClass return std::make_pair (slots_, stack); } - int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr) const + int Weapon::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); const int size = 12; @@ -146,10 +143,9 @@ namespace MWClass return -1; } - int Weapon::getValue (const MWWorld::Ptr& ptr) const + int Weapon::getValue (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mValue; } @@ -267,10 +263,9 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr) const + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 88282f5a3c..916b61eaee 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -20,7 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - virtual std::string getName (const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -31,13 +31,13 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? - virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; @@ -47,11 +47,11 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual int getValue (const MWWorld::Ptr& ptr) const; + virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. static void registerSelf(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f8d4fbde41..85a5a5720a 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -80,7 +80,7 @@ namespace MWWorld return false; } - int Class::getItemHealth(const Ptr &ptr) const + int Class::getItemHealth(const ConstPtr &ptr) const { if (ptr.getCellRef().getCharge() == -1) return getItemMaxHealth(ptr); @@ -88,7 +88,7 @@ namespace MWWorld return ptr.getCellRef().getCharge(); } - int Class::getItemMaxHealth (const Ptr& ptr) const + int Class::getItemMaxHealth (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have item health"); } @@ -153,7 +153,7 @@ namespace MWWorld throw std::runtime_error ("class does not support time-based uses"); } - float Class::getRemainingUsageTime (const Ptr& ptr) const + float Class::getRemainingUsageTime (const ConstPtr& ptr) const { return -1; } @@ -193,12 +193,12 @@ namespace MWWorld return std::make_pair (std::vector(), false); } - int Class::getEquipmentSkill (const Ptr& ptr) const + int Class::getEquipmentSkill (const ConstPtr& ptr) const { return -1; } - int Class::getValue (const Ptr& ptr) const + int Class::getValue (const ConstPtr& ptr) const { throw std::logic_error ("value not supported by this class"); } @@ -272,7 +272,7 @@ namespace MWWorld throw std::runtime_error ("class does not have any inventory icon"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const + MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have a tool tip"); } @@ -447,7 +447,7 @@ namespace MWWorld return -1; } - int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + int Class::getEffectiveArmorRating(const ConstPtr &armor, const Ptr &actor) const { throw std::runtime_error("class does not support armor ratings"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 38ca7fcc14..3410949642 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -86,7 +86,7 @@ namespace MWWorld virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). - virtual std::string getName (const Ptr& ptr) const = 0; + virtual std::string getName (const ConstPtr& ptr) const = 0; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -101,7 +101,7 @@ namespace MWWorld virtual bool hasToolTip (const Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; @@ -111,10 +111,10 @@ namespace MWWorld virtual bool hasItemHealth (const Ptr& ptr) const; ///< \return Item health data available? (default implementation: false) - virtual int getItemHealth (const Ptr& ptr) const; + virtual int getItemHealth (const ConstPtr& ptr) const; ///< Return current item health or throw an exception if class does not have item health - virtual int getItemMaxHealth (const Ptr& ptr) const; + virtual int getItemMaxHealth (const ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) @@ -167,7 +167,7 @@ namespace MWWorld ///< Sets the remaining duration of the object, such as an equippable light /// source. (default implementation: throw an exception) - virtual float getRemainingUsageTime (const Ptr& ptr) const; + virtual float getRemainingUsageTime (const ConstPtr& ptr) const; ///< Returns the remaining duration of the object, such as an equippable light /// source. (default implementation: -1, i.e. infinite) @@ -193,13 +193,13 @@ namespace MWWorld /// /// Default implementation: return (empty vector, false). - virtual int getEquipmentSkill (const Ptr& ptr) + virtual int getEquipmentSkill (const ConstPtr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. /// (default implementation: return -1) - virtual int getValue (const Ptr& ptr) const; + virtual int getValue (const ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. /// (default implementation: throws an exception) @@ -279,9 +279,9 @@ namespace MWWorld virtual bool isPersistent (const MWWorld::Ptr& ptr) const; - virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } - virtual bool isGold(const MWWorld::Ptr& ptr) const { return false; }; + virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; @@ -344,7 +344,7 @@ namespace MWWorld virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. - virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; + virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 8edbb345fb..dce1e9fdde 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -21,6 +21,13 @@ MWClass::NpcCustomData &CustomData::asNpcCustomData() throw std::logic_error(error.str()); } +const MWClass::NpcCustomData &CustomData::asNpcCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to NpcCustomData"; + throw std::logic_error(error.str()); +} + MWClass::ContainerCustomData &CustomData::asContainerCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 8c3890580b..407962ee0f 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -26,6 +26,7 @@ namespace MWWorld virtual MWClass::CreatureCustomData& asCreatureCustomData(); virtual MWClass::NpcCustomData& asNpcCustomData(); + virtual const MWClass::NpcCustomData& asNpcCustomData() const; virtual MWClass::ContainerCustomData& asContainerCustomData(); From f258c5c508e1ecd3541952ccb9026913d39ce54e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:51:05 +0100 Subject: [PATCH 1746/1812] Accept a ConstPtr in getModel --- apps/openmw/mwclass/activator.cpp | 6 ++---- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 6 ++---- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 6 ++---- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 6 ++---- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 6 ++---- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 6 ++---- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 6 ++---- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 6 ++---- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 7 ++----- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 6 ++---- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 6 ++---- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 6 ++---- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/static.cpp | 6 ++---- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 6 ++---- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 38 files changed, 56 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 1ca1150dfb..fcf5dcfd7a 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -45,11 +45,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Activator::getModel(const MWWorld::Ptr &ptr) const + std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 4e371d8ddf..7cdd9506c5 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -39,7 +39,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 3caf68aae6..6a64b88c23 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -37,11 +37,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const + std::string Apparatus::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 32b58af07c..fbbe676eb1 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -58,7 +58,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index c9369e1ae6..a4206a0be5 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -43,11 +43,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Armor::getModel(const MWWorld::Ptr &ptr) const + std::string Armor::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c989fcde0a..a2dd0adc71 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -81,7 +81,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 49b53c480c..f0e69eabfe 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -40,11 +40,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Book::getModel(const MWWorld::Ptr &ptr) const + std::string Book::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a4f2302199..38dc0ae7ba 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -60,7 +60,7 @@ 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; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index faa776e3ab..ee75676bde 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -39,11 +39,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Clothing::getModel(const MWWorld::Ptr &ptr) const + std::string Clothing::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 30d16f0d7e..655a38742f 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -73,7 +73,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 9c39c9df15..c70228baee 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -107,11 +107,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Container::getModel(const MWWorld::Ptr &ptr) const + std::string Container::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 13593b1c07..c6a23df6c1 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -73,7 +73,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr &ptr) const; - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index fceae4060c..1072a24358 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -175,11 +175,9 @@ namespace MWClass objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } - std::string Creature::getModel(const MWWorld::Ptr &ptr) const + std::string Creature::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert (ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index efb4715af4..47e886c01d 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -100,7 +100,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool isActor() const { diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 47116cd7b5..3e6f2b9562 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -78,11 +78,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Door::getModel(const MWWorld::Ptr &ptr) const + std::string Door::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 384f38fa9a..6cb297ca5b 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -54,7 +54,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; /// 0 = nothing, 1 = opening, 2 = closing virtual int getDoorState (const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 95cf00d948..f871095c7a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -43,11 +43,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const + std::string Ingredient::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index a6740a3998..7f1e53ca67 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -55,7 +55,7 @@ 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; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index eb1c3bcc20..8c0a05b960 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -59,11 +59,9 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - std::string Light::getModel(const MWWorld::Ptr &ptr) const + std::string Light::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert (ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 5e04fdb0ba..3cc005429f 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual float getRemainingUsageTime (const MWWorld::ConstPtr& ptr) const; ///< Returns the remaining duration of the object. - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 858a01992c..53bcb97076 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -38,11 +38,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const + std::string Lockpick::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 44333eb454..565477b8b2 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -59,7 +59,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 57d5a1b1f8..da8f48c385 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -51,11 +51,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const + std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index a8ee52657f..b2c7b5c766 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -51,7 +51,7 @@ 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; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0d0978d370..0dc97df878 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -425,11 +425,9 @@ namespace MWClass return ref->mBase->mPersistent; } - std::string Npc::getModel(const MWWorld::Ptr &ptr) const + std::string Npc::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); std::string model = "meshes\\base_anim.nif"; const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); @@ -437,7 +435,6 @@ namespace MWClass model = "meshes\\base_animkna.nif"; return model; - } std::string Npc::getName (const MWWorld::ConstPtr& ptr) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f5d9044a7e..aac93ab6eb 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -126,7 +126,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 34f9922eac..7c499c7bc5 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -41,11 +41,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Potion::getModel(const MWWorld::Ptr &ptr) const + std::string Potion::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 10083a7cf7..d884277ce6 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -54,7 +54,7 @@ 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; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 8882af507b..24d64c613c 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -38,11 +38,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Probe::getModel(const MWWorld::Ptr &ptr) const + std::string Probe::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 69cf614fd6..9a8c677894 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -59,7 +59,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index b52b06baf4..038162c928 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -37,11 +37,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Repair::getModel(const MWWorld::Ptr &ptr) const + std::string Repair::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index ed17ff5872..b52677d689 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -51,7 +51,7 @@ 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; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index f9d9f618a2..5539f83751 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -29,11 +29,9 @@ namespace MWClass physics.addObject(ptr, model); } - std::string Static::getModel(const MWWorld::Ptr &ptr) const + std::string Static::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 1748f86c64..9c4a614104 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -26,7 +26,7 @@ namespace MWClass static void registerSelf(); - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e363c942e9..438497024f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -41,11 +41,9 @@ namespace MWClass // TODO: add option somewhere to enable collision for placeable objects } - std::string Weapon::getModel(const MWWorld::Ptr &ptr) const + std::string Weapon::getModel(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - assert(ref->mBase != NULL); + const MWWorld::LiveCellRef *ref = ptr.get(); const std::string &model = ref->mBase->mModel; if (!model.empty()) { diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 916b61eaee..877de41d34 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -79,7 +79,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 85a5a5720a..2e6b74abcf 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -291,7 +291,7 @@ namespace MWWorld { } - std::string Class::getModel(const MWWorld::Ptr &ptr) const + std::string Class::getModel(const MWWorld::ConstPtr &ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3410949642..9d1190a04a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -266,7 +266,7 @@ namespace MWWorld virtual int getServices (const MWWorld::Ptr& actor) const; - virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. From beb8805a12a0b53a972f46db9e10f30f80e89714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:53:47 +0100 Subject: [PATCH 1747/1812] Accept a ConstPtr in getInventoryIcon --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6a64b88c23..323ebfa63c 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -92,10 +92,9 @@ namespace MWClass return std::string("Item Apparatus Down"); } - std::string Apparatus::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Apparatus::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index fbbe676eb1..82dff46ffb 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a4206a0be5..e366ed5918 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -199,10 +199,9 @@ namespace MWClass return std::string("Item Armor Heavy Down"); } - std::string Armor::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Armor::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index a2dd0adc71..5857c01a17 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -64,7 +64,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index f0e69eabfe..6ce07b50dc 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -106,10 +106,9 @@ namespace MWClass return std::string("Item Book Down"); } - std::string Book::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Book::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 38dc0ae7ba..14a41b2107 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index ee75676bde..0cec71d056 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -158,10 +158,9 @@ namespace MWClass return std::string("Item Clothes Down"); } - std::string Clothing::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Clothing::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 655a38742f..fc2fa800bf 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index f871095c7a..3a2cdfc159 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -108,10 +108,9 @@ namespace MWClass return std::string("Item Ingredient Down"); } - std::string Ingredient::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Ingredient::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 7f1e53ca67..309917c44a 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 8c0a05b960..fc3f4e5c56 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -138,10 +138,9 @@ namespace MWClass } - std::string Light::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Light::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 3cc005429f..68529e2d0f 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 53bcb97076..d26585ed3b 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -102,10 +102,9 @@ namespace MWClass return std::string("Item Lockpick Down"); } - std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Lockpick::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 565477b8b2..fa24c0c004 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index da8f48c385..a29142f07c 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -120,10 +120,9 @@ namespace MWClass return std::string("Item Misc Down"); } - std::string Miscellaneous::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index b2c7b5c766..9583ce2dac 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 7c499c7bc5..cf83089d22 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -97,10 +97,9 @@ namespace MWClass return std::string("Item Potion Down"); } - std::string Potion::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Potion::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index d884277ce6..e0cc2722b8 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 24d64c613c..53403e10a7 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -102,10 +102,9 @@ namespace MWClass return std::string("Item Probe Down"); } - std::string Probe::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Probe::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 9a8c677894..fccb94ebbc 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 038162c928..5e8cbad538 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -93,10 +93,9 @@ namespace MWClass return std::string("Item Repair Down"); } - std::string Repair::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Repair::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index b52677d689..06ccf8c35d 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -48,7 +48,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 438497024f..8752d0b333 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -245,10 +245,9 @@ namespace MWClass return std::string("Item Misc Down"); } - std::string Weapon::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Weapon::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mIcon; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 877de41d34..73e4aa2de4 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -62,7 +62,7 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2e6b74abcf..e7c86f65d6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -267,7 +267,7 @@ namespace MWWorld throw std::runtime_error("class does not support soundgen look up"); } - std::string Class::getInventoryIcon (const MWWorld::Ptr& ptr) const + std::string Class::getInventoryIcon (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error ("class does not have any inventory icon"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 9d1190a04a..321f646159 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -248,7 +248,7 @@ namespace MWWorld virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor - virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; From 2bc851c7d3356c77edff589f368074d6666dc3be Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:56:45 +0100 Subject: [PATCH 1748/1812] Accept a ConstPtr in getEnchantment --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 10 files changed, 14 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e366ed5918..f575f99557 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -258,10 +258,9 @@ namespace MWClass return info; } - std::string Armor::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Armor::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5857c01a17..b5ec114456 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 6ce07b50dc..d4e67fdbe7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -146,10 +146,9 @@ namespace MWClass return info; } - std::string Book::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Book::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 14a41b2107..b70b3b5f55 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0cec71d056..1316fabd2b 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -200,10 +200,9 @@ namespace MWClass return info; } - std::string Clothing::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Clothing::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index fc2fa800bf..3ad0b12f9a 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8752d0b333..d8aac64e46 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -347,10 +347,9 @@ namespace MWClass return info; } - std::string Weapon::getEnchantment (const MWWorld::Ptr& ptr) const + std::string Weapon::getEnchantment (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mEnchant; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 73e4aa2de4..556f92e0b5 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e7c86f65d6..7f6006c5cd 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -282,7 +282,7 @@ namespace MWWorld return false; } - std::string Class::getEnchantment (const Ptr& ptr) const + std::string Class::getEnchantment (const ConstPtr& ptr) const { return ""; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 321f646159..f12b90ecac 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -251,7 +251,7 @@ namespace MWWorld virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. - virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) From 0047a2d3302c93da46ca87755c3fbdd773fd404d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 15:58:23 +0100 Subject: [PATCH 1749/1812] Accept a ConstPtr in canSell --- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 2 +- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 2 +- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 27 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 323ebfa63c..878c9f59ec 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -144,7 +144,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Apparatus::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Apparatus) != 0; } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 82dff46ffb..c5066d0fcb 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -60,7 +60,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f575f99557..0554c738e3 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -382,7 +382,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Armor::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Armor) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index b5ec114456..4fd426da4d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -85,7 +85,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index d4e67fdbe7..9ef9b769e2 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -190,7 +190,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Book::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Books) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index b70b3b5f55..21c9a018de 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -66,7 +66,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 1316fabd2b..f5000229b1 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -278,7 +278,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Clothing::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Clothing) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 3ad0b12f9a..4c0240e746 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -79,7 +79,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 3a2cdfc159..5c2cabd4ce 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -181,7 +181,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Ingredient::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Ingredients) != 0; } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 309917c44a..dddf538d19 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index fc3f4e5c56..46ddeeb5f3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -213,7 +213,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Light::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Lights) != 0; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 68529e2d0f..f0061117b9 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -69,7 +69,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index d26585ed3b..26f7fba10e 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -162,7 +162,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Lockpick::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Picks) != 0; } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index fa24c0c004..e06060172b 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a29142f07c..aba92ae3dc 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -228,10 +228,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); } - bool Miscellaneous::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Miscellaneous::canSell (const MWWorld::ConstPtr& item, int npcServices) const { - MWWorld::LiveCellRef *ref = - item.get(); + const MWWorld::LiveCellRef *ref = item.get(); return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 9583ce2dac..bc15f2c5f3 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual bool isKey (const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index cf83089d22..8ca8e51114 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -175,7 +175,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Potion::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Potions) != 0; } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index e0cc2722b8..c4e9dba3d6 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -58,7 +58,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 53403e10a7..89b7f0ab58 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -162,7 +162,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Probe::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Probes) != 0; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index fccb94ebbc..79f1831b3b 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 5e8cbad538..3e6bcca950 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -161,7 +161,7 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); } - bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Repair::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::RepairItem) != 0; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 06ccf8c35d..0e9c21cdb8 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d8aac64e46..3a827088ce 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -419,7 +419,7 @@ namespace MWClass return ref->mBase->mData.mEnchant; } - bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Weapon::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Weapon) || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 556f92e0b5..29222bb5dd 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -81,7 +81,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f6006c5cd..9111215d2b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -55,7 +55,7 @@ namespace MWWorld throw std::runtime_error ("class does not represent an actor"); } - bool Class::canSell (const MWWorld::Ptr& item, int npcServices) const + bool Class::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index f12b90ecac..8d64f9cbe4 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -261,7 +261,7 @@ namespace MWWorld virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh - virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices virtual int getServices (const MWWorld::Ptr& actor) const; From e0bb28480484f20f0fa4ddad4357d1c0dd9c65d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:00:50 +0100 Subject: [PATCH 1750/1812] Accept a ConstPtr in getWeight --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 26 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 878c9f59ec..2a007d6ad3 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -149,10 +149,9 @@ namespace MWClass return (npcServices & ESM::NPC::Apparatus) != 0; } - float Apparatus::getWeight(const MWWorld::Ptr &ptr) const + float Apparatus::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index c5066d0fcb..240bf8dea7 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -16,7 +16,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0554c738e3..8cd4a98e66 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -388,10 +388,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Armor::getWeight(const MWWorld::Ptr &ptr) const + float Armor::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 4fd426da4d..c06c1689fd 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -15,7 +15,7 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9ef9b769e2..372dc084fd 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -196,10 +196,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Book::getWeight(const MWWorld::Ptr &ptr) const + float Book::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 21c9a018de..0452dd6f1e 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -64,7 +64,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f5000229b1..7b32377f69 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -284,10 +284,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Clothing::getWeight(const MWWorld::Ptr &ptr) const + float Clothing::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4c0240e746..fdf7b14931 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -77,7 +77,7 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 5c2cabd4ce..67d85458de 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -187,10 +187,9 @@ namespace MWClass } - float Ingredient::getWeight(const MWWorld::Ptr &ptr) const + float Ingredient::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index dddf538d19..46695e52d6 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -57,7 +57,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 46ddeeb5f3..21277c038c 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -218,10 +218,9 @@ namespace MWClass return (npcServices & ESM::NPC::Lights) != 0; } - float Light::getWeight(const MWWorld::Ptr &ptr) const + float Light::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index f0061117b9..669e7e1e04 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 26f7fba10e..80982c4712 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -174,10 +174,9 @@ namespace MWClass return ref->mBase->mData.mUses; } - float Lockpick::getWeight(const MWWorld::Ptr &ptr) const + float Lockpick::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index e06060172b..da6f824ecc 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index aba92ae3dc..8dad332b63 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -235,10 +235,9 @@ namespace MWClass return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); } - float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const + float Miscellaneous::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index bc15f2c5f3..64e7c6e6df 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -57,7 +57,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 8ca8e51114..24f7aae2d1 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -180,10 +180,9 @@ namespace MWClass return (npcServices & ESM::NPC::Potions) != 0; } - float Potion::getWeight(const MWWorld::Ptr &ptr) const + float Potion::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index c4e9dba3d6..a0c4b97df5 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 89b7f0ab58..6757c6ed28 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -174,10 +174,9 @@ namespace MWClass return ref->mBase->mData.mUses; } - float Probe::getWeight(const MWWorld::Ptr &ptr) const + float Probe::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 79f1831b3b..0c971c914b 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 3e6bcca950..83162462f9 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -166,10 +166,9 @@ namespace MWClass return (npcServices & ESM::NPC::RepairItem) != 0; } - float Repair::getWeight(const MWWorld::Ptr &ptr) const + float Repair::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 0e9c21cdb8..44b845d69f 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -65,7 +65,7 @@ namespace MWClass ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exception) - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 3a827088ce..a45eaaa335 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -425,10 +425,9 @@ namespace MWClass || ((npcServices & ESM::NPC::MagicItems) && !getEnchantment(item).empty()); } - float Weapon::getWeight(const MWWorld::Ptr &ptr) const + float Weapon::getWeight(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mWeight; } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 29222bb5dd..0582d98920 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -83,7 +83,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9111215d2b..f19dce5d04 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -208,7 +208,7 @@ namespace MWWorld throw std::runtime_error ("capacity not supported by this class"); } - float Class::getWeight(const Ptr &ptr) const + float Class::getWeight(const ConstPtr &ptr) const { throw std::runtime_error ("weight not supported by this class"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 8d64f9cbe4..0a82654045 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -275,7 +275,7 @@ namespace MWWorld ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message - virtual float getWeight (const MWWorld::Ptr& ptr) const; + virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual bool isPersistent (const MWWorld::Ptr& ptr) const; From dc92fefd2b6b0fec54d8b31301d4c3aade9aed5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:06:31 +0100 Subject: [PATCH 1751/1812] Accept a ConstPtr in canBeEquipped, getEquipmentSlots & hasItemHealth --- apps/openmw/mwclass/armor.cpp | 6 +++--- apps/openmw/mwclass/armor.hpp | 6 +++--- apps/openmw/mwclass/clothing.cpp | 7 +++---- apps/openmw/mwclass/clothing.hpp | 4 ++-- apps/openmw/mwclass/light.cpp | 10 ++++------ apps/openmw/mwclass/light.hpp | 4 ++-- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/lockpick.hpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/probe.hpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 12 +++++------- apps/openmw/mwclass/weapon.hpp | 6 +++--- apps/openmw/mwworld/class.cpp | 6 +++--- apps/openmw/mwworld/class.hpp | 6 +++--- 16 files changed, 39 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 8cd4a98e66..a10ad8da75 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -67,7 +67,7 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - bool Armor::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Armor::hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } @@ -86,7 +86,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Armor::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); @@ -295,7 +295,7 @@ namespace MWClass return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; } - std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Armor::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c06c1689fd..270a36bf42 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -30,7 +30,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; @@ -39,7 +39,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -73,7 +73,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 7b32377f69..85c2fd1ba2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -70,10 +70,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -221,7 +220,7 @@ namespace MWClass return record->mId; } - std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Clothing::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index fdf7b14931..799c7d688e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -65,7 +65,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 21277c038c..bc07d905b8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -100,10 +100,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Light::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; @@ -224,10 +223,9 @@ namespace MWClass return ref->mBase->mData.mWeight; } - std::pair Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Light::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) return std::make_pair(0,""); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 669e7e1e04..7ee5d1d472 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -71,7 +71,7 @@ namespace MWClass virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; - std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 80982c4712..c9410dd0bc 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -69,7 +69,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { std::vector slots_; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index da6f824ecc..5a8579e358 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -68,7 +68,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } ///< \return Item health data available? (default implementation: false) }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 6757c6ed28..5973e407c8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -69,7 +69,7 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Probe::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { std::vector slots_; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 0c971c914b..b7252f61dc 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -37,7 +37,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -68,7 +68,7 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } ///< \return Item health data available? (default implementation: false) }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 83162462f9..bf3ebda896 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -108,7 +108,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - bool Repair::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Repair::hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 44b845d69f..8264ae0920 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -58,7 +58,7 @@ namespace MWClass ///< Generate action for using via inventory menu (default implementation: return a /// null action). - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? (default implementation: false) virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a45eaaa335..299a79781a 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -65,10 +65,9 @@ namespace MWClass return defaultItemActivate(ptr, actor); } - bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const + bool Weapon::hasItemHealth (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } @@ -88,10 +87,9 @@ namespace MWClass return ref->mBase->mScript; } - std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const + std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots_; bool stack = false; @@ -369,7 +367,7 @@ namespace MWClass return record->mId; } - std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Weapon::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 0582d98920..273f8ba18a 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -34,7 +34,7 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. - virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::ConstPtr& ptr) const; @@ -43,7 +43,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const MWWorld::ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? @@ -71,7 +71,7 @@ namespace MWClass virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f19dce5d04..5f88f241a6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -75,7 +75,7 @@ namespace MWWorld throw std::runtime_error ("class does not have NPC stats"); } - bool Class::hasItemHealth (const Ptr& ptr) const + bool Class::hasItemHealth (const ConstPtr& ptr) const { return false; } @@ -188,7 +188,7 @@ namespace MWWorld return osg::Vec3f (0, 0, 0); } - std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const + std::pair, bool> Class::getEquipmentSlots (const ConstPtr& ptr) const { return std::make_pair (std::vector(), false); } @@ -301,7 +301,7 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - std::pair Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Class::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const { return std::make_pair (1, ""); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0a82654045..17ab13fbb1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -108,7 +108,7 @@ namespace MWWorld ///< Return NPC stats or throw an exception, if class does not have NPC stats /// (default implementation: throw an exception) - virtual bool hasItemHealth (const Ptr& ptr) const; + virtual bool hasItemHealth (const ConstPtr& ptr) const; ///< \return Item health data available? (default implementation: false) virtual int getItemHealth (const ConstPtr& ptr) const; @@ -187,7 +187,7 @@ namespace MWWorld virtual osg::Vec3f getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. - virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; + virtual std::pair, bool> getEquipmentSlots (const ConstPtr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? /// @@ -271,7 +271,7 @@ namespace MWWorld virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. - virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. /// Second item in the pair specifies the error message From d77f785cbcfb38a1694fc78afcac99b94a1fb47e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:09:08 +0100 Subject: [PATCH 1752/1812] Accept a ConstPtr in get*SoundId --- apps/openmw/mwclass/apparatus.cpp | 4 ++-- apps/openmw/mwclass/apparatus.hpp | 4 ++-- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 4 ++-- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 4 ++-- apps/openmw/mwclass/clothing.cpp | 10 ++++------ apps/openmw/mwclass/clothing.hpp | 4 ++-- apps/openmw/mwclass/ingredient.cpp | 4 ++-- apps/openmw/mwclass/ingredient.hpp | 4 ++-- apps/openmw/mwclass/light.cpp | 4 ++-- apps/openmw/mwclass/light.hpp | 4 ++-- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/lockpick.hpp | 4 ++-- apps/openmw/mwclass/misc.cpp | 4 ++-- apps/openmw/mwclass/misc.hpp | 4 ++-- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 4 ++-- apps/openmw/mwclass/weapon.cpp | 10 ++++------ apps/openmw/mwclass/weapon.hpp | 4 ++-- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 4 ++-- 26 files changed, 56 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2a007d6ad3..a90a53adb0 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -82,12 +82,12 @@ namespace MWClass registerClass (typeid (ESM::Apparatus).name(), instance); } - std::string Apparatus::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Apparatus::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Apparatus Up"); } - std::string Apparatus::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Apparatus::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Apparatus Down"); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 240bf8dea7..e50a57c6af 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -45,10 +45,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a10ad8da75..500664b366 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -177,7 +177,7 @@ namespace MWClass registerClass (typeid (ESM::Armor).name(), instance); } - std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Armor::getUpSoundId (const MWWorld::ConstPtr& ptr) const { int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) @@ -188,7 +188,7 @@ namespace MWClass return std::string("Item Armor Heavy Up"); } - std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Armor::getDownSoundId (const MWWorld::ConstPtr& ptr) const { int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 270a36bf42..8ddd92e4dc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -58,10 +58,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 372dc084fd..25be08587e 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -96,12 +96,12 @@ namespace MWClass registerClass (typeid (ESM::Book).name(), instance); } - std::string Book::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Book::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Book Up"); } - std::string Book::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Book::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Book Down"); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 0452dd6f1e..a0b5b434ec 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 85c2fd1ba2..bf3b909419 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -133,10 +133,9 @@ namespace MWClass registerClass (typeid (ESM::Clothing).name(), instance); } - std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Clothing::getUpSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType == 8) { @@ -145,10 +144,9 @@ namespace MWClass return std::string("Item Clothes Up"); } - std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Clothing::getDownSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mData.mType == 8) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 799c7d688e..e513613e43 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -50,10 +50,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 67d85458de..bdc67b4525 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -98,12 +98,12 @@ namespace MWClass registerClass (typeid (ESM::Ingredient).name(), instance); } - std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Ingredient::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Ingredient Up"); } - std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Ingredient::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Ingredient Down"); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 46695e52d6..96fc7e8e42 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index bc07d905b8..c45b114673 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -126,12 +126,12 @@ namespace MWClass registerClass (typeid (ESM::Light).name(), instance); } - std::string Light::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Light::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Misc Up"); } - std::string Light::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Light::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Misc Down"); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 7ee5d1d472..02e3275877 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index c9410dd0bc..b46159cbcd 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -92,12 +92,12 @@ namespace MWClass registerClass (typeid (ESM::Lockpick).name(), instance); } - std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Lockpick::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Lockpick Up"); } - std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Lockpick::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Lockpick Down"); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 5a8579e358..b5b4844c39 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8dad332b63..c8fdc2a8ae 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -106,14 +106,14 @@ namespace MWClass registerClass (typeid (ESM::Miscellaneous).name(), instance); } - std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getUpSoundId (const MWWorld::ConstPtr& ptr) const { if (isGold(ptr)) return std::string("Item Gold Up"); return std::string("Item Misc Up"); } - std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Miscellaneous::getDownSoundId (const MWWorld::ConstPtr& ptr) const { if (isGold(ptr)) return std::string("Item Gold Down"); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 64e7c6e6df..679319e02b 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 24f7aae2d1..e4928384d6 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -87,12 +87,12 @@ namespace MWClass registerClass (typeid (ESM::Potion).name(), instance); } - std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Potion::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Potion Up"); } - std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Potion::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Potion Down"); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index a0c4b97df5..ac6e0d1805 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -45,10 +45,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5973e407c8..ac9ac56e85 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -92,12 +92,12 @@ namespace MWClass registerClass (typeid (ESM::Probe).name(), instance); } - std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Probe::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Probe Up"); } - std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Probe::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Probe Down"); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index b7252f61dc..d0a4b49478 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -46,10 +46,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index bf3ebda896..1940baa676 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -83,12 +83,12 @@ namespace MWClass registerClass (typeid (ESM::Repair).name(), instance); } - std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Repair::getUpSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Repair Up"); } - std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Repair::getDownSoundId (const MWWorld::ConstPtr& ptr) const { return std::string("Item Repair Down"); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 8264ae0920..dce47167fd 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -42,10 +42,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 299a79781a..db1448afc9 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -153,10 +153,9 @@ namespace MWClass registerClass (typeid (ESM::Weapon).name(), instance); } - std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr) const + std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->mBase->mData.mType; // Ammo @@ -198,10 +197,9 @@ namespace MWClass return std::string("Item Misc Up"); } - std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr) const + std::string Weapon::getDownSoundId (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->mBase->mData.mType; // Ammo diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 273f8ba18a..611e2edf0c 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -56,10 +56,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getUpSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + virtual std::string getDownSoundId (const MWWorld::ConstPtr& ptr) const; ///< Return the put down sound Id virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5f88f241a6..653163a4cc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -252,12 +252,12 @@ namespace MWWorld sClasses.insert(std::make_pair(key, instance)); } - std::string Class::getUpSoundId (const Ptr& ptr) const + std::string Class::getUpSoundId (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have an up sound"); } - std::string Class::getDownSoundId (const Ptr& ptr) const + std::string Class::getDownSoundId (const ConstPtr& ptr) const { throw std::runtime_error ("class does not have an down sound"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 17ab13fbb1..56dc7ede5d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -234,11 +234,11 @@ namespace MWWorld /// /// (default implementation: return false) - virtual std::string getUpSoundId (const Ptr& ptr) const; + virtual std::string getUpSoundId (const ConstPtr& ptr) const; ///< Return the up sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) - virtual std::string getDownSoundId (const Ptr& ptr) const; + virtual std::string getDownSoundId (const ConstPtr& ptr) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) From d120f760312fdd1140aa6b6b92e1696e1adcb5ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:11:03 +0100 Subject: [PATCH 1753/1812] Accept a ConstPtr in getSound --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c45b114673..626cde9ac1 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -250,7 +250,7 @@ namespace MWClass return std::make_pair(1,""); } - std::string Light::getSound(const MWWorld::Ptr& ptr) const + std::string Light::getSound(const MWWorld::ConstPtr& ptr) const { return ptr.get()->mBase->mSound; } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 02e3275877..a52c3f5686 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -73,7 +73,7 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; - virtual std::string getSound(const MWWorld::Ptr& ptr) const; + virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 653163a4cc..0617796f36 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -428,7 +428,7 @@ namespace MWWorld return getEncumbrance(ptr) / capacity; } - std::string Class::getSound(const MWWorld::Ptr&) const + std::string Class::getSound(const MWWorld::ConstPtr&) const { return std::string(); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 56dc7ede5d..1873b2a0c8 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -336,7 +336,7 @@ namespace MWWorld virtual void restock (const MWWorld::Ptr& ptr) const {} /// Returns sound id - virtual std::string getSound(const MWWorld::Ptr& ptr) const; + virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; From 92a3acfa5673d2690de13dbb3a902481b5494d6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:12:35 +0100 Subject: [PATCH 1754/1812] Accept a ConstPtr in getBaseFightRating --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1072a24358..80042fa52c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -770,9 +770,9 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getRefId()); } - int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const + int Creature::getBaseFightRating(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mAiData.mFight; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 47e886c01d..66e9207a04 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -129,7 +129,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr &ptr) const; - virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; + virtual int getBaseFightRating(const MWWorld::ConstPtr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0dc97df878..1fa8d27a2c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1236,9 +1236,9 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getRefId()); } - int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const + int Npc::getBaseFightRating (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mAiData.mFight; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index aac93ab6eb..1d554ed3c5 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -167,7 +167,7 @@ namespace MWClass virtual void restock (const MWWorld::Ptr& ptr) const; - virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; + virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; virtual std::string getPrimaryFaction(const MWWorld::Ptr &ptr) const; virtual int getPrimaryFactionRank(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 0617796f36..a481afeb09 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -433,7 +433,7 @@ namespace MWWorld return std::string(); } - int Class::getBaseFightRating(const Ptr &ptr) const + int Class::getBaseFightRating(const ConstPtr &ptr) const { throw std::runtime_error("class does not support fight rating"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1873b2a0c8..6603ecf4be 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -338,7 +338,7 @@ namespace MWWorld /// Returns sound id virtual std::string getSound(const MWWorld::ConstPtr& ptr) const; - virtual int getBaseFightRating (const MWWorld::Ptr& ptr) const; + virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; From b09bdd6af58a44f767570b22892454c26de10a26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:15:40 +0100 Subject: [PATCH 1755/1812] Accept a ConstPtr in isBipedal --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 12 +++++++++++- apps/openmw/mwclass/npc.hpp | 10 +++------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 80042fa52c..35b3c45463 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -40,7 +40,7 @@ namespace { - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + bool isFlagBitSet(const MWWorld::ConstPtr &ptr, ESM::Creature::Flags bitMask) { return (ptr.get()->mBase->mFlags & bitMask) != 0; } @@ -599,7 +599,7 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - bool Creature::isBipedal(const MWWorld::Ptr &ptr) const + bool Creature::isBipedal(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, ESM::Creature::Bipedal); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 66e9207a04..fb303278fe 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -107,7 +107,7 @@ namespace MWClass return true; } - virtual bool isBipedal (const MWWorld::Ptr &ptr) const; + virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; virtual bool canFly (const MWWorld::Ptr &ptr) const; virtual bool canSwim (const MWWorld::Ptr &ptr) const; virtual bool canWalk (const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1fa8d27a2c..8ef3c219a8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1208,6 +1208,16 @@ namespace MWClass return Misc::StringUtils::ciEqual(ptr.get()->mBase->mClass, className); } + bool Npc::canSwim(const MWWorld::ConstPtr &ptr) const + { + return true; + } + + bool Npc::canWalk(const MWWorld::ConstPtr &ptr) const + { + return true; + } + void Npc::respawn(const MWWorld::Ptr &ptr) const { if (ptr.get()->mBase->mFlags & ESM::NPC::Respawn) @@ -1242,7 +1252,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - bool Npc::isBipedal(const MWWorld::Ptr &ptr) const + bool Npc::isBipedal(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1d554ed3c5..acde83c5f2 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -153,15 +153,11 @@ namespace MWClass virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; - virtual bool canSwim (const MWWorld::Ptr &ptr) const { - return true; - } + virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; - virtual bool canWalk (const MWWorld::Ptr &ptr) const { - return true; - } + virtual bool canWalk (const MWWorld::ConstPtr &ptr) const; - virtual bool isBipedal (const MWWorld::Ptr &ptr) const; + virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a481afeb09..681b72c5bc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -355,7 +355,7 @@ namespace MWWorld return newPtr; } - bool Class::isBipedal(const Ptr &ptr) const + bool Class::isBipedal(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 6603ecf4be..cc84f9b32b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -300,7 +300,7 @@ namespace MWWorld return false; } - virtual bool isBipedal(const MWWorld::Ptr& ptr) const; + virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::Ptr& ptr) const; virtual bool canSwim(const MWWorld::Ptr& ptr) const; virtual bool canWalk(const MWWorld::Ptr& ptr) const; From 954186fe1e3b4045a08dfa0a3265b7b38b87f93f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:16:45 +0100 Subject: [PATCH 1756/1812] Accept a ConstPtr in canFly, canSwim & canWalk --- apps/openmw/mwclass/creature.cpp | 6 +++--- apps/openmw/mwclass/creature.hpp | 6 +++--- apps/openmw/mwworld/class.cpp | 6 +++--- apps/openmw/mwworld/class.hpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 35b3c45463..f903144b61 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -604,17 +604,17 @@ namespace MWClass return isFlagBitSet(ptr, ESM::Creature::Bipedal); } - bool Creature::canFly(const MWWorld::Ptr &ptr) const + bool Creature::canFly(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, ESM::Creature::Flies); } - bool Creature::canSwim(const MWWorld::Ptr &ptr) const + bool Creature::canSwim(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, static_cast(ESM::Creature::Swims | ESM::Creature::Bipedal)); } - bool Creature::canWalk(const MWWorld::Ptr &ptr) const + bool Creature::canWalk(const MWWorld::ConstPtr &ptr) const { return isFlagBitSet(ptr, static_cast(ESM::Creature::Walks | ESM::Creature::Bipedal)); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index fb303278fe..5f110e9180 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -108,9 +108,9 @@ namespace MWClass } virtual bool isBipedal (const MWWorld::ConstPtr &ptr) const; - virtual bool canFly (const MWWorld::Ptr &ptr) const; - virtual bool canSwim (const MWWorld::Ptr &ptr) const; - virtual bool canWalk (const MWWorld::Ptr &ptr) const; + virtual bool canFly (const MWWorld::ConstPtr &ptr) const; + virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; + virtual bool canWalk (const MWWorld::ConstPtr &ptr) const; virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 681b72c5bc..8722187aba 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -360,17 +360,17 @@ namespace MWWorld return false; } - bool Class::canFly(const Ptr &ptr) const + bool Class::canFly(const ConstPtr &ptr) const { return false; } - bool Class::canSwim(const Ptr &ptr) const + bool Class::canSwim(const ConstPtr &ptr) const { return false; } - bool Class::canWalk(const Ptr &ptr) const + bool Class::canWalk(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc84f9b32b..619508f744 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -301,9 +301,9 @@ namespace MWWorld } virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; - virtual bool canFly(const MWWorld::Ptr& ptr) const; - virtual bool canSwim(const MWWorld::Ptr& ptr) const; - virtual bool canWalk(const MWWorld::Ptr& ptr) const; + virtual bool canFly(const MWWorld::ConstPtr& ptr) const; + virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; + virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; From da7ebfde9918f4c9d3bba176bea093aab69e170f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:24:24 +0100 Subject: [PATCH 1757/1812] Accept a ConstPtr in copyToCell --- apps/openmw/mwclass/activator.cpp | 6 ++---- apps/openmw/mwclass/activator.hpp | 3 +-- apps/openmw/mwclass/apparatus.cpp | 6 ++---- apps/openmw/mwclass/apparatus.hpp | 3 +-- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 3 +-- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 3 +-- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 3 +-- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 3 +-- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/creature.hpp | 3 +-- apps/openmw/mwclass/door.cpp | 6 ++---- apps/openmw/mwclass/door.hpp | 3 +-- apps/openmw/mwclass/ingredient.cpp | 6 ++---- apps/openmw/mwclass/ingredient.hpp | 3 +-- apps/openmw/mwclass/light.cpp | 6 ++---- apps/openmw/mwclass/light.hpp | 3 +-- apps/openmw/mwclass/lockpick.cpp | 6 ++---- apps/openmw/mwclass/lockpick.hpp | 3 +-- apps/openmw/mwclass/misc.cpp | 7 +++---- apps/openmw/mwclass/misc.hpp | 3 +-- apps/openmw/mwclass/npc.cpp | 6 ++---- apps/openmw/mwclass/npc.hpp | 3 +-- apps/openmw/mwclass/potion.cpp | 6 ++---- apps/openmw/mwclass/potion.hpp | 3 +-- apps/openmw/mwclass/probe.cpp | 6 ++---- apps/openmw/mwclass/probe.hpp | 3 +-- apps/openmw/mwclass/repair.cpp | 6 ++---- apps/openmw/mwclass/repair.hpp | 3 +-- apps/openmw/mwclass/static.cpp | 6 ++---- apps/openmw/mwclass/static.hpp | 3 +-- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 8 ++++---- apps/openmw/mwworld/class.hpp | 8 +++----- 38 files changed, 62 insertions(+), 114 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index fcf5dcfd7a..799ab53117 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -120,11 +120,9 @@ namespace MWClass } - MWWorld::Ptr - Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Activator::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 7cdd9506c5..7214b86e02 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -8,8 +8,7 @@ namespace MWClass class Activator : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index a90a53adb0..36870997bf 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -135,11 +135,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionAlchemy()); } - MWWorld::Ptr - Apparatus::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Apparatus::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index e50a57c6af..d8176d5df5 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -8,8 +8,7 @@ namespace MWClass class Apparatus : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 500664b366..d4605a195d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -365,11 +365,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Armor::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Armor::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8ddd92e4dc..5fd4311936 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Armor : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 25be08587e..591a3cc69b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -173,11 +173,9 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRead(ptr)); } - MWWorld::Ptr - Book::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Book::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a0b5b434ec..84f7448932 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Book : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index bf3b909419..d7a9491689 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -258,11 +258,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Clothing::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Clothing::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index e513613e43..13ec2e5936 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Clothing : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c70228baee..03c676b9ed 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -284,10 +284,9 @@ namespace MWClass return true; } - MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Container::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index c6a23df6c1..9b6d5d2e03 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -10,8 +10,7 @@ namespace MWClass void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index f903144b61..38e0a826d5 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -590,11 +590,9 @@ namespace MWClass return ""; } - MWWorld::Ptr - Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Creature::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5f110e9180..5076d36d01 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -14,8 +14,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; static int getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name); diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3e6f2b9562..f279ae3a07 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -299,11 +299,9 @@ namespace MWClass return "#{sCell=" + dest + "}"; } - MWWorld::Ptr - Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Door::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 6cb297ca5b..f789055ff2 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -11,8 +11,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bdc67b4525..bfe482e96a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -172,11 +172,9 @@ namespace MWClass return info; } - MWWorld::Ptr - Ingredient::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Ingredient::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 96fc7e8e42..dd156d314c 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Ingredient : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 626cde9ac1..86f1b1d610 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -203,11 +203,9 @@ namespace MWClass return ptr.getCellRef().getChargeFloat(); } - MWWorld::Ptr - Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Light::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index a52c3f5686..7fbaa833ad 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Light : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index b46159cbcd..abf9f9c141 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -153,11 +153,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Lockpick::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index b5b4844c39..7225cab116 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Lockpick : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index c8fdc2a8ae..1c8e75f1fe 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -182,8 +182,7 @@ namespace MWClass return info; } - MWWorld::Ptr - Miscellaneous::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Miscellaneous::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { MWWorld::Ptr newPtr; @@ -206,14 +205,14 @@ namespace MWClass // 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 = + const MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getRefData().setCount(1); } else { - MWWorld::LiveCellRef *ref = + const MWWorld::LiveCellRef *ref = ptr.get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 679319e02b..d9979fa87e 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Miscellaneous : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 8ef3c219a8..42e28fc2f9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1124,11 +1124,9 @@ namespace MWClass throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); } - MWWorld::Ptr - Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index acde83c5f2..b621923678 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -14,8 +14,7 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; struct GMST { diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index e4928384d6..f0875d1384 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -166,11 +166,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Potion::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Potion::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index ac6e0d1805..92f0ebcd91 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Potion : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ac9ac56e85..010a73a3c8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -153,11 +153,9 @@ namespace MWClass return action; } - MWWorld::Ptr - Probe::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Probe::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index d0a4b49478..2dc63b1558 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Probe : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 1940baa676..6d681a87c4 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -147,11 +147,9 @@ namespace MWClass return info; } - MWWorld::Ptr - Repair::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Repair::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index dce47167fd..2dcf03ce25 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Repair : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 5539f83751..a6863f4001 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -52,11 +52,9 @@ namespace MWClass registerClass (typeid (ESM::Static).name(), instance); } - MWWorld::Ptr - Static::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Static::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 9c4a614104..f2a5cef92d 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -7,8 +7,7 @@ namespace MWClass { class Static : public MWWorld::Class { - virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index db1448afc9..1b40787c81 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -399,10 +399,9 @@ namespace MWClass } MWWorld::Ptr - Weapon::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return MWWorld::Ptr(cell.insert(ref), &cell); } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 611e2edf0c..aa87afc7ad 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -8,7 +8,7 @@ namespace MWClass class Weapon : public MWWorld::Class { virtual MWWorld::Ptr - copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; public: diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 8722187aba..7b57a2136f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -333,13 +333,13 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const + Class::copyToCellImpl(const ConstPtr &ptr, CellStore &cell) const { - throw std::runtime_error("unable to move class to cell"); + throw std::runtime_error("unable to copy class to cell"); } MWWorld::Ptr - Class::copyToCell(const Ptr &ptr, CellStore &cell) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell) const { Ptr newPtr = copyToCellImpl(ptr, cell); newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference @@ -347,7 +347,7 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const { Ptr newPtr = copyToCell(ptr, cell); newPtr.getRefData().setPosition(pos); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 619508f744..26bd98aa4b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -66,7 +66,7 @@ namespace MWWorld boost::shared_ptr defaultItemActivate(const Ptr &ptr, const Ptr &actor) const; ///< Generate default action for activating inventory items - virtual Ptr copyToCellImpl(const Ptr &ptr, CellStore &cell) const; + virtual Ptr copyToCellImpl(const ConstPtr &ptr, CellStore &cell) const; public: @@ -286,11 +286,9 @@ namespace MWWorld /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; - virtual Ptr - copyToCell(const Ptr &ptr, CellStore &cell) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; - virtual Ptr - copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const; virtual bool isActor() const { return false; From 5b082be79fa70795dd54623b590fe55e57239968 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:28:20 +0100 Subject: [PATCH 1758/1812] Accept a ConstPtr in getBaseGold --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 38e0a826d5..dc64fd3be4 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -735,7 +735,7 @@ namespace MWClass customData.mCreatureStats.writeState (state2.mCreatureStats); } - int Creature::getBaseGold(const MWWorld::Ptr& ptr) const + int Creature::getBaseGold(const MWWorld::ConstPtr& ptr) const { return ptr.get()->mBase->mData.mGold; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5076d36d01..27dc197f97 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -122,7 +122,7 @@ namespace MWClass virtual void writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const; ///< Write additional state from \a ptr into \a state. - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 42e28fc2f9..7238ad453d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1192,9 +1192,9 @@ namespace MWClass static_cast (customData.mNpcStats).writeState (state2.mCreatureStats); } - int Npc::getBaseGold(const MWWorld::Ptr& ptr) const + int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) return ref->mBase->mNpdt52.mGold; else diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b621923678..946276876a 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -148,7 +148,7 @@ namespace MWClass const; ///< Write additional state from \a ptr into \a state. - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7b57a2136f..c4cef4a8bb 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -399,7 +399,7 @@ namespace MWWorld void Class::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const {} - int Class::getBaseGold(const MWWorld::Ptr& ptr) const + int Class::getBaseGold(const MWWorld::ConstPtr& ptr) const { throw std::runtime_error("class does not support base gold"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 26bd98aa4b..fd2c1da8e6 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -320,7 +320,7 @@ namespace MWWorld static void registerClass (const std::string& key, boost::shared_ptr instance); - virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; From 2ac92012e8e7b5b7011d3fcb89802dbf62dc9ed7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:29:30 +0100 Subject: [PATCH 1759/1812] Accept a ConstPtr in isClass --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7238ad453d..82dcf052b4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1201,7 +1201,7 @@ namespace MWClass return ref->mBase->mNpdt12.mGold; } - bool Npc::isClass(const MWWorld::Ptr& ptr, const std::string &className) const + bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const { return Misc::StringUtils::ciEqual(ptr.get()->mBase->mClass, className); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 946276876a..f86eeb8fff 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -150,7 +150,7 @@ namespace MWClass virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; - virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; + virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c4cef4a8bb..bf5fdebb88 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -404,7 +404,7 @@ namespace MWWorld throw std::runtime_error("class does not support base gold"); } - bool Class::isClass(const MWWorld::Ptr& ptr, const std::string &className) const + bool Class::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index fd2c1da8e6..5a9a49d5a0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -322,7 +322,7 @@ namespace MWWorld virtual int getBaseGold(const MWWorld::ConstPtr& ptr) const; - virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; + virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; /// 0 = nothing, 1 = opening, 2 = closing virtual int getDoorState (const MWWorld::Ptr &ptr) const; From 2bd8d60e9fc0bed16fa031f08bed03b430f81e77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:33:54 +0100 Subject: [PATCH 1760/1812] Accept a ConstPtr in getPrimaryFaction, getPrimaryFactionRank --- apps/openmw/mwclass/npc.cpp | 8 ++++---- apps/openmw/mwclass/npc.hpp | 4 ++-- apps/openmw/mwscript/statsextensions.cpp | 24 ++++++++++++------------ apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 82dcf052b4..be5f6c6db0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1255,15 +1255,15 @@ namespace MWClass return true; } - std::string Npc::getPrimaryFaction (const MWWorld::Ptr& ptr) const + std::string Npc::getPrimaryFaction (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mFaction; } - int Npc::getPrimaryFactionRank (const MWWorld::Ptr& ptr) const + int Npc::getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->getFactionRank(); } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f86eeb8fff..ba2679c082 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -164,8 +164,8 @@ namespace MWClass virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; - virtual std::string getPrimaryFaction(const MWWorld::Ptr &ptr) const; - virtual int getPrimaryFactionRank(const MWWorld::Ptr &ptr) const; + virtual std::string getPrimaryFaction(const MWWorld::ConstPtr &ptr) const; + virtual int getPrimaryFactionRank(const MWWorld::ConstPtr &ptr) const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index dcac733117..2a504f2aba 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -32,7 +32,7 @@ namespace { - std::string getDialogueActorFaction(MWWorld::Ptr actor) + std::string getDialogueActorFaction(MWWorld::ConstPtr actor) { std::string factionId = actor.getClass().getPrimaryFaction(actor); if (factionId.empty()) @@ -530,7 +530,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -562,7 +562,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -601,7 +601,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr actor = R()(runtime, false); + MWWorld::ConstPtr actor = R()(runtime, false); std::string factionID = ""; @@ -633,7 +633,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0) @@ -739,7 +739,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionId; @@ -771,7 +771,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); @@ -805,7 +805,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); @@ -867,7 +867,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + MWWorld::ConstPtr ptr = R()(runtime); std::string race = runtime.getStringLiteral(runtime[0].mInteger); ::Misc::StringUtils::lowerCaseInPlace(race); @@ -899,7 +899,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) @@ -931,7 +931,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) @@ -958,7 +958,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime, false); + MWWorld::ConstPtr ptr = R()(runtime, false); std::string factionID = ""; if(arg0 >0 ) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index bf5fdebb88..9ff6beb8e0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -438,11 +438,11 @@ namespace MWWorld throw std::runtime_error("class does not support fight rating"); } - std::string Class::getPrimaryFaction (const MWWorld::Ptr& ptr) const + std::string Class::getPrimaryFaction (const MWWorld::ConstPtr& ptr) const { return std::string(); } - int Class::getPrimaryFactionRank (const MWWorld::Ptr& ptr) const + int Class::getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const { return -1; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5a9a49d5a0..10754de7d1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -338,8 +338,8 @@ namespace MWWorld virtual int getBaseFightRating (const MWWorld::ConstPtr& ptr) const; - virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; - virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + virtual std::string getPrimaryFaction (const MWWorld::ConstPtr& ptr) const; + virtual int getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const; /// Get the effective armor rating, factoring in the actor's skills, for the given armor. virtual int getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const; From 4a47fc32fae0040732688fdbd1d0ebeffbff6a58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:38:14 +0100 Subject: [PATCH 1761/1812] Accept a ConstPtr in getBloodTexture --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index dc64fd3be4..6646a7d790 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -675,7 +675,7 @@ namespace MWClass } } - int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const + int Creature::getBloodTexture(const MWWorld::ConstPtr &ptr) const { int flags = ptr.get()->mBase->mFlags; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 27dc197f97..720d87f179 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -114,7 +114,7 @@ namespace MWClass virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index be5f6c6db0..350b644ed4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1136,9 +1136,9 @@ namespace MWClass return ptr.getClass().getNpcStats(ptr).getSkill(skill).getModified(); } - int Npc::getBloodTexture(const MWWorld::Ptr &ptr) const + int Npc::getBloodTexture(const MWWorld::ConstPtr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mFlags & ESM::NPC::Skeleton) return 1; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index ba2679c082..684d891f91 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -130,7 +130,7 @@ namespace MWClass virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual bool isActor() const { return true; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9ff6beb8e0..a0037df578 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -390,7 +390,7 @@ namespace MWWorld throw std::runtime_error("class does not support skills"); } - int Class::getBloodTexture (const MWWorld::Ptr& ptr) const + int Class::getBloodTexture (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error("class does not support gore"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 10754de7d1..04d22f91af 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -284,7 +284,7 @@ namespace MWWorld virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) - virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; + virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; From 3fe3091275f3e6a1f1d7d144ee997b237672898b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:39:35 +0100 Subject: [PATCH 1762/1812] Accept a ConstPtr in isEssential --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6646a7d790..2483f2a7e9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -448,7 +448,7 @@ namespace MWClass return ref->mBase->mScript; } - bool Creature::isEssential (const MWWorld::Ptr& ptr) const + bool Creature::isEssential (const MWWorld::ConstPtr& ptr) const { return isFlagBitSet(ptr, ESM::Creature::Essential); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 720d87f179..72305a1d8b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -83,7 +83,7 @@ namespace MWClass virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) virtual int getServices (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 350b644ed4..0e9618608f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -908,10 +908,9 @@ namespace MWClass return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement; } - bool Npc::isEssential (const MWWorld::Ptr& ptr) const + bool Npc::isEssential (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mFlags & ESM::NPC::Essential) != 0; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 684d891f91..3dfb0b96e1 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -114,7 +114,7 @@ namespace MWClass virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) virtual int getServices (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a0037df578..a07c94a0c6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -218,7 +218,7 @@ namespace MWWorld throw std::runtime_error ("encumbrance not supported by class"); } - bool Class::isEssential (const MWWorld::Ptr& ptr) const + bool Class::isEssential (const MWWorld::ConstPtr& ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 04d22f91af..4fc0c96ecc 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -229,7 +229,7 @@ namespace MWWorld /// /// (default implementations: throws an exception) - virtual bool isEssential (const MWWorld::Ptr& ptr) const; + virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) /// /// (default implementation: return false) From 3c98f8dde3b3a89c3fb6bf50b7e1c141aa1a6202 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:41:37 +0100 Subject: [PATCH 1763/1812] Accept a ConstPtr in isPersistent --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2483f2a7e9..26bb45ea36 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -554,9 +554,9 @@ namespace MWClass return 0; } - bool Creature::isPersistent(const MWWorld::Ptr &actor) const + bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); return ref->mBase->mPersistent; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 72305a1d8b..2299e655ce 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -88,7 +88,7 @@ namespace MWClass virtual int getServices (const MWWorld::Ptr& actor) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0e9618608f..d05b0235ec 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -419,9 +419,9 @@ namespace MWClass renderingInterface.getObjects().insertNPC(ptr); } - bool Npc::isPersistent(const MWWorld::Ptr &actor) const + bool Npc::isPersistent(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); return ref->mBase->mPersistent; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 3dfb0b96e1..8dd78f4846 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -119,7 +119,7 @@ namespace MWClass virtual int getServices (const MWWorld::Ptr& actor) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a07c94a0c6..b4861c85f6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return *iter->second; } - bool Class::isPersistent(const Ptr &ptr) const + bool Class::isPersistent(const ConstPtr &ptr) const { throw std::runtime_error ("class does not support persistence"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4fc0c96ecc..3cf4326c81 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -277,7 +277,7 @@ namespace MWWorld virtual float getWeight (const MWWorld::ConstPtr& ptr) const; - virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } From 648ee6e7fb04424b05ca405b4c229b5bf6597dbd Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:43:11 +0100 Subject: [PATCH 1764/1812] Accept a ConstPtr in applyEnchantment --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 4 ++-- 10 files changed, 15 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index d4605a195d..f11bbcda8d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -265,10 +265,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Armor::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Armor newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5fd4311936..598b779299 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -69,7 +69,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 591a3cc69b..faea0d6f25 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -153,10 +153,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Book::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Book newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 84f7448932..6b8be41bb1 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -53,7 +53,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d7a9491689..2e2b8af84e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -204,10 +204,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Clothing::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Clothing newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 13ec2e5936..42d1a7ea47 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 1b40787c81..085954c815 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -350,10 +350,9 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Weapon::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); ESM::Weapon newItem = *ref->mBase; newItem.mId=""; diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index aa87afc7ad..9acda286b3 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -68,7 +68,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::ConstPtr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index b4861c85f6..5426e85450 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -296,7 +296,7 @@ namespace MWWorld return ""; } - std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Class::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3cf4326c81..5aa8762282 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -268,7 +268,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; @@ -281,7 +281,7 @@ namespace MWWorld virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } - virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }; + virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; } /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; From 09bdb0ad4bde954045119543f610ec32d6a0d2e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:44:35 +0100 Subject: [PATCH 1765/1812] Accept a ConstPtr in getServices --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 26bb45ea36..753f3cbba2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -545,9 +545,9 @@ namespace MWClass return static_cast(stats.getAttribute(0).getModified() * 5); } - int Creature::getServices(const MWWorld::Ptr &actor) const + int Creature::getServices(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); if (ref->mBase->mHasAI) return ref->mBase->mAiData.mServices; else diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 2299e655ce..0ee6e65122 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -86,7 +86,7 @@ namespace MWClass virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d05b0235ec..2ec436a99f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1046,9 +1046,9 @@ namespace MWClass } - int Npc::getServices(const MWWorld::Ptr &actor) const + int Npc::getServices(const MWWorld::ConstPtr &actor) const { - MWWorld::LiveCellRef* ref = actor.get(); + const MWWorld::LiveCellRef* ref = actor.get(); if (ref->mBase->mHasAI) return ref->mBase->mAiData.mServices; else diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 8dd78f4846..90019e45b2 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -117,7 +117,7 @@ namespace MWClass virtual bool isEssential (const MWWorld::ConstPtr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual bool isPersistent (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5426e85450..43bfafb6cb 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -60,7 +60,7 @@ namespace MWWorld return false; } - int Class::getServices(const Ptr &actor) const + int Class::getServices(const ConstPtr &actor) const { throw std::runtime_error ("class does not have services"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5aa8762282..a7aacf6382 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -264,7 +264,7 @@ namespace MWWorld virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices - virtual int getServices (const MWWorld::Ptr& actor) const; + virtual int getServices (const MWWorld::ConstPtr& actor) const; virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; From 303521002d2d4788912415d6bc3158b15c98a214 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:46:02 +0100 Subject: [PATCH 1766/1812] Accept a ConstPtr in adjustScale --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 5 ++--- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 753f3cbba2..43e45067a1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -774,9 +774,9 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const + void Creature::adjustScale(const MWWorld::ConstPtr &ptr, osg::Vec3f &scale, bool /* rendering */) const { - MWWorld::LiveCellRef *ref = ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 0ee6e65122..8f55b9f3dc 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -130,7 +130,7 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::ConstPtr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2ec436a99f..2f328b7de7 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1019,14 +1019,13 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const + void Npc::adjustScale(const MWWorld::ConstPtr &ptr, osg::Vec3f&scale, bool rendering) const { if (!rendering) return; // collision meshes are not scaled based on race height // having the same collision extents for all races makes the environments easier to test - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 90019e45b2..50adb19e0b 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -108,7 +108,7 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const; + virtual void adjustScale (const MWWorld::ConstPtr &ptr, osg::Vec3f &scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 43bfafb6cb..fab74094ab 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -287,7 +287,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const + void Class::adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index a7aacf6382..207fc8a20a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -258,7 +258,7 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; From c43f80633a87f9bb45476e7942f4dc185be4abf1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:48:19 +0100 Subject: [PATCH 1767/1812] Accept a ConstPtr in getEnchantmentPoints --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 10 files changed, 14 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f11bbcda8d..5a5265e17c 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -371,10 +371,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Armor::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 598b779299..5e7f1c2edc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -82,7 +82,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual bool canSell (const MWWorld::ConstPtr& item, int npcServices) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index faea0d6f25..56b573ee38 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -179,10 +179,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Book::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 6b8be41bb1..7d2f578ccc 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual float getWeight (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 2e2b8af84e..73a012cdb4 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -264,10 +264,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Clothing::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 42d1a7ea47..bb9fd3492c 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -74,7 +74,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; virtual float getWeight (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 085954c815..0018ff930f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -405,10 +405,9 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } - int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Weapon::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return ref->mBase->mData.mEnchant; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9acda286b3..9426a14350 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -85,7 +85,7 @@ namespace MWClass virtual float getWeight (const MWWorld::ConstPtr& ptr) const; - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index fab74094ab..6e699dd97f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -173,7 +173,7 @@ namespace MWWorld return 0; } - int Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + int Class::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const { throw std::runtime_error ("class does not support enchanting"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 207fc8a20a..943cfc451a 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -255,7 +255,7 @@ namespace MWWorld ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) - virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual int getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const; ///< @return the number of enchantment points available for possible enchanting virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const; From 266fbbef4827a12ceb1760a31f53fd48854e79c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:50:32 +0100 Subject: [PATCH 1768/1812] Accept a ConstPtr in canLock --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 03c676b9ed..39ce594ae8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -279,7 +279,7 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } - bool Container::canLock(const MWWorld::Ptr &ptr) const + bool Container::canLock(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 9b6d5d2e03..53795b5406 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -56,7 +56,7 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f279ae3a07..dfd974ef61 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -209,7 +209,7 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } - bool Door::canLock(const MWWorld::Ptr &ptr) const + bool Door::canLock(const MWWorld::ConstPtr &ptr) const { return true; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index f789055ff2..7db9852db0 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -46,7 +46,7 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6e699dd97f..e4bb722839 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -143,7 +143,7 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } - bool Class::canLock(const Ptr &ptr) const + bool Class::canLock(const ConstPtr &ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 943cfc451a..0129a3dcfe 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -161,7 +161,7 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) - virtual bool canLock (const Ptr& ptr) const; + virtual bool canLock (const ConstPtr& ptr) const; virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object, such as an equippable light From 04f7a8f8eb239f1b080103ee28b50f4d5eabce6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 16:58:08 +0100 Subject: [PATCH 1769/1812] Remove redundant getId function --- apps/openmw/mwclass/activator.cpp | 4 ---- apps/openmw/mwclass/activator.hpp | 3 --- apps/openmw/mwclass/apparatus.cpp | 4 ---- apps/openmw/mwclass/apparatus.hpp | 3 --- apps/openmw/mwclass/armor.cpp | 4 ---- apps/openmw/mwclass/armor.hpp | 3 --- apps/openmw/mwclass/book.cpp | 4 ---- apps/openmw/mwclass/book.hpp | 3 --- apps/openmw/mwclass/clothing.cpp | 4 ---- apps/openmw/mwclass/clothing.hpp | 3 --- apps/openmw/mwclass/container.cpp | 5 ----- apps/openmw/mwclass/container.hpp | 3 --- apps/openmw/mwclass/creature.cpp | 16 ++++------------ apps/openmw/mwclass/creature.hpp | 3 --- apps/openmw/mwclass/creaturelevlist.cpp | 5 ----- apps/openmw/mwclass/creaturelevlist.hpp | 3 --- apps/openmw/mwclass/door.cpp | 5 ----- apps/openmw/mwclass/door.hpp | 3 --- apps/openmw/mwclass/ingredient.cpp | 7 ------- apps/openmw/mwclass/ingredient.hpp | 3 --- apps/openmw/mwclass/itemlevlist.cpp | 4 ---- apps/openmw/mwclass/itemlevlist.hpp | 3 --- apps/openmw/mwclass/light.cpp | 4 ---- apps/openmw/mwclass/light.hpp | 5 +---- apps/openmw/mwclass/lockpick.cpp | 4 ---- apps/openmw/mwclass/lockpick.hpp | 3 --- apps/openmw/mwclass/misc.cpp | 4 ---- apps/openmw/mwclass/misc.hpp | 3 --- apps/openmw/mwclass/npc.cpp | 14 +++----------- apps/openmw/mwclass/npc.hpp | 3 --- apps/openmw/mwclass/potion.cpp | 4 ---- apps/openmw/mwclass/potion.hpp | 3 --- apps/openmw/mwclass/probe.cpp | 4 ---- apps/openmw/mwclass/probe.hpp | 3 --- apps/openmw/mwclass/repair.cpp | 4 ---- apps/openmw/mwclass/repair.hpp | 3 --- apps/openmw/mwclass/static.cpp | 4 ---- apps/openmw/mwclass/static.hpp | 3 --- apps/openmw/mwclass/weapon.cpp | 6 ------ apps/openmw/mwclass/weapon.hpp | 3 --- apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwmechanics/alchemy.cpp | 4 ++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwscript/interpretercontext.cpp | 2 +- apps/openmw/mwworld/actioneat.cpp | 2 +- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 6 ------ apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 2 +- 50 files changed, 19 insertions(+), 186 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 799ab53117..e6dc0b1fe5 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -26,10 +26,6 @@ namespace MWClass { - std::string Activator::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 7214b86e02..d1e9058813 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 36870997bf..8dbd638c05 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -20,10 +20,6 @@ namespace MWClass { - std::string Apparatus::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index d8176d5df5..6763629751 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 5a5265e17c..07e4e2810e 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -26,10 +26,6 @@ namespace MWClass { - std::string Armor::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 5e7f1c2edc..0fdfa566d0 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual float getWeight (const MWWorld::ConstPtr& ptr) const; virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 56b573ee38..8c37dadd75 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -23,10 +23,6 @@ namespace MWClass { - std::string Book::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Book::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 7d2f578ccc..a419c89fef 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 73a012cdb4..6b64e84b05 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -22,10 +22,6 @@ namespace MWClass { - std::string Clothing::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index bb9fd3492c..cbdc6295dc 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 39ce594ae8..bd5f18efd1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -47,11 +47,6 @@ namespace MWClass return new ContainerCustomData (*this); } - std::string Container::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - void Container::ensureCustomData (const MWWorld::Ptr& ptr) const { if (!ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 53795b5406..d8aaab3278 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -14,9 +14,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 43e45067a1..bdd06b9f41 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -154,21 +154,13 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); + getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); } } - std::string Creature::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWRender::Objects& objects = renderingInterface.getObjects(); @@ -335,7 +327,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitAttemptObject(object.getCellRef().getRefId()); if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -353,7 +345,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitObject(object.getCellRef().getRefId()); if (damage > 0.0f && !object.isEmpty()) MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); @@ -571,7 +563,7 @@ namespace MWClass MWWorld::LiveCellRef* ref = ptr.get(); - const std::string& ourId = (ref->mBase->mOriginal.empty()) ? getId(ptr) : ref->mBase->mOriginal; + const std::string& ourId = (ref->mBase->mOriginal.empty()) ? ptr.getCellRef().getRefId() : ref->mBase->mOriginal; MWWorld::Store::iterator sound = store.begin(); while(sound != store.end()) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8f55b9f3dc..1647da01ec 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -40,9 +40,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 9bd5f95372..1f9e9b0fc4 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -29,11 +29,6 @@ namespace MWClass return new CreatureLevListCustomData (*this); } - std::string CreatureLevList::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const { return ""; diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 4ada3cd863..67a7858d87 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index dfd974ef61..e007d3448f 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -48,11 +48,6 @@ namespace MWClass return new DoorCustomData (*this); } - std::string Door::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } - void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { if (!model.empty()) { diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 7db9852db0..ff94cd613c 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -15,9 +15,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bfe482e96a..5fbefcbe38 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -23,13 +23,6 @@ namespace MWClass { - std::string Ingredient::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index dd156d314c..42920f5fc2 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index 7690169c6f..290ac4c26d 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -4,10 +4,6 @@ namespace MWClass { - std::string ItemLevList::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } std::string ItemLevList::getName (const MWWorld::ConstPtr& ptr) const { diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index 8a95b9adbc..a8b313185c 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -9,9 +9,6 @@ namespace MWClass { public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 86f1b1d610..6ff8461528 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -27,10 +27,6 @@ namespace MWClass { - std::string Light::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Light::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 7fbaa833ad..c57a3afb9d 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -11,10 +11,7 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index abf9f9c141..66edd7d81f 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -21,10 +21,6 @@ namespace MWClass { - std::string Lockpick::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 7225cab116..81d7c0c514 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1c8e75f1fe..00505067dc 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -34,10 +34,6 @@ namespace MWClass || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); } - std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index d9979fa87e..d2681ac722 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2f328b7de7..e3e3fd3c2d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -395,7 +395,7 @@ namespace MWClass // inventory // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); + data->mInventoryStore.fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); data->mNpcStats.setGoldPool(gold); @@ -406,14 +406,6 @@ namespace MWClass } } - std::string Npc::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mId; - } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getObjects().insertNPC(ptr); @@ -603,7 +595,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitAttemptObject(object.getCellRef().getRefId()); if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { @@ -621,7 +613,7 @@ namespace MWClass } if(!object.isEmpty()) - getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); + getCreatureStats(ptr).setLastHitObject(object.getCellRef().getRefId()); if (damage > 0.0f && !object.isEmpty()) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 50adb19e0b..88c4dfac9c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -44,9 +44,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index f0875d1384..6ef035679f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -24,10 +24,6 @@ namespace MWClass { - std::string Potion::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 92f0ebcd91..391a5093d1 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 010a73a3c8..fdbf69811c 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -21,10 +21,6 @@ namespace MWClass { - std::string Probe::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 2dc63b1558..62eeb30161 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 6d681a87c4..c6e90aecda 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -20,10 +20,6 @@ namespace MWClass { - std::string Repair::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 2dcf03ce25..3967278582 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index a6863f4001..65e69ea90a 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -11,10 +11,6 @@ namespace MWClass { - std::string Static::getId (const MWWorld::Ptr& ptr) const - { - return ptr.get()->mBase->mId; - } void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index f2a5cef92d..076c39cf10 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -11,9 +11,6 @@ namespace MWClass public: - /// Return ID of \a ptr - virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0018ff930f..e9acf9ba27 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -22,12 +22,6 @@ namespace MWClass { - std::string Weapon::getId (const MWWorld::Ptr& ptr) const - { - MWWorld::LiveCellRef *ref = ptr.get(); - - return ref->mBase->mId; - } void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9426a14350..f24409d82e 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -12,9 +12,6 @@ namespace MWClass public: - virtual std::string getId (const MWWorld::Ptr& ptr) const; - ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 084941b460..43d979ea28 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -28,7 +28,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const // actor id if (!info.mActor.empty()) { - if ( !Misc::StringUtils::ciEqual(info.mActor, mActor.getClass().getId (mActor))) + if ( !Misc::StringUtils::ciEqual(info.mActor, mActor.getCellRef().getRefId())) return false; } else if (isCreature) @@ -438,7 +438,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_NotId: - return !Misc::StringUtils::ciEqual(mActor.getClass().getId (mActor), select.getName()); + return !Misc::StringUtils::ciEqual(mActor.getCellRef().getRefId(), select.getName()); case SelectWrapper::Function_NotFaction: diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 0d3b64f78a..c775330084 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -93,7 +93,7 @@ namespace MWGui Spell newSpell; newSpell.mItem = item; - newSpell.mId = item.getClass().getId(item); + newSpell.mId = item.getCellRef().getRefId(); newSpell.mName = item.getClass().getName(item); newSpell.mType = Spell::Type_EnchantedItem; newSpell.mSelected = invStore.getSelectedEnchantItem() == it; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 38d85a7cd3..d39c881506 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -421,8 +421,8 @@ int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) return -1; for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) - if (!iter->isEmpty() && Misc::StringUtils::ciEqual(ingredient.getClass().getId(ingredient), - iter->getClass().getId(*iter))) + if (!iter->isEmpty() && Misc::StringUtils::ciEqual(ingredient.getCellRef().getRefId(), + iter->getCellRef().getRefId())) return -1; mIngredients[slot] = ingredient; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ba958df10e..21039cc653 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -983,7 +983,7 @@ namespace MWMechanics MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getCellRef().getRefId())); if (stolenIt == mStolenItems.end()) continue; OwnerMap& owners = stolenIt->second; @@ -1045,7 +1045,7 @@ namespace MWMechanics Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) - mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c70eb6cf8f..7a6afe2e0c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -145,7 +145,7 @@ namespace MWScript // selected), store the ID of that reference store it so it can be inherited by // targeted scripts started from this one. if (targetId.empty() && !reference.isEmpty()) - mTargetId = reference.getClass().getId (reference); + mTargetId = reference.getCellRef().getRefId(); } int InterpreterContext::getLocalShort (int index) const diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 82c7fb80e4..84805c70e1 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -19,7 +19,7 @@ namespace MWWorld getTarget().getContainerStore()->remove(getTarget(), 1, actor); // apply to actor - std::string id = getTarget().getClass().getId (getTarget()); + std::string id = getTarget().getCellRef().getRefId(); if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e4bb722839..118bfe0183 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -30,11 +30,6 @@ namespace MWWorld Class::~Class() {} - std::string Class::getId (const Ptr& ptr) const - { - throw std::runtime_error ("class does not support ID retrieval"); - } - void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0129a3dcfe..33d7e26c80 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -76,12 +76,6 @@ namespace MWWorld return mTypeName; } - virtual std::string getId (const Ptr& ptr) const; - ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval - /// (default implementation: throw an exception) - /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. - /// Leaving it here for now in case we want to optimize later. - virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index bfc33507ac..8041be1eab 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -700,7 +700,7 @@ void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sou if (*iter==end()) continue; - if ((*iter)->getClass().getId(**iter) != sourceId) + if ((*iter)->getCellRef().getRefId() != sourceId) continue; std::string enchantmentId = (*iter)->getClass().getEnchantment (**iter); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 00cb8a810a..15b3c057bc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -32,7 +32,7 @@ namespace MWRender::RenderingManager& rendering) { std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); - std::string id = ptr.getClass().getId(ptr); + std::string id = ptr.getCellRef().getRefId(); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player ptr.getClass().insertObjectRendering(ptr, model, rendering); From edde5bd065b76eec01fe3d0a6478d6a1b18905a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:00:31 +0100 Subject: [PATCH 1770/1812] Accept a ConstPtr in ContainerStore::stacks --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- apps/openmw/mwworld/ptr.hpp | 30 ++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 4b4c515478..6a0921013f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -176,7 +176,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld:: return retval; } -bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) { const MWWorld::Class& cls1 = ptr1.getClass(); const MWWorld::Class& cls2 = ptr2.getClass(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e103e16a1d..b01a793668 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -149,7 +149,7 @@ namespace MWWorld public: - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2); ///< @return true if the two specified objects can stack with each other void fill (const ESM::InventoryList& items, const std::string& owner); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 8041be1eab..0f9b2380c6 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -450,7 +450,7 @@ void MWWorld::InventoryStore::flagAsModified() mRechargingItemsUpToDate = false; } -bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) { bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); if (!canStack) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 2c1be9b038..1e03746ffb 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -167,7 +167,7 @@ namespace MWWorld ///< \attention This function is internal to the world model and should not be called from /// outside. - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2); ///< @return true if the two specified objects can stack with each other virtual int remove(const Ptr& item, int count, const Ptr& actor); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 9d370c4cbe..d34f516a79 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -195,6 +195,36 @@ namespace MWWorld { return !(left>right); } + + inline bool operator== (const ConstPtr& left, const ConstPtr& right) + { + return left.mRef==right.mRef; + } + + inline bool operator!= (const ConstPtr& left, const ConstPtr& right) + { + return !(left==right); + } + + inline bool operator< (const ConstPtr& left, const ConstPtr& right) + { + return left.mRef= (const ConstPtr& left, const ConstPtr& right) + { + return !(left (const ConstPtr& left, const ConstPtr& right) + { + return rightright); + } } #endif From e1c6261fee10655b12a58da19037e3f6917c3df9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:03:49 +0100 Subject: [PATCH 1771/1812] Accept a ConstPtr in ContainerStore::getType --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 6a0921013f..52b311abb8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -585,7 +585,7 @@ float MWWorld::ContainerStore::getWeight() const return mCachedWeight; } -int MWWorld::ContainerStore::getType (const Ptr& ptr) +int MWWorld::ContainerStore::getType (const ConstPtr& ptr) { if (ptr.isEmpty()) throw std::runtime_error ("can't put a non-existent object into a container"); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index b01a793668..e1e59d70f9 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -163,7 +163,7 @@ namespace MWWorld float getWeight() const; ///< Return total weight of the items contained in *this. - static int getType (const Ptr& ptr); + static int getType (const ConstPtr& ptr); ///< This function throws an exception, if ptr does not point to an object, that can be /// put into a container. From 3856f931dbade002ae58f08be4d5f7b453f45db2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:04:54 +0100 Subject: [PATCH 1772/1812] Accept a ConstPtr in ContainerStore::addNewStack --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 52b311abb8..ab9fa46110 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -336,7 +336,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, return addNewStack(ptr, count); } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Ptr& ptr, int count) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const ConstPtr& ptr, int count) { ContainerStoreIterator it = begin(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e1e59d70f9..b7ec4bb74e 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,7 +142,7 @@ namespace MWWorld int count (const std::string& id); protected: - ContainerStoreIterator addNewStack (const Ptr& ptr, int count); + ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ///< Add the item to this container (do not try to stack it onto existing items) virtual void flagAsModified(); From f35ab12979a09d67d774a27a52afe4bffff8d372 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:06:58 +0100 Subject: [PATCH 1773/1812] Accept a ConstPtr in InventoryStore::isEquipped --- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 0f9b2380c6..b82b798d11 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -742,7 +742,7 @@ void MWWorld::InventoryStore::clear() ContainerStore::clear(); } -bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) +bool MWWorld::InventoryStore::isEquipped(const MWWorld::ConstPtr &item) { for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) { diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 1e03746ffb..28c44bcec1 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -141,7 +141,7 @@ namespace MWWorld void equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor); ///< \warning \a iterator can not be an end()-iterator, use unequip function instead - bool isEquipped(const MWWorld::Ptr& item); + bool isEquipped(const MWWorld::ConstPtr& item); ///< Utility function, returns true if the given item is equipped in any slot void setSelectedEnchantItem(const ContainerStoreIterator& iterator); From 1212c072665ddb8e63f8270ef85d3bb7917361a5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:08:26 +0100 Subject: [PATCH 1774/1812] Pass a string by reference --- apps/openmw/mwworld/livecellref.cpp | 2 +- apps/openmw/mwworld/livecellref.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 0f83cd9c2a..32830b5fb9 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -11,7 +11,7 @@ #include "class.hpp" #include "esmstore.hpp" -MWWorld::LiveCellRefBase::LiveCellRefBase(std::string type, const ESM::CellRef &cref) +MWWorld::LiveCellRefBase::LiveCellRefBase(const std::string& type, const ESM::CellRef &cref) : mClass(&Class::get(type)), mRef(cref), mData(cref) { } diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 3994d8a249..2631f513fb 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -31,7 +31,7 @@ namespace MWWorld /** runtime-data */ RefData mData; - LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef()); + LiveCellRefBase(const std::string& type, const ESM::CellRef &cref=ESM::CellRef()); /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() { } From 8f9fc87565acfaa63893bd6dbddb1ccc62bd7998 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:09:11 +0100 Subject: [PATCH 1775/1812] Accept a ConstPtr in LocalScripts::setIgnore --- apps/openmw/mwworld/localscripts.cpp | 2 +- apps/openmw/mwworld/localscripts.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 030a418915..46d0b3cc22 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -63,7 +63,7 @@ namespace MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} -void MWWorld::LocalScripts::setIgnore (const Ptr& ptr) +void MWWorld::LocalScripts::setIgnore (const ConstPtr& ptr) { mIgnore = ptr; } diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 5a156a2e97..6ef4633a1d 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -17,14 +17,14 @@ namespace MWWorld { std::list > mScripts; std::list >::iterator mIter; - MWWorld::Ptr mIgnore; + MWWorld::ConstPtr mIgnore; const MWWorld::ESMStore& mStore; public: LocalScripts (const MWWorld::ESMStore& store); - void setIgnore (const Ptr& ptr); + void setIgnore (const ConstPtr& ptr); ///< Mark a single reference for ignoring during iteration over local scripts (will revoke /// previous ignores). From 553132cb51985f5580c19726edd7cc3cfd95da8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:13:54 +0100 Subject: [PATCH 1776/1812] Accept a ConstPtr in launchProjectile --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ba48aa910c..27b071f96b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -481,7 +481,7 @@ namespace MWBase virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; virtual const std::vector& getContentFiles() const = 0; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5728fe1d73..439ac19ec9 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -161,7 +161,7 @@ namespace MWWorld mMagicBolts.push_back(state); } - void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) + void ProjectileManager::launchProjectile(Ptr actor, ConstPtr projectile, const osg::Vec3f &pos, const osg::Quat &orient, Ptr bow, float speed, float attackStrength) { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index f58e266b38..74d4c1dc53 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); - void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); void update(float dt); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 56fe2fc3dd..3f13f2faf0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2712,7 +2712,7 @@ namespace MWWorld } } - void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + void World::launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) { mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7d67395cfd..46f245a127 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -586,7 +586,7 @@ namespace MWWorld virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, float speed, bool stack, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile, + virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); From 7a4aac184243e04bc5d12e966e8d1d3e0b0a1cb6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:20:29 +0100 Subject: [PATCH 1777/1812] Use a ConstPtr for the PtrAnimationMap --- apps/openmw/mwrender/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 5c7ea32f49..3ce6266c8a 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -57,7 +57,7 @@ public: }; class Objects{ - typedef std::map PtrAnimationMap; + typedef std::map PtrAnimationMap; typedef std::map > CellMap; CellMap mCellSceneNodes; From 7a8a7e3dd6a28bb734abcdf85b51d3f8662ac1c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:21:51 +0100 Subject: [PATCH 1778/1812] Add const version of getAnimation --- apps/openmw/mwrender/objects.cpp | 9 +++++++++ apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++++++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + 4 files changed, 19 insertions(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d612824e24..f58ebb9174 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -263,4 +263,13 @@ Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) return NULL; } +const Animation* Objects::getAnimation(const MWWorld::ConstPtr &ptr) const +{ + PtrAnimationMap::const_iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + return iter->second; + + return NULL; +} + } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 3ce6266c8a..3d0c92cb43 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -81,6 +81,7 @@ public: void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); Animation* getAnimation(const MWWorld::Ptr &ptr); + const Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; bool removeObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b44d777220..775463eafa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -706,6 +706,14 @@ namespace MWRender return mObjects->getAnimation(ptr); } + const MWRender::Animation* RenderingManager::getAnimation(const MWWorld::ConstPtr &ptr) const + { + if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) + return mPlayerAnimation.get(); + + return mObjects->getAnimation(ptr); + } + MWRender::Animation* RenderingManager::getPlayerAnimation() { return mPlayerAnimation.get(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7b1c8529fc..c48864e914 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -136,6 +136,7 @@ namespace MWRender void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); + const Animation* getAnimation(const MWWorld::ConstPtr& ptr) const; Animation* getPlayerAnimation(); void addWaterRippleEmitter(const MWWorld::Ptr& ptr); From 795032621c4d8dd643ccde72c7ebaaa7ec390b18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:30:39 +0100 Subject: [PATCH 1779/1812] Use a ConstPtr for the ActorMap and ObjectMap --- apps/openmw/mwphysics/actor.hpp | 7 ++++++- apps/openmw/mwphysics/physicssystem.cpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.hpp | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 3ea64840e2..03193c675e 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -31,7 +31,12 @@ namespace MWPhysics mPtr = updated; } - MWWorld::Ptr getPtr() const + MWWorld::Ptr getPtr() + { + return mPtr; + } + + MWWorld::ConstPtr getPtr() const { return mPtr; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7b4b936782..99aa208532 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -409,7 +409,7 @@ namespace MWPhysics && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; - const PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); if (ptrHolder) standingCollisionTracker[ptr] = ptrHolder->getPtr(); @@ -801,7 +801,7 @@ namespace MWPhysics if (resultCallback.mObject) { - const PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); + PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); if (holder) return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); } @@ -1020,7 +1020,7 @@ namespace MWPhysics if (collisionObject == mTestedAgainst) collisionObject = col1; #endif - const PtrHolder* holder = static_cast(collisionObject->getUserPointer()); + PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) mResult.push_back(holder->getPtr()); return 0.f; @@ -1303,7 +1303,7 @@ namespace MWPhysics // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum, + osg::Vec3f newpos = MovementSolver::move(physicActor->getPtr(), physicActor, iter->second, mTimeAccum, world->isFlying(iter->first), waterlevel, slowFall, mCollisionWorld, mStandingCollisions); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index de644e0f3c..311d5ef968 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -170,12 +170,12 @@ namespace MWPhysics std::auto_ptr mShapeManager; - typedef std::map ObjectMap; + typedef std::map ObjectMap; ObjectMap mObjects; std::set mAnimatedObjects; // stores pointers to elements in mObjects - typedef std::map ActorMap; + typedef std::map ActorMap; ActorMap mActors; typedef std::map, HeightField*> HeightFieldMap; From 0796f49c1765071492c294fcd26741b0ca74f0ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:36:14 +0100 Subject: [PATCH 1780/1812] Accept a ConstPtr in various physics getters --- apps/openmw/mwbase/world.hpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.cpp | 10 +++++----- apps/openmw/mwphysics/physicssystem.hpp | 10 +++++----- apps/openmw/mwworld/worldimp.cpp | 12 ++++++------ apps/openmw/mwworld/worldimp.hpp | 8 ++++---- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 27b071f96b..54babfbcb2 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -374,7 +374,7 @@ namespace MWBase virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const = 0; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; virtual void togglePOV() = 0; virtual bool isFirstPerson() const = 0; @@ -541,14 +541,14 @@ namespace MWBase /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors() = 0; - virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0; + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) = 0; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 99aa208532..d25099a808 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -808,7 +808,7 @@ namespace MWPhysics return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } - float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::Ptr &target) const + float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::ConstPtr &target) const { btCollisionObject* targetCollisionObj = NULL; const Actor* actor = getActor(target); @@ -965,7 +965,7 @@ namespace MWPhysics } } - osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -974,7 +974,7 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -983,7 +983,7 @@ namespace MWPhysics return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const + osg::Vec3f PhysicsSystem::getPosition(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); if (physactor) @@ -1157,7 +1157,7 @@ namespace MWPhysics return NULL; } - const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const + const Actor *PhysicsSystem::getActor(const MWWorld::ConstPtr &ptr) const { ActorMap::const_iterator found = mActors.find(ptr); if (found != mActors.end()) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 311d5ef968..4edf462cab 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -63,7 +63,7 @@ namespace MWPhysics void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); Actor* getActor(const MWWorld::Ptr& ptr); - const Actor* getActor(const MWWorld::Ptr& ptr) const; + const Actor* getActor(const MWWorld::ConstPtr& ptr) const; // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -95,7 +95,7 @@ namespace MWPhysics /// target vector hits the collision shape and then calculates distance from the intersection point. /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. /// \note Only Actor targets are supported at the moment. - float getHitDistance(const osg::Vec3f& point, const MWWorld::Ptr& target) const; + float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const; struct RayResult { @@ -117,14 +117,14 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); /// Get physical half extents (scaled) of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; /// @see MWPhysics::Actor::getRenderingHalfExtents - osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const; + osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. - osg::Vec3f getPosition(const MWWorld::Ptr& actor) const; + osg::Vec3f getPosition(const MWWorld::ConstPtr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3f13f2faf0..d0b3ff99ef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1038,9 +1038,9 @@ namespace MWWorld return facedObject; } - osg::Matrixf World::getActorHeadTransform(const MWWorld::Ptr& actor) const + osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const { - MWRender::Animation *anim = mRendering->getAnimation(actor); + const MWRender::Animation *anim = mRendering->getAnimation(actor); if(anim) { const osg::Node *node = anim->getNode("Head"); @@ -3285,22 +3285,22 @@ namespace MWWorld } } - bool World::isWalkingOnWater(const Ptr &actor) + bool World::isWalkingOnWater(const ConstPtr &actor) { - MWPhysics::Actor* physicActor = mPhysics->getActor(actor); + const MWPhysics::Actor* physicActor = mPhysics->getActor(actor); if (physicActor && physicActor->isWalkingOnWater()) return true; return false; } - osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) + osg::Vec3f World::aimToTarget(const ConstPtr &actor, const MWWorld::ConstPtr& target) { osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } - float World::getHitDistance(const Ptr &actor, const Ptr &target) + float World::getHitDistance(const ConstPtr &actor, const ConstPtr &target) { osg::Vec3f weaponPos = getActorHeadTransform(actor).getTrans(); return mPhysics->getHitDistance(weaponPos, target); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 46f245a127..90fc60ac7a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -470,7 +470,7 @@ namespace MWWorld virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::Ptr& actor) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; virtual void togglePOV(); @@ -640,14 +640,14 @@ namespace MWWorld /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors(); - virtual bool isWalkingOnWater (const MWWorld::Ptr& actor); + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor); /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); }; } From 6c505ca06f2176586cc244c462937f5326b41d95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:38:21 +0100 Subject: [PATCH 1781/1812] Accept a ConstPtr in getHitContact --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 54babfbcb2..25d434492d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -248,7 +248,7 @@ namespace MWBase /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d25099a808..5caffe4ddd 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -770,7 +770,7 @@ namespace MWPhysics } }; - std::pair PhysicsSystem::getHitContact(const MWWorld::Ptr& actor, + std::pair PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor, const osg::Vec3f &origin, const osg::Quat &orient, float queryDistance) @@ -790,7 +790,7 @@ namespace MWPhysics object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); const btCollisionObject* me = NULL; - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) me = physactor->getCollisionObject(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4edf462cab..0271db273f 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -85,7 +85,7 @@ namespace MWPhysics std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); - std::pair getHitContact(const MWWorld::Ptr& actor, + std::pair getHitContact(const MWWorld::ConstPtr& actor, const osg::Vec3f &origin, const osg::Quat &orientation, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d0b3ff99ef..be54f557af 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1056,7 +1056,7 @@ namespace MWWorld } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + std::pair World::getHitContact(const MWWorld::ConstPtr &ptr, float distance) { const ESM::Position &posdata = ptr.getRefData().getPosition(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90fc60ac7a..c4d37b0086 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -344,7 +344,7 @@ namespace MWWorld /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance); /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const Ptr& ptr); From c9ca5bc94658508920dbbef1f1a29101ab20ec4f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:42:59 +0100 Subject: [PATCH 1782/1812] Accept a ConstPtr in placeObject --- apps/openmw/mwbase/world.hpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 16 ++++++---------- apps/openmw/mwworld/worldimp.hpp | 8 ++++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 25d434492d..3705cebaa8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -271,7 +271,7 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; + virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) @@ -347,14 +347,14 @@ namespace MWBase virtual void update (float duration, bool paused) = 0; - virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0; + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) = 0; ///< copy and 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) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0; + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) = 0; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be54f557af..2efe578a41 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1319,7 +1319,7 @@ namespace MWWorld rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } - MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) + MWWorld::Ptr World::safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { return copyObjectToCell(ptr,cell,pos,false); } @@ -1797,7 +1797,7 @@ namespace MWWorld item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1); } - MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) + MWWorld::Ptr World::placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) { const float maxDist = 200.f; @@ -1817,10 +1817,8 @@ namespace MWWorld pos.rot[1] = 0; // copy the object and set its count - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, cell, pos, true); - object.getRefData().setCount(origCount); + dropped.getRefData().setCount(amount); // only the player place items in the world, so no need to check actor PCDropped(dropped); @@ -1846,7 +1844,7 @@ namespace MWWorld } - Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) + Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { if (cell->isExterior()) { @@ -1899,7 +1897,7 @@ namespace MWWorld return dropped; } - MWWorld::Ptr World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount) + MWWorld::Ptr World::dropObjectOnGround (const Ptr& actor, const ConstPtr& object, int amount) { MWWorld::CellStore* cell = actor.getCell(); @@ -1920,10 +1918,8 @@ namespace MWWorld pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, cell, pos); - object.getRefData().setCount(origCount); + dropped.getRefData().setCount(amount); if(actor == mPlayer->getPlayer()) // Only call if dropped by player PCDropped(dropped); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c4d37b0086..244ed98354 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -123,7 +123,7 @@ namespace MWWorld Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); + Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); void updateSoundListener(); void updateWindowManager (); @@ -365,7 +365,7 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); + virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. virtual float getMaxActivationDistance(); @@ -443,14 +443,14 @@ namespace MWWorld virtual void update (float duration, bool paused); - virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount); + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount); ///< copy and 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) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount); + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount); ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object From ed101ad35a43e57b5bcc043e76993d1030fdd184 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:44:57 +0100 Subject: [PATCH 1783/1812] Remove redundant getPlayerAnimation function --- apps/openmw/mwrender/renderingmanager.cpp | 5 ----- apps/openmw/mwrender/renderingmanager.hpp | 1 - apps/openmw/mwworld/worldimp.cpp | 2 -- 3 files changed, 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 775463eafa..ee9d93c0f2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -714,11 +714,6 @@ namespace MWRender return mObjects->getAnimation(ptr); } - MWRender::Animation* RenderingManager::getPlayerAnimation() - { - return mPlayerAnimation.get(); - } - void RenderingManager::setupPlayer(const MWWorld::Ptr &player) { if (!mPlayerNode) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c48864e914..58012078c4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -137,7 +137,6 @@ namespace MWRender Animation* getAnimation(const MWWorld::Ptr& ptr); const Animation* getAnimation(const MWWorld::ConstPtr& ptr) const; - Animation* getPlayerAnimation(); void addWaterRippleEmitter(const MWWorld::Ptr& ptr); void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2efe578a41..5da1e1a435 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2109,8 +2109,6 @@ namespace MWWorld MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) { - if (ptr == getPlayerPtr()) - return mRendering->getPlayerAnimation(); return mRendering->getAnimation(ptr); } From 388aed174884c2c91ac4187cafee950f93e4e219 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 17:56:48 +0100 Subject: [PATCH 1784/1812] Accept a ConstPtr in findContainer, collision script functions, getUnderwater functions --- apps/openmw/mwbase/world.hpp | 20 +++++++++---------- apps/openmw/mwphysics/physicssystem.cpp | 12 ++++++------ apps/openmw/mwphysics/physicssystem.hpp | 12 ++++++------ apps/openmw/mwworld/ptr.cpp | 5 +++++ apps/openmw/mwworld/worldimp.cpp | 26 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 22 ++++++++++----------- 6 files changed, 51 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3705cebaa8..05b6454a3d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -178,7 +178,7 @@ namespace MWBase virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr) = 0; + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) = 0; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. @@ -367,10 +367,10 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; - virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; - virtual bool isWading(const MWWorld::Ptr &object) const = 0; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const = 0; + virtual bool isWading(const MWWorld::ConstPtr &object) const = 0; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; @@ -396,14 +396,14 @@ namespace MWBase /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0; - virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::Ptr& object) = 0; ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::Ptr& object, float dmgPerSecond) = 0; + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) = 0; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::Ptr& object, float dmgPerSecond) = 0; + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) = 0; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5caffe4ddd..495880469b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -697,7 +697,7 @@ namespace MWPhysics return mDebugDrawEnabled; } - void PhysicsSystem::markAsNonSolid(const MWWorld::Ptr &ptr) + void PhysicsSystem::markAsNonSolid(const MWWorld::ConstPtr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); if (found == mObjects.end()) @@ -1027,7 +1027,7 @@ namespace MWPhysics } }; - std::vector PhysicsSystem::getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const + std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = NULL; @@ -1337,7 +1337,7 @@ namespace MWPhysics mDebugDrawer->step(); } - bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const + bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { @@ -1347,7 +1347,7 @@ namespace MWPhysics return false; } - void PhysicsSystem::getActorsStandingOn(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsStandingOn(const MWWorld::ConstPtr &object, std::vector &out) const { for (CollisionMap::const_iterator it = mStandingCollisions.begin(); it != mStandingCollisions.end(); ++it) { @@ -1356,13 +1356,13 @@ namespace MWPhysics } } - bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::Ptr &object) const + bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); } - void PhysicsSystem::getActorsCollidingWith(const MWWorld::Ptr &object, std::vector &out) const + void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr &object, std::vector &out) const { std::vector collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); out.insert(out.end(), collisions.begin(), collisions.end()); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 0271db273f..ce611a4d01 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -82,7 +82,7 @@ namespace MWPhysics void stepSimulation(float dt); void debugDraw(); - std::vector getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with + std::vector getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight); std::pair getHitContact(const MWWorld::ConstPtr& actor, @@ -139,23 +139,23 @@ namespace MWPhysics /// Return true if \a actor has been standing on \a object in this frame /// This will trigger whenever the object is directly below the actor. /// It doesn't matter if the actor is stationary or moving. - bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; + bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; /// Get the handle of all actors standing on \a object in this frame. - void getActorsStandingOn(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector& out) const; /// Return true if \a actor has collided with \a object in this frame. /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. - bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::Ptr& object) const; + bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; /// Get the handle of all actors colliding with \a object in this frame. - void getActorsCollidingWith(const MWWorld::Ptr& object, std::vector& out) const; + void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector& out) const; bool toggleDebugRendering(); /// Mark the given object as a 'non-solid' object. A non-solid object means that /// \a isOnSolidGround will return false for actors standing on that object. - void markAsNonSolid (const MWWorld::Ptr& ptr); + void markAsNonSolid (const MWWorld::ConstPtr& ptr); bool isOnSolidGround (const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 3f2ef80b65..01e7be1d1d 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -70,6 +70,11 @@ const MWWorld::LiveCellRefBase *MWWorld::ConstPtr::getBase() const return mRef; } +const MWWorld::ContainerStore *MWWorld::ConstPtr::getContainerStore() const +{ + return mContainerStore; +} + MWWorld::ConstPtr::operator const void *() { return mRef; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5da1e1a435..d19e311f55 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -691,10 +691,10 @@ namespace MWWorld struct FindContainerVisitor { - Ptr mContainedPtr; + ConstPtr mContainedPtr; Ptr mResult; - FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + FindContainerVisitor(const ConstPtr& containedPtr) : mContainedPtr(containedPtr) {} bool operator() (Ptr ptr) { @@ -708,7 +708,7 @@ namespace MWWorld } }; - Ptr World::findContainer(const Ptr& ptr) + Ptr World::findContainer(const ConstPtr& ptr) { if (ptr.isInCell()) return Ptr(); @@ -1967,23 +1967,23 @@ namespace MWWorld return false; } - bool World::isSubmerged(const MWWorld::Ptr &object) const + bool World::isSubmerged(const MWWorld::ConstPtr &object) const { return isUnderwater(object, 1.0f/mSwimHeightScale); } - bool World::isSwimming(const MWWorld::Ptr &object) const + bool World::isSwimming(const MWWorld::ConstPtr &object) const { return isUnderwater(object, mSwimHeightScale); } - bool World::isWading(const MWWorld::Ptr &object) const + bool World::isWading(const MWWorld::ConstPtr &object) const { const float kneeDeep = 0.25f; return isUnderwater(object, kneeDeep); } - bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const + bool World::isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const { osg::Vec3f pos (object.getRefData().getPosition().asVec3()); @@ -2148,33 +2148,33 @@ namespace MWWorld mDoorStates.erase(door); } - bool World::getPlayerStandingOn (const MWWorld::Ptr& object) + bool World::getPlayerStandingOn (const MWWorld::ConstPtr& object) { MWWorld::Ptr player = getPlayerPtr(); return mPhysics->isActorStandingOn(player, object); } - bool World::getActorStandingOn (const MWWorld::Ptr& object) + bool World::getActorStandingOn (const MWWorld::ConstPtr& object) { std::vector actors; mPhysics->getActorsStandingOn(object, actors); return !actors.empty(); } - bool World::getPlayerCollidingWith (const MWWorld::Ptr& object) + bool World::getPlayerCollidingWith (const MWWorld::ConstPtr& object) { MWWorld::Ptr player = getPlayerPtr(); return mPhysics->isActorCollidingWith(player, object); } - bool World::getActorCollidingWith (const MWWorld::Ptr& object) + bool World::getActorCollidingWith (const MWWorld::ConstPtr& object) { std::vector actors; mPhysics->getActorsCollidingWith(object, actors); return !actors.empty(); } - void World::hurtStandingActors(const Ptr &object, float healthPerSecond) + void World::hurtStandingActors(const ConstPtr &object, float healthPerSecond) { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; @@ -2204,7 +2204,7 @@ namespace MWWorld } } - void World::hurtCollidingActors(const Ptr &object, float healthPerSecond) + void World::hurtCollidingActors(const ConstPtr &object, float healthPerSecond) { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 244ed98354..ba3993c240 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -155,7 +155,7 @@ namespace MWWorld const std::vector& content, ContentLoader& contentLoader); float mSwimHeightScale; - bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; + bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() bool mTeleportEnabled; @@ -269,7 +269,7 @@ namespace MWWorld virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr); + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr); ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. @@ -464,10 +464,10 @@ namespace MWWorld virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::Ptr &object) const; - virtual bool isSwimming(const MWWorld::Ptr &object) const; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; - virtual bool isWading(const MWWorld::Ptr &object) const; + virtual bool isWading(const MWWorld::ConstPtr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; @@ -500,14 +500,14 @@ namespace MWWorld /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state); - virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::Ptr& object); ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::Ptr& object); ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::Ptr& object, float dmgPerSecond); + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object); ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object); ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object); ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object); ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::Ptr& object, float dmgPerSecond); + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. From 029d467ea5d4f96aebf4adc764e9c3a58f0c4d0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:00:18 +0100 Subject: [PATCH 1785/1812] Accept a ConstPtr in getItemsOwnedBy, getContainersOwnedBy --- apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 05b6454a3d..9ee9db48c6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -409,9 +409,9 @@ namespace MWBase virtual float getWindSpeed() = 0; - virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all items in active cells owned by this Npc virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d19e311f55..357d508456 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2260,13 +2260,13 @@ namespace MWWorld struct GetContainersOwnedByVisitor { - GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector& out) + GetContainersOwnedByVisitor(const MWWorld::ConstPtr& owner, std::vector& out) : mOwner(owner) , mOut(out) { } - MWWorld::Ptr mOwner; + MWWorld::ConstPtr mOwner; std::vector& mOut; bool operator()(const MWWorld::Ptr& ptr) @@ -2281,7 +2281,7 @@ namespace MWWorld } }; - void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector& out) + void World::getContainersOwnedBy (const MWWorld::ConstPtr& owner, std::vector& out) { const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) @@ -2303,7 +2303,7 @@ namespace MWWorld } }; - void World::getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + void World::getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) { const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ba3993c240..55932981ee 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -513,9 +513,9 @@ namespace MWWorld virtual float getWindSpeed(); - virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all items in active cells owned by this Npc virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); From a0fb31e3b1f869b7b2019c303298002d16755132 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:02:57 +0100 Subject: [PATCH 1786/1812] Accept a ConstPtr in getLOS --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 10 +++++----- apps/openmw/mwphysics/physicssystem.hpp | 4 ++-- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9ee9db48c6..fd8a10af89 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -414,7 +414,7 @@ namespace MWBase virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) = 0; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0; + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) = 0; ///< get Line of Sight (morrowind stupid implementation) virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 495880469b..39e212c0bc 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -857,7 +857,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) const { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -865,7 +865,7 @@ namespace MWPhysics const btCollisionObject* me = NULL; if (!ignore.isEmpty()) { - Actor* actor = getActor(ignore); + const Actor* actor = getActor(ignore); if (actor) me = actor->getCollisionObject(); } @@ -912,10 +912,10 @@ namespace MWPhysics return result; } - bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) + bool PhysicsSystem::getLineOfSight(const MWWorld::ConstPtr &actor1, const MWWorld::ConstPtr &actor2) const { - Actor* physactor1 = getActor(actor1); - Actor* physactor2 = getActor(actor2); + const Actor* physactor1 = getActor(actor1); + const Actor* physactor2 = getActor(actor2); if (!physactor1 || !physactor2) return false; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ce611a4d01..09a76e2081 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -107,12 +107,12 @@ namespace MWPhysics /// @param me Optional, a Ptr to ignore in the list of results RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff); + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff) const; RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); /// Return true if actor1 can see actor2. - bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); + bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; bool isOnGround (const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 6c89f6d6f4..1da6b53fa4 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -118,6 +118,11 @@ namespace MWWorld return mBaseNode; } + const SceneUtil::PositionAttitudeTransform* RefData::getBaseNode() const + { + return mBaseNode; + } + int RefData::getCount() const { return mCount; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index d02e05c987..28d2dad4c9 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -75,6 +75,9 @@ namespace MWWorld /// Return base node (can be a null pointer). SceneUtil::PositionAttitudeTransform* getBaseNode(); + /// Return base node (can be a null pointer). + const SceneUtil::PositionAttitudeTransform* getBaseNode() const; + /// Set base node (can be a null pointer). void setBaseNode (SceneUtil::PositionAttitudeTransform* base); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 357d508456..821f950dda 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2317,7 +2317,7 @@ namespace MWWorld } } - bool World::getLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor) + bool World::getLOS(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& targetActor) { if (!targetActor.getRefData().isEnabled() || !actor.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 55932981ee..51056c4293 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -518,7 +518,7 @@ namespace MWWorld virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor); + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor); ///< get Line of Sight (morrowind stupid implementation) virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist); From 604b5d24e91c3d582dccf87657497a2542674eb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:11:30 +0100 Subject: [PATCH 1787/1812] Use a ConstPtr in SoundManager --- apps/openmw/mwbase/soundmanager.hpp | 20 +++++------ apps/openmw/mwsound/soundmanagerimp.cpp | 46 ++++++++++++------------- apps/openmw/mwsound/soundmanagerimp.hpp | 26 +++++++------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index cc580f1c9c..22582c2b1f 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -87,7 +87,7 @@ namespace MWBase ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0; + virtual void say(const MWWorld::ConstPtr &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. @@ -95,13 +95,13 @@ namespace MWBase ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0; + virtual bool sayDone(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) const = 0; ///< Is actor not speaking? - virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; + virtual void stopSay(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) = 0; ///< Stop an actor speaking - virtual float getSaySoundLoudness(const MWWorld::Ptr& reference) const = 0; + virtual float getSaySoundLoudness(const MWWorld::ConstPtr& reference) const = 0; ///< Check the currently playing say sound for this actor /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. @@ -123,7 +123,7 @@ namespace MWBase ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. @@ -136,10 +136,10 @@ namespace MWBase virtual void stopSound(SoundPtr sound) = 0; ///< Stop the given sound from playing - virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; + virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, - virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; + virtual void stopSound3D(const MWWorld::ConstPtr &reference) = 0; ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell) = 0; @@ -148,13 +148,13 @@ namespace MWBase virtual void stopSound(const std::string& soundId) = 0; ///< Stop a non-3d looping sound - virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration) = 0; + virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration) = 0; ///< Fade out given sound (that is already playing) of given object ///< @param reference Reference to object, whose sound is faded out ///< @param soundId ID of the sound to fade out. ///< @param duration Time until volume reaches 0. - virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0; + virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? /// If you want to check if sound played with playSound is playing, use empty Ptr @@ -168,7 +168,7 @@ namespace MWBase virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0; - virtual void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0; + virtual void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) = 0; virtual void clear() = 0; }; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d235b2fb95..e8ceaa40f5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -392,7 +392,7 @@ namespace MWSound } - void SoundManager::say(const MWWorld::Ptr &ptr, const std::string &filename) + void SoundManager::say(const MWWorld::ConstPtr &ptr, const std::string &filename) { if(!mOutput->isInitialized()) return; @@ -429,7 +429,7 @@ namespace MWSound } } - float SoundManager::getSaySoundLoudness(const MWWorld::Ptr &ptr) const + float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const { SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -456,17 +456,17 @@ namespace MWSound DecoderPtr decoder = loadVoice(voicefile, &loudness); if(!loudness->isReady()) - mPendingSaySounds[MWWorld::Ptr()] = std::make_pair(decoder, loudness); + mPendingSaySounds[MWWorld::ConstPtr()] = std::make_pair(decoder, loudness); else { - SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::Ptr()); + SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr()); if (oldIt != mActiveSaySounds.end()) { mOutput->finishStream(oldIt->second.first); mActiveSaySounds.erase(oldIt); } - mActiveSaySounds.insert(std::make_pair(MWWorld::Ptr(), + mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), std::make_pair(playVoice(decoder, osg::Vec3f(), true), loudness))); } } @@ -476,7 +476,7 @@ namespace MWSound } } - bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const + bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const { SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -488,7 +488,7 @@ namespace MWSound return mPendingSaySounds.find(ptr) == mPendingSaySounds.end(); } - void SoundManager::stopSay(const MWWorld::Ptr &ptr) + void SoundManager::stopSay(const MWWorld::ConstPtr &ptr) { SaySoundMap::iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) @@ -552,7 +552,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); + mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception&) { @@ -562,7 +562,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, + MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { MWBase::SoundPtr sound; @@ -627,7 +627,7 @@ namespace MWSound if(iter != mUnusedBuffers.end()) mUnusedBuffers.erase(iter); } - mActiveSounds[MWWorld::Ptr()].push_back(std::make_pair(sound, sfx)); + mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); } catch(std::exception &) { @@ -643,7 +643,7 @@ namespace MWSound mOutput->finishSound(sound); } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -658,7 +658,7 @@ namespace MWSound } } - void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) + void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr) { SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -674,7 +674,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->first != MWWorld::Ptr() && + if(snditer->first != MWWorld::ConstPtr() && snditer->first != MWMechanics::getPlayer() && snditer->first.getCell() == cell) { @@ -687,7 +687,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - if(sayiter->first != MWWorld::Ptr() && + if(sayiter->first != MWWorld::ConstPtr() && sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) { @@ -699,7 +699,7 @@ namespace MWSound void SoundManager::stopSound(const std::string& soundId) { - SoundMap::iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + SoundMap::iterator snditer = mActiveSounds.find(MWWorld::ConstPtr()); if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); @@ -712,7 +712,7 @@ namespace MWSound } } - void SoundManager::fadeOutSound3D(const MWWorld::Ptr &ptr, + void SoundManager::fadeOutSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, float duration) { SoundMap::iterator snditer = mActiveSounds.find(ptr); @@ -728,7 +728,7 @@ namespace MWSound } } - bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const + bool SoundManager::getSoundPlaying(const MWWorld::ConstPtr &ptr, const std::string& soundId) const { SoundMap::const_iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) @@ -773,7 +773,7 @@ namespace MWSound static std::string regionName = ""; static float sTimePassed = 0.0; MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Ptr player = world->getPlayerPtr(); + const MWWorld::ConstPtr player = world->getPlayerPtr(); const ESM::Cell *cell = player.getCell()->getCell(); sTimePassed += duration; @@ -864,7 +864,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - MWWorld::Ptr ptr = snditer->first; + MWWorld::ConstPtr ptr = snditer->first; MWBase::SoundPtr sound = sndidx->first; if(!ptr.isEmpty() && sound->getIs3D()) { @@ -912,7 +912,7 @@ namespace MWSound decoder->rewind(); MWBase::SoundStreamPtr sound; - MWWorld::Ptr ptr = penditer->first; + MWWorld::ConstPtr ptr = penditer->first; SaySoundMap::iterator old = mActiveSaySounds.find(ptr); if (old != mActiveSaySounds.end()) @@ -921,7 +921,7 @@ namespace MWSound mActiveSaySounds.erase(old); } - if(ptr == MWWorld::Ptr()) + if(ptr == MWWorld::ConstPtr()) sound = playVoice(decoder, osg::Vec3f(), true); else { @@ -944,7 +944,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); while(sayiter != mActiveSaySounds.end()) { - MWWorld::Ptr ptr = sayiter->first; + MWWorld::ConstPtr ptr = sayiter->first; MWBase::SoundStreamPtr sound = sayiter->second.first; if(!ptr.isEmpty() && sound->getIs3D()) { @@ -1068,7 +1068,7 @@ namespace MWSound mListenerUnderwater = underwater; } - void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + void SoundManager::updatePtr(const MWWorld::ConstPtr &old, const MWWorld::ConstPtr &updated) { SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 7058c55b64..695ca92a2a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -81,15 +81,15 @@ namespace MWSound typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; - typedef std::map SoundMap; + typedef std::map SoundMap; SoundMap mActiveSounds; typedef std::pair SoundLoudnessPair; - typedef std::map SaySoundMap; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; typedef std::pair DecoderLoudnessPair; - typedef std::map SayDecoderMap; + typedef std::map SayDecoderMap; SayDecoderMap mPendingSaySounds; typedef std::vector TrackList; @@ -154,7 +154,7 @@ namespace MWSound ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(const MWWorld::Ptr &reference, const std::string& filename); + virtual void say(const MWWorld::ConstPtr &reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -162,13 +162,13 @@ namespace MWSound ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const; + virtual bool sayDone(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()) const; ///< Is actor not speaking? - virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); + virtual void stopSay(const MWWorld::ConstPtr &reference=MWWorld::ConstPtr()); ///< Stop an actor speaking - virtual float getSaySoundLoudness(const MWWorld::Ptr& reference) const; + virtual float getSaySoundLoudness(const MWWorld::ConstPtr& reference) const; ///< Check the currently playing say sound for this actor /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. @@ -188,7 +188,7 @@ namespace MWSound ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. @@ -203,10 +203,10 @@ namespace MWSound ///< Stop the given sound from playing /// @note no-op if \a sound is null - virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); + virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, - virtual void stopSound3D(const MWWorld::Ptr &reference); + virtual void stopSound3D(const MWWorld::ConstPtr &reference); ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell); @@ -215,13 +215,13 @@ namespace MWSound virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound - virtual void fadeOutSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float duration); + virtual void fadeOutSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, float duration); ///< Fade out given sound (that is already playing) of given object ///< @param reference Reference to object, whose sound is faded out ///< @param soundId ID of the sound to fade out. ///< @param duration Time until volume reaches 0. - virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const; + virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask); @@ -234,7 +234,7 @@ namespace MWSound virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater); - virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + virtual void updatePtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated); virtual void clear(); }; From 2c51e7345fb77f44ed72541c817cfbd72dd29936 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Dec 2015 18:32:42 +0100 Subject: [PATCH 1788/1812] Use a separate collision type for doors (Fixes #1962) --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwphysics/actor.cpp | 2 +- apps/openmw/mwphysics/collisiontype.hpp | 5 +++-- apps/openmw/mwphysics/physicssystem.cpp | 8 ++++---- apps/openmw/mwphysics/physicssystem.hpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index e007d3448f..3d2719c589 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -58,7 +58,7 @@ namespace MWClass void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if(!model.empty()) - physics.addObject(ptr, model); + physics.addObject(ptr, model, MWPhysics::CollisionType_Door); // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 8438f26a30..cc46897d13 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -76,7 +76,7 @@ void Actor::updateCollisionMask() mCollisionWorld->removeCollisionObject(mCollisionObject.get()); int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) - collisionMask |= CollisionType_Actor | CollisionType_Projectile; + collisionMask |= CollisionType_Actor | CollisionType_Projectile | CollisionType_Door; if (mCanWaterWalk) collisionMask |= CollisionType_Water; mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); diff --git a/apps/openmw/mwphysics/collisiontype.hpp b/apps/openmw/mwphysics/collisiontype.hpp index 0f083ab352..0d6a32fc09 100644 --- a/apps/openmw/mwphysics/collisiontype.hpp +++ b/apps/openmw/mwphysics/collisiontype.hpp @@ -6,8 +6,9 @@ namespace MWPhysics enum CollisionType { CollisionType_World = 1<<0, - CollisionType_Actor = 1<<1, - CollisionType_HeightMap = 1<<2, + CollisionType_Door = 1<<1, + CollisionType_Actor = 1<<2, + CollisionType_HeightMap = 1<<3, CollisionType_Projectile = 1<<4, CollisionType_Water = 1<<5 }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 39e212c0bc..8806641d38 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -857,7 +857,7 @@ namespace MWPhysics const btCollisionObject* mMe; }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore, int mask, int group) const + PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore, int mask, int group) const { btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); @@ -923,7 +923,7 @@ namespace MWPhysics osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); - RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); + RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door); return !result.mHit; } @@ -1073,7 +1073,7 @@ namespace MWPhysics } } - void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh) + void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType) { osg::ref_ptr shapeInstance = mShapeManager->createInstance(mesh); if (!shapeInstance || !shapeInstance->getCollisionShape()) @@ -1085,7 +1085,7 @@ namespace MWPhysics if (obj->isAnimated()) mAnimatedObjects.insert(obj); - mCollisionWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World, + mCollisionWorld->addCollisionObject(obj->getCollisionObject(), collisionType, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 09a76e2081..f53d7e3d9b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -57,7 +57,7 @@ namespace MWPhysics void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, const std::string& mesh); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); @@ -106,8 +106,8 @@ namespace MWPhysics }; /// @param me Optional, a Ptr to ignore in the list of results - RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = - CollisionType_World|CollisionType_HeightMap|CollisionType_Actor, int group=0xff) const; + RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore = MWWorld::ConstPtr(), int mask = + CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 821f950dda..0449bfbda8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1380,7 +1380,7 @@ namespace MWWorld { osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); return result.mHit; } @@ -1413,7 +1413,7 @@ namespace MWWorld bool reached = (targetRot == maxRot && it->second) || targetRot == minRot; /// \todo should use convexSweepTest here - std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Actor, MWPhysics::CollisionType_Actor); + std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { MWWorld::Ptr ptr = *cit; @@ -2334,7 +2334,7 @@ namespace MWWorld to = from + (to * maxDist); MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), - MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap); + MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap|MWPhysics::CollisionType_Door); if (!result.mHit) return maxDist; From 53f4b92426ec8ea89175ab7be2b907c111d4b9f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:11:07 +0100 Subject: [PATCH 1789/1812] AiEscort do not follow target through doors Testing revealed a problem where the guard on the prison ship would incorrectly follow the player outside. Upon further investigation in vanilla MW, it appears that with AiEscort the actor only follows the target through doors once the AiEscort package has completed, *and* no new AI package is running yet. --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwmechanics/actors.cpp | 22 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/aifollow.hpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 +++++ apps/openmw/mwmechanics/aipackage.hpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ .../mwmechanics/mechanicsmanagerimp.hpp | 1 + apps/openmw/mwworld/actionteleport.cpp | 2 +- 9 files changed, 40 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7cfc0861c7..31afc126a1 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -187,6 +187,7 @@ namespace MWBase ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; + virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0; ///Returns a list of actors who are fighting the given actor within the fAlarmDistance diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ee114dff22..7f857a7008 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1327,6 +1327,28 @@ namespace MWMechanics return list; } + std::list Actors::getActorsFollowing(const MWWorld::Ptr& actor) + { + std::list list; + for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + const MWWorld::Class &cls = iter->first.getClass(); + CreatureStats &stats = cls.getCreatureStats(iter->first); + if (stats.isDead()) + continue; + + // An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package + for (std::list::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) + { + if ((*it)->followTargetThroughDoors() && (*it)->getTarget() == actor) + list.push_back(iter->first); + else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) + break; + } + } + return list; + } + std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 494216ba88..0bdf611d2a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -114,6 +114,7 @@ namespace MWMechanics ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ std::list getActorsSidingWith(const MWWorld::Ptr& actor); + std::list getActorsFollowing(const MWWorld::Ptr& actor); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 97140a63a2..017ea7122d 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -33,6 +33,7 @@ namespace MWMechanics MWWorld::Ptr getTarget(); virtual bool sideWithTarget() const { return true; } + virtual bool followTargetThroughDoors() const { return true; } virtual AiFollow *clone() const; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index fef10b7307..cb2b002f6c 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -30,6 +30,11 @@ bool MWMechanics::AiPackage::sideWithTarget() const return false; } +bool MWMechanics::AiPackage::followTargetThroughDoors() const +{ + return false; +} + MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4b760e4c95..76f89dff4e 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -75,6 +75,9 @@ namespace MWMechanics /// Return true if having this AiPackage makes the actor side with the target in fights (default false) virtual bool sideWithTarget() const; + /// Return true if the actor should follow the target through teleport doors (default false) + virtual bool followTargetThroughDoors() const; + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); protected: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 21039cc653..9dafebffa7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1492,6 +1492,11 @@ namespace MWMechanics return mActors.getActorsSidingWith(actor); } + std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) + { + return mActors.getActorsFollowing(actor); + } + std::list MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor) { return mActors.getActorsFollowingIndices(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 279adeeede..603888adc2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -151,6 +151,7 @@ namespace MWMechanics virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); + virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); virtual std::list getActorsFighting(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index bcb1fc6d42..031f07258c 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -13,7 +13,7 @@ namespace void getFollowers (const MWWorld::Ptr& actor, std::set& out) { - std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor); + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); for(std::list::iterator it = followers.begin();it != followers.end();++it) { if (out.insert(*it).second) From 7a2ca5580a40ef5760336652d0c664ae0084f75f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:50:13 +0100 Subject: [PATCH 1790/1812] Accept a ConstPtr in RippleSimulation --- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 6 +++--- apps/openmw/mwrender/ripplesimulation.hpp | 8 ++++---- apps/openmw/mwstate/statemanagerimp.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 0fdfa566d0..dc8f4f2478 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -40,7 +40,7 @@ namespace MWClass /// stay stacked when equipped? virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index cbdc6295dc..096f9e0cb5 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -32,7 +32,7 @@ namespace MWClass /// stay stacked when equipped? virtual int getEquipmentSkill (const MWWorld::ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 7439bfc702..f232ea475d 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -146,7 +146,7 @@ void RippleSimulation::update(float dt) } -void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +void RippleSimulation::addEmitter(const MWWorld::ConstPtr& ptr, float scale, float force) { Emitter newEmitter; newEmitter.mPtr = ptr; @@ -156,7 +156,7 @@ void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float fo mEmitters.push_back (newEmitter); } -void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +void RippleSimulation::removeEmitter (const MWWorld::ConstPtr& ptr) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) { @@ -168,7 +168,7 @@ void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) } } -void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +void RippleSimulation::updateEmitterPtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& ptr) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) { diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 7d412f4542..a4e12f2756 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -31,7 +31,7 @@ namespace MWRender struct Emitter { - MWWorld::Ptr mPtr; + MWWorld::ConstPtr mPtr; osg::Vec3f mLastEmitPosition; float mScale; float mForce; @@ -47,9 +47,9 @@ namespace MWRender void update(float dt); /// adds an emitter, position will be tracked automatically - void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); - void removeEmitter (const MWWorld::Ptr& ptr); - void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void addEmitter (const MWWorld::ConstPtr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::ConstPtr& ptr); + void updateEmitterPtr (const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& ptr); void removeCell(const MWWorld::CellStore* store); void emitRipple(const osg::Vec3f& pos); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9931cf9672..89d31c4853 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -482,7 +482,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::ConstPtr ptr = MWMechanics::getPlayer(); const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId(); @@ -529,7 +529,7 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); std::string name = player.get()->mBase->mName; return mCharacterManager.getCurrentCharacter (create, name); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 33d7e26c80..deee0f1544 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -189,7 +189,7 @@ namespace MWWorld virtual int getEquipmentSkill (const ConstPtr& ptr) const; - /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. /// (default implementation: return -1) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 9a93f38279..5ce3d5c2fe 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -623,7 +623,7 @@ void WeatherManager::playerTeleported() void WeatherManager::update(float duration, bool paused) { - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); MWBase::World& world = *MWBase::Environment::get().getWorld(); TimeStamp time = world.getTimeStamp(); @@ -885,7 +885,7 @@ inline void WeatherManager::importRegions() inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region) { // If the region is current, then add a weather transition for it. - MWWorld::Ptr player = MWMechanics::getPlayer(); + MWWorld::ConstPtr player = MWMechanics::getPlayer(); if(player.isInCell()) { std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); From 51c77c5045566af4ba9e9d8dca5426ed79ca4d00 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 15:57:37 +0100 Subject: [PATCH 1791/1812] Accept a ConstPtr in getDoorState --- apps/openmw/mwclass/door.cpp | 9 +++++++-- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.hpp | 4 ++-- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 8 files changed, 21 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3d2719c589..58c33ba954 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -41,6 +41,10 @@ namespace MWClass { return *this; } + virtual const DoorCustomData& asDoorCustomData() const + { + return *this; + } }; MWWorld::CustomData *DoorCustomData::clone() const @@ -312,9 +316,10 @@ namespace MWClass } } - int Door::getDoorState (const MWWorld::Ptr &ptr) const + int Door::getDoorState (const MWWorld::ConstPtr &ptr) const { - ensureCustomData(ptr); + if (!ptr.getRefData().getCustomData()) + return 0; const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); return customData.mDoorState; } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index ff94cd613c..74ab11fd98 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -53,7 +53,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::Ptr &ptr) const; + virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 409f7b9c40..100b666e89 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -11,7 +11,7 @@ #include "steering.hpp" -MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) +MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr) : AiPackage(), mDuration(1), mDoorPtr(doorPtr), mAdjAngle(0) { diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 1ad945bca8..9d63c63e08 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -16,7 +16,7 @@ namespace MWMechanics { public: /// Avoid door until the door is fully open - AiAvoidDoor(const MWWorld::Ptr& doorPtr); + AiAvoidDoor(const MWWorld::ConstPtr& doorPtr); virtual AiAvoidDoor *clone() const; @@ -28,7 +28,7 @@ namespace MWMechanics private: float mDuration; - MWWorld::Ptr mDoorPtr; + MWWorld::ConstPtr mDoorPtr; ESM::Position mLastPos; float mAdjAngle; }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 118bfe0183..397762df8b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -404,7 +404,7 @@ namespace MWWorld return false; } - int Class::getDoorState (const MWWorld::Ptr &ptr) const + int Class::getDoorState (const MWWorld::ConstPtr &ptr) const { throw std::runtime_error("this is not a door"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index deee0f1544..2ef0ba2d46 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -319,7 +319,7 @@ namespace MWWorld virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::Ptr &ptr) const; + virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index dce1e9fdde..6f9fb39a78 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -42,6 +42,13 @@ MWClass::DoorCustomData &CustomData::asDoorCustomData() throw std::logic_error(error.str()); } +const MWClass::DoorCustomData &CustomData::asDoorCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to DoorCustomData"; + throw std::logic_error(error.str()); +} + MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 407962ee0f..4ca16fd32e 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -31,6 +31,7 @@ namespace MWWorld virtual MWClass::ContainerCustomData& asContainerCustomData(); virtual MWClass::DoorCustomData& asDoorCustomData(); + virtual const MWClass::DoorCustomData& asDoorCustomData() const; virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); }; From 29d0f448b4ba8315677b72a609cf6c9b38386606 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:02:47 +0100 Subject: [PATCH 1792/1812] Add const version of World::getAnimation --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index fd8a10af89..5ae21022ca 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -430,6 +430,7 @@ namespace MWBase /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const = 0; virtual void reattachPlayerCamera() = 0; /// \todo this does not belong here diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 10c20e65de..ba6a8fe4b0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2114,7 +2114,7 @@ void CharacterController::setActive(bool active) mAnimation->setActive(active); } -void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) +void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target) { mHeadTrackTarget = target; } @@ -2137,7 +2137,7 @@ void CharacterController::updateHeadTracking(float duration) osg::Vec3f headPos = mat.getTrans(); osg::Vec3f direction; - if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) + if (const MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); if (node == NULL) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 90e285b522..5e43bc2b73 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -180,7 +180,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - MWWorld::Ptr mHeadTrackTarget; + MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning @@ -255,7 +255,7 @@ public: void setActive(bool active); /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. - void setHeadTrackTarget(const MWWorld::Ptr& target); + void setHeadTrackTarget(const MWWorld::ConstPtr& target); }; MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0449bfbda8..f403a6faa0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2112,6 +2112,11 @@ namespace MWWorld return mRendering->getAnimation(ptr); } + const MWRender::Animation* World::getAnimation(const MWWorld::ConstPtr &ptr) const + { + return mRendering->getAnimation(ptr); + } + void World::screenshot(osg::Image* image, int w, int h) { mRendering->screenshot(image, w, h); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 51056c4293..2af6a970f1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -534,6 +534,7 @@ namespace MWWorld /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; virtual void reattachPlayerCamera(); /// \todo this does not belong here From b0894ea20dc7e1fc05bd5d542df5925e356473ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:13:00 +0100 Subject: [PATCH 1793/1812] Accept a ConstPtr in hasToolTip --- apps/openmw/mwclass/activator.cpp | 5 ++--- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/actor.cpp | 5 ----- apps/openmw/mwclass/actor.hpp | 3 --- apps/openmw/mwclass/apparatus.cpp | 5 ++--- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 5 ++--- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 13 +++++++++++++ apps/openmw/mwclass/creature.hpp | 3 +++ apps/openmw/mwclass/door.cpp | 5 ++--- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 5 ++--- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 5 ++--- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 5 ++--- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 5 ++--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 9 +++++++++ apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwclass/potion.cpp | 5 ++--- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 5 ++--- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 5 ++--- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 8 +++----- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 40 files changed, 84 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index e6dc0b1fe5..48d0a254d3 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -74,10 +74,9 @@ namespace MWClass registerClass (typeid (ESM::Activator).name(), instance); } - bool Activator::hasToolTip (const MWWorld::Ptr& ptr) const + bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index d1e9058813..3cc4a394ca 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -21,7 +21,7 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index d58047d06f..4e89c7282e 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -61,11 +61,6 @@ namespace MWClass } } - bool Actor::hasToolTip(const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 3f795dff9d..88a3f1a328 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -28,9 +28,6 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; - virtual bool hasToolTip(const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 8dbd638c05..0c27be469d 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -95,10 +95,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const + bool Apparatus::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 6763629751..3405dd8504 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -33,7 +33,7 @@ namespace MWClass virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 07e4e2810e..c06dcbb98f 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -202,10 +202,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const + bool Armor::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index dc8f4f2478..239d3613b7 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -43,7 +43,7 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 8c37dadd75..c5881eb3b7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -109,10 +109,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Book::hasToolTip (const MWWorld::Ptr& ptr) const + bool Book::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a419c89fef..7d28fe4c6b 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 6b64e84b05..f7762f6b5b 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -158,10 +158,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const + bool Clothing::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 096f9e0cb5..08ca5aa2e6 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -35,7 +35,7 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index bd5f18efd1..5a66c49997 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -215,10 +215,9 @@ namespace MWClass registerClass (typeid (ESM::Container).name(), instance); } - bool Container::hasToolTip (const MWWorld::Ptr& ptr) const + bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d8aaab3278..d378bdb25a 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -27,7 +27,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index bdd06b9f41..4b513a6407 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -62,6 +62,10 @@ namespace MWClass { return *this; } + virtual const CreatureCustomData& asCreatureCustomData() const + { + return *this; + } CreatureCustomData() : mContainerStore(0) {} virtual ~CreatureCustomData() { delete mContainerStore; } @@ -510,6 +514,15 @@ namespace MWClass return ptr.getRefData().getCustomData()->asCreatureCustomData().mMovement; } + bool Creature::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + return true; + + const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); + return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); + } + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 1647da01ec..8b31f2edf9 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -47,6 +47,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 58c33ba954..b8013177a3 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -227,10 +227,9 @@ namespace MWClass registerClass (typeid (ESM::Door).name(), instance); } - bool Door::hasToolTip (const MWWorld::Ptr& ptr) const + bool Door::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 74ab11fd98..d11abedcd1 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -28,7 +28,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 5fbefcbe38..53316da4c1 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -108,10 +108,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const + bool Ingredient::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 42920f5fc2..12d2ee3f0c 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 6ff8461528..2fab081548 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -140,10 +140,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Light::hasToolTip (const MWWorld::Ptr& ptr) const + bool Light::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index c57a3afb9d..ff934406e8 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -20,7 +20,7 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 66edd7d81f..908a3b2ad7 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -105,10 +105,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const + bool Lockpick::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 81d7c0c514..16e9caaa84 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 00505067dc..72041fd536 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -123,10 +123,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const + bool Miscellaneous::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index d2681ac722..9954c1f483 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e3e3fd3c2d..fc82b143a0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -913,6 +913,15 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } + bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + return true; + + const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); + return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); + } + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 88c4dfac9c..fb358c73ee 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -60,6 +60,9 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store + virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 6ef035679f..e10f7a9f8d 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -100,10 +100,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const + bool Potion::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 391a5093d1..e17c55563a 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index fdbf69811c..113f500fd4 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -105,10 +105,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const + bool Probe::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 62eeb30161..fec44967dc 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index c6e90aecda..3f3aaa8de5 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -96,10 +96,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const + bool Repair::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3967278582..9ead26f033 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -24,7 +24,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e9acf9ba27..367b744827 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -242,10 +242,9 @@ namespace MWClass return ref->mBase->mIcon; } - bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const + bool Weapon::hasToolTip (const MWWorld::ConstPtr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + const MWWorld::LiveCellRef *ref = ptr.get(); return (ref->mBase->mName != ""); } @@ -391,8 +390,7 @@ namespace MWClass return action; } - MWWorld::Ptr - Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Weapon::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index f24409d82e..99fd8f5eb9 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -25,7 +25,7 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 397762df8b..7f44319835 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -272,7 +272,7 @@ namespace MWWorld throw std::runtime_error ("class does not have a tool tip"); } - bool Class::hasToolTip (const Ptr& ptr) const + bool Class::hasToolTip (const ConstPtr& ptr) const { return false; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2ef0ba2d46..0ac368cca1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -92,7 +92,7 @@ namespace MWWorld ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exception) - virtual bool hasToolTip (const Ptr& ptr) const; + virtual bool hasToolTip (const ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 6f9fb39a78..4b3e143f26 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -14,6 +14,13 @@ MWClass::CreatureCustomData &CustomData::asCreatureCustomData() throw std::logic_error(error.str()); } +const MWClass::CreatureCustomData &CustomData::asCreatureCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureCustomData"; + throw std::logic_error(error.str()); +} + MWClass::NpcCustomData &CustomData::asNpcCustomData() { std::stringstream error; diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 4ca16fd32e..80d706e39a 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -24,6 +24,7 @@ namespace MWWorld // Fast version of dynamic_cast. Needs to be overridden in the respective class. virtual MWClass::CreatureCustomData& asCreatureCustomData(); + virtual const MWClass::CreatureCustomData& asCreatureCustomData() const; virtual MWClass::NpcCustomData& asNpcCustomData(); virtual const MWClass::NpcCustomData& asNpcCustomData() const; From 16e3699739a72f1df790b3be538b6361713bb69b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:18:12 +0100 Subject: [PATCH 1794/1812] Fix collision mask in castSphere --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8806641d38..c3c171af8b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -892,7 +892,7 @@ namespace MWPhysics { btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); callback.m_collisionFilterGroup = 0xff; - callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door; btSphereShape shape(radius); const btQuaternion btrot = btQuaternion::getIdentity(); From 0d4729dcd5b57c0e7ed507ee64b59b6a27c25d56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:19:52 +0100 Subject: [PATCH 1795/1812] Use the const version of CustomData::as* --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.cpp | 6 +++++- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwworld/customdata.cpp | 7 +++++++ apps/openmw/mwworld/customdata.hpp | 1 + 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 4b513a6407..a94c70719a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -734,7 +734,7 @@ namespace MWClass return; } - const CreatureCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); customData.mContainerStore->writeState (state2.mInventory); customData.mCreatureStats.writeState (state2.mCreatureStats); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 1f9e9b0fc4..db2ba45bc7 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -22,6 +22,10 @@ namespace MWClass { return *this; } + virtual const CreatureLevListCustomData& asCreatureLevListCustomData() const + { + return *this; + } }; MWWorld::CustomData *CreatureLevListCustomData::clone() const @@ -121,7 +125,7 @@ namespace MWClass return; } - const CreatureLevListCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); state2.mSpawnActorId = customData.mSpawnActorId; state2.mSpawn = customData.mSpawn; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index b8013177a3..ce987bebf9 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -351,7 +351,7 @@ namespace MWClass state.mHasCustomState = false; return; } - const DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); state2.mDoorState = customData.mDoorState; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index fc82b143a0..a5f997e1c8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1184,7 +1184,7 @@ namespace MWClass return; } - const NpcCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); + const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); diff --git a/apps/openmw/mwworld/customdata.cpp b/apps/openmw/mwworld/customdata.cpp index 4b3e143f26..a63123bcf5 100644 --- a/apps/openmw/mwworld/customdata.cpp +++ b/apps/openmw/mwworld/customdata.cpp @@ -63,5 +63,12 @@ MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() throw std::logic_error(error.str()); } +const MWClass::CreatureLevListCustomData &CustomData::asCreatureLevListCustomData() const +{ + std::stringstream error; + error << "bad cast " << typeid(this).name() << " to CreatureLevListCustomData"; + throw std::logic_error(error.str()); +} + } diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp index 80d706e39a..11932e690f 100644 --- a/apps/openmw/mwworld/customdata.hpp +++ b/apps/openmw/mwworld/customdata.hpp @@ -35,6 +35,7 @@ namespace MWWorld virtual const MWClass::DoorCustomData& asDoorCustomData() const; virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData(); + virtual const MWClass::CreatureLevListCustomData& asCreatureLevListCustomData() const; }; } From 32d5dece58e99024f17abb798cfe0e34ab74767c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:29:07 +0100 Subject: [PATCH 1796/1812] Add count argument to getToolTipInfo --- apps/openmw/mwclass/activator.cpp | 4 ++-- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 4 ++-- apps/openmw/mwclass/apparatus.hpp | 2 +- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/door.hpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 4 ++-- apps/openmw/mwclass/ingredient.hpp | 2 +- apps/openmw/mwclass/light.cpp | 4 ++-- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/lockpick.hpp | 2 +- apps/openmw/mwclass/misc.cpp | 4 +--- apps/openmw/mwclass/misc.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 4 ++-- apps/openmw/mwclass/potion.hpp | 2 +- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/probe.hpp | 2 +- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/repair.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 18 +++++++----------- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 38 files changed, 56 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 48d0a254d3..9785eef1e6 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -81,12 +81,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 3cc4a394ca..15dbf57677 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -24,7 +24,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 0c27be469d..8907a5f8da 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -102,12 +102,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 3405dd8504..d669b9c2da 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static void registerSelf(); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index c06dcbb98f..2e4667016f 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -209,12 +209,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 239d3613b7..9746d6d209 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -46,7 +46,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index c5881eb3b7..a7d8ed8f4d 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -116,12 +116,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 7d28fe4c6b..73bfecacd9 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -30,7 +30,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f7762f6b5b..20ebab3145 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -165,12 +165,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 08ca5aa2e6..e1c0f63f78 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -38,7 +38,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual int getValue (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 5a66c49997..675287af96 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -222,7 +222,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index d378bdb25a..3add65a7e4 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -30,7 +30,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a94c70719a..e9502d86b8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -523,7 +523,7 @@ namespace MWClass return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); } - MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8b31f2edf9..cb89a53d62 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -50,7 +50,7 @@ namespace MWClass virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index ce987bebf9..8d54dff5d0 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -234,7 +234,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index d11abedcd1..42aa6d64d3 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -31,7 +31,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. static std::string getDestination (const MWWorld::LiveCellRef& door); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 53316da4c1..99a50a67a0 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -115,12 +115,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 12d2ee3f0c..9a8bdacfb8 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 2fab081548..c7ebc184fd 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -147,12 +147,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index ff934406e8..5ec21f41fd 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -23,7 +23,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 908a3b2ad7..d3889d2fcd 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -112,12 +112,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 16e9caaa84..f04674f5c0 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 72041fd536..353b93c887 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -130,7 +130,7 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); @@ -138,8 +138,6 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - int count = ptr.getRefData().getCount(); - bool gold = isGold(ptr); if (gold) count *= getValue(ptr); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 9954c1f483..363af7e895 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index a5f997e1c8..57a6d088ab 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -922,7 +922,7 @@ namespace MWClass return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index fb358c73ee..5df34380a5 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -63,7 +63,7 @@ namespace MWClass virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index e10f7a9f8d..40b4d62342 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -107,12 +107,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index e17c55563a..9cdd58058d 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 113f500fd4..79d33ba60e 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -112,12 +112,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index fec44967dc..4fc991a5ff 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 3f3aaa8de5..271f52bde9 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -115,12 +115,12 @@ namespace MWClass return ref->mBase->mData.mUses; } - MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 9ead26f033..f0d1292f4d 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -27,7 +27,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 367b744827..f3f8409215 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -249,12 +249,12 @@ namespace MWClass return (ref->mBase->mName != ""); } - MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr) const + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 99fd8f5eb9..5fc3983f25 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -28,7 +28,7 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual bool hasItemHealth (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3356698df8..ffc32bd9ff 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -115,7 +115,7 @@ namespace MWGui tooltipSize = createToolTip(info, true); } else - tooltipSize = getToolTipViaPtr(true); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true); MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition(); position(tooltipPosition, tooltipSize, viewSize); @@ -183,17 +183,13 @@ namespace MWGui else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") { std::pair pair = *focus->getUserData >(); mFocusObject = pair.second->getItem(pair.first).mBase; - // HACK: To get the correct count for multiple item stack sources - int oldCount = mFocusObject.getRefData().getCount(); - mFocusObject.getRefData().setCount(pair.second->getItem(pair.first).mCount); - tooltipSize = getToolTipViaPtr(false); - mFocusObject.getRefData().setCount(oldCount); + tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false); } else if (type == "ToolTipInfo") { @@ -207,7 +203,7 @@ namespace MWGui mFocusObject = item; if (!mFocusObject.isEmpty ()) - tooltipSize = getToolTipViaPtr(false); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "Spell") { @@ -294,7 +290,7 @@ namespace MWGui { if (!mFocusObject.isEmpty()) { - MyGUI::IntSize tooltipSize = getToolTipViaPtr(); + MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount()); setCoord(viewSize.width/2 - tooltipSize.width/2, std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), @@ -326,7 +322,7 @@ namespace MWGui mFocusObject = focus; } - MyGUI::IntSize ToolTips::getToolTipViaPtr (bool image) + MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -342,7 +338,7 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - ToolTipInfo info = object.getToolTipInfo(mFocusObject); + ToolTipInfo info = object.getToolTipInfo(mFocusObject, count); if (!image) info.icon = ""; tooltipSize = createToolTip(info, true); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index fa1ae4f886..dd4d83e56a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -95,7 +95,7 @@ namespace MWGui MWWorld::Ptr mFocusObject; - MyGUI::IntSize getToolTipViaPtr (bool image=true); + MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f44319835..4cdff6c3a1 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -267,7 +267,7 @@ namespace MWWorld throw std::runtime_error ("class does not have any inventory icon"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr) const + MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr, int count) const { throw std::runtime_error ("class does not have a tool tip"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0ac368cca1..c59bd675e9 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -95,7 +95,7 @@ namespace MWWorld virtual bool hasToolTip (const ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; From 5a7bbbd508638171afce00e7e969299b626bfb56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:34:26 +0100 Subject: [PATCH 1797/1812] Accept a ConstPtr in ToolTips::setFocusObject --- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ffc32bd9ff..cb3d0d0a1f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -317,7 +317,7 @@ namespace MWGui } } - void ToolTips::setFocusObject(const MWWorld::Ptr& focus) + void ToolTips::setFocusObject(const MWWorld::ConstPtr& focus) { mFocusObject = focus; } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index dd4d83e56a..1fc736bffd 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -58,7 +58,7 @@ namespace MWGui void setDelay(float delay); - void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObject(const MWWorld::ConstPtr& 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 @@ -93,7 +93,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWWorld::Ptr mFocusObject; + MWWorld::ConstPtr mFocusObject; MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size From 41c8ec56e0e1b231e089d4cc6bc45b0b4615e499 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:37:26 +0100 Subject: [PATCH 1798/1812] Accept a ConstPtr in ItemPtr tooltips --- apps/openmw/mwgui/alchemywindow.cpp | 6 +++--- apps/openmw/mwgui/enchantingdialog.cpp | 4 ++-- apps/openmw/mwgui/hud.cpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 6 +++--- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/repair.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index d12c22e06d..97731e571c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -139,7 +139,7 @@ namespace MWGui if (!iter->isEmpty()) { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); - mApparatus.at (index)->setUserData (*iter); + mApparatus.at (index)->setUserData (MWWorld::ConstPtr(*iter)); } } @@ -207,9 +207,9 @@ namespace MWGui continue; ingredient->setUserString("ToolTipType", "ItemPtr"); - ingredient->setUserData(item); + ingredient->setUserData(MWWorld::ConstPtr(item)); - ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); + ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); } mItemView->update(); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c182a0a527..ac48bf1db2 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -79,7 +79,7 @@ namespace MWGui { mSoulBox->setItem(gem); mSoulBox->setUserString ("ToolTipType", "ItemPtr"); - mSoulBox->setUserData(gem); + mSoulBox->setUserData(MWWorld::ConstPtr(gem)); mEnchanting.setSoulGem(gem); } } @@ -97,7 +97,7 @@ namespace MWGui mName->setCaption(item.getClass().getName(item)); mItemBox->setItem(item); mItemBox->setUserString ("ToolTipType", "ItemPtr"); - mItemBox->setUserData(item); + mItemBox->setUserData(MWWorld::ConstPtr(item)); mEnchanting.setOldItem(item); } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cf0fa3414a..680783c19d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -417,7 +417,7 @@ namespace MWGui mSpellStatus->setProgressPosition(chargePercent); mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(item); + mSpellBox->setUserData(MWWorld::ConstPtr(item)); mSpellImage->setItem(item); } @@ -435,7 +435,7 @@ namespace MWGui mWeapBox->clearUserStrings(); mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(item); + mWeapBox->setUserData(MWWorld::ConstPtr(item)); mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(durabilityPercent); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 481e1ceb47..e22ce5f05d 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -87,11 +87,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; button->setUserString("Price", MyGUI::utility::toString(price)); - button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); + button->setUserData(MWWorld::ConstPtr(*iter)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f2ae8dd837..c741c06ce6 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -185,7 +185,7 @@ namespace MWGui button->setItem(item, ItemWidget::Barter); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); @@ -209,7 +209,7 @@ namespace MWGui button->setIcon(item); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -278,7 +278,7 @@ namespace MWGui if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; - button->setUserData(item); + button->setUserData(MWWorld::ConstPtr(item)); break; } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1dac7138fb..82962aa15f 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -56,7 +56,7 @@ void Recharge::start (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); - mGemIcon->setUserData(item); + mGemIcon->setUserData(MWWorld::ConstPtr(item)); updateView(); } @@ -116,7 +116,7 @@ void Recharge::updateView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); + icon->setUserData(MWWorld::ConstPtr(*iter)); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 49d5735a46..a625c07aba 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -53,7 +53,7 @@ void Repair::startRepairItem(const MWWorld::Ptr &item) mToolIcon->setItem(item); mToolIcon->setUserString("ToolTipType", "ItemPtr"); - mToolIcon->setUserData(item); + mToolIcon->setUserData(MWWorld::ConstPtr(item)); updateRepairView(); } @@ -119,7 +119,7 @@ void Repair::updateRepairView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); + icon->setUserData(MWWorld::ConstPtr(*iter)); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 06809bb49f..ca1219e91c 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -278,7 +278,7 @@ namespace MWGui { if (spell.mType == Spell::Type_EnchantedItem) { - widget->setUserData(spell.mItem); + widget->setUserData(MWWorld::ConstPtr(spell.mItem)); widget->setUserString("ToolTipType", "ItemPtr"); } else diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index cb3d0d0a1f..e24c33b39f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -182,7 +182,7 @@ namespace MWGui } else if (type == "ItemPtr") { - mFocusObject = *focus->getUserData(); + mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") From e5d9ee30f4d15f912cf1b2b3a35c89cd57d260b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 16:47:55 +0100 Subject: [PATCH 1799/1812] Add count argument to copyObjectToCell Fixes the gold bug introduced in c9ca5bc94658508920dbbef1f1a29101ab20ec4f --- apps/openmw/mwclass/misc.cpp | 7 +++++-- apps/openmw/mwclass/misc.hpp | 4 ++-- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/class.cpp | 7 ++++--- apps/openmw/mwworld/class.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 12 +++++------- apps/openmw/mwworld/worldimp.hpp | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 353b93c887..2f41fca303 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -175,7 +175,7 @@ namespace MWClass return info; } - MWWorld::Ptr Miscellaneous::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Miscellaneous::copyToCell(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell, int count) const { MWWorld::Ptr newPtr; @@ -183,7 +183,7 @@ namespace MWClass MWBase::Environment::get().getWorld()->getStore(); if (isGold(ptr)) { - int goldAmount = getValue(ptr) * ptr.getRefData().getCount(); + int goldAmount = getValue(ptr) * count; std::string base = "Gold_001"; if (goldAmount >= 100) @@ -208,7 +208,10 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); newPtr = MWWorld::Ptr(cell.insert(ref), &cell); + newPtr.getRefData().setCount(count); } + newPtr.getCellRef().unsetRefNum(); + return newPtr; } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 363af7e895..2a534f058b 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -7,10 +7,10 @@ namespace MWClass { class Miscellaneous : public MWWorld::Class { - virtual MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const; - public: + virtual MWWorld::Ptr copyToCell(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell, int count) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a6389ee0ce..08f272ea2a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -244,7 +244,7 @@ namespace MWWorld // on a save/load, so do a simple copy & delete for these objects. if (!object.getCellRef().getRefNum().hasContentFile()) { - MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo); + MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo, object.getRefData().getCount()); object.getRefData().setCount(0); object.getRefData().setBaseNode(NULL); return copied; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4cdff6c3a1..7f2d759b95 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -334,17 +334,18 @@ namespace MWWorld } MWWorld::Ptr - Class::copyToCell(const ConstPtr &ptr, CellStore &cell) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, int count) const { Ptr newPtr = copyToCellImpl(ptr, cell); newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference + newPtr.getRefData().setCount(count); return newPtr; } MWWorld::Ptr - Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const + Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const { - Ptr newPtr = copyToCell(ptr, cell); + Ptr newPtr = copyToCell(ptr, cell, count); newPtr.getRefData().setPosition(pos); return newPtr; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c59bd675e9..85cd9ff7c5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -280,9 +280,9 @@ namespace MWWorld /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; - virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, int count) const; - virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos) const; + virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const; virtual bool isActor() const { return false; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f403a6faa0..c2c8e58334 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1321,7 +1321,7 @@ namespace MWWorld MWWorld::Ptr World::safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { - return copyObjectToCell(ptr,cell,pos,false); + return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); } void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const @@ -1817,8 +1817,7 @@ namespace MWWorld pos.rot[1] = 0; // copy the object and set its count - Ptr dropped = copyObjectToCell(object, cell, pos, true); - dropped.getRefData().setCount(amount); + Ptr dropped = copyObjectToCell(object, cell, pos, amount, true); // only the player place items in the world, so no need to check actor PCDropped(dropped); @@ -1844,7 +1843,7 @@ namespace MWWorld } - Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, bool adjustPos) + Ptr World::copyObjectToCell(const ConstPtr &object, CellStore* cell, ESM::Position pos, int count, bool adjustPos) { if (cell->isExterior()) { @@ -1854,7 +1853,7 @@ namespace MWWorld } MWWorld::Ptr dropped = - object.getClass().copyToCell(object, *cell, pos); + object.getClass().copyToCell(object, *cell, pos, count); // Reset some position values that could be uninitialized if this item came from a container dropped.getCellRef().setPosition(pos); @@ -1918,8 +1917,7 @@ namespace MWWorld pos.pos[2] = result.mHitPointWorld.z(); // copy the object and set its count - Ptr dropped = copyObjectToCell(object, cell, pos); - dropped.getRefData().setCount(amount); + Ptr dropped = copyObjectToCell(object, cell, pos, amount, true); if(actor == mPlayer->getPlayer()) // Only call if dropped by player PCDropped(dropped); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2af6a970f1..ceda1321a9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -123,7 +123,7 @@ namespace MWWorld Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return an updated Ptr in case the Ptr's cell changes - Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); + Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos); void updateSoundListener(); void updateWindowManager (); From 5ac226f519a2b05a84a63b50ca901ebea7dcdb35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 17:02:57 +0100 Subject: [PATCH 1800/1812] Another collision mask fix --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c3c171af8b..f6883ae35d 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -796,7 +796,7 @@ namespace MWPhysics DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; - resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; + resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; mCollisionWorld->contactTest(&object, resultCallback); if (resultCallback.mObject) From 2176ac592c12a1298bfbf4af87c4cab9647940d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 21:58:49 +0100 Subject: [PATCH 1801/1812] Call updateDialogueGlobals before dialogue starts (Fixes #3034) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c5e271b7a3..c99e86c2d0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -114,6 +114,8 @@ namespace MWDialogue void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { + updateGlobals(); + // Dialogue with dead actor (e.g. through script) should not be allowed. if (actor.getClass().getCreatureStats(actor).isDead()) return; @@ -331,6 +333,8 @@ namespace MWDialogue void DialogueManager::updateTopics() { + updateGlobals(); + std::list keywordList; int choice = mChoice; mChoice = -1; @@ -417,8 +421,6 @@ namespace MWDialogue win->setKeywords(keywordList); mChoice = choice; - - updateGlobals(); } void DialogueManager::keywordSelected (const std::string& keyword) From db7b80b5035c23adae28b4f7f0bf6997c71dfae4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Dec 2015 22:52:35 +0100 Subject: [PATCH 1802/1812] Revert "Accept a ConstPtr in ItemPtr tooltips" This reverts commit 41c8ec56e0e1b231e089d4cc6bc45b0b4615e499. Does not work due to code relying on getting the non-const Ptr from the widget. Further refactoring is needed. --- apps/openmw/mwgui/alchemywindow.cpp | 6 +++--- apps/openmw/mwgui/enchantingdialog.cpp | 4 ++-- apps/openmw/mwgui/hud.cpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 6 +++--- apps/openmw/mwgui/recharge.cpp | 4 ++-- apps/openmw/mwgui/repair.cpp | 4 ++-- apps/openmw/mwgui/spellview.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 97731e571c..d12c22e06d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -139,7 +139,7 @@ namespace MWGui if (!iter->isEmpty()) { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); - mApparatus.at (index)->setUserData (MWWorld::ConstPtr(*iter)); + mApparatus.at (index)->setUserData (*iter); } } @@ -207,9 +207,9 @@ namespace MWGui continue; ingredient->setUserString("ToolTipType", "ItemPtr"); - ingredient->setUserData(MWWorld::ConstPtr(item)); + ingredient->setUserData(item); - ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); + ingredient->setCount(ingredient->getUserData()->getRefData().getCount()); } mItemView->update(); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ac48bf1db2..c182a0a527 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -79,7 +79,7 @@ namespace MWGui { mSoulBox->setItem(gem); mSoulBox->setUserString ("ToolTipType", "ItemPtr"); - mSoulBox->setUserData(MWWorld::ConstPtr(gem)); + mSoulBox->setUserData(gem); mEnchanting.setSoulGem(gem); } } @@ -97,7 +97,7 @@ namespace MWGui mName->setCaption(item.getClass().getName(item)); mItemBox->setItem(item); mItemBox->setUserString ("ToolTipType", "ItemPtr"); - mItemBox->setUserData(MWWorld::ConstPtr(item)); + mItemBox->setUserData(item); mEnchanting.setOldItem(item); } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 680783c19d..cf0fa3414a 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -417,7 +417,7 @@ namespace MWGui mSpellStatus->setProgressPosition(chargePercent); mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(MWWorld::ConstPtr(item)); + mSpellBox->setUserData(item); mSpellImage->setItem(item); } @@ -435,7 +435,7 @@ namespace MWGui mWeapBox->clearUserStrings(); mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(MWWorld::ConstPtr(item)); + mWeapBox->setUserData(item); mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(durabilityPercent); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index e22ce5f05d..481e1ceb47 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -87,11 +87,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; button->setUserString("Price", MyGUI::utility::toString(price)); + button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(*iter)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index c741c06ce6..f2ae8dd837 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -185,7 +185,7 @@ namespace MWGui button->setItem(item, ItemWidget::Barter); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); @@ -209,7 +209,7 @@ namespace MWGui button->setIcon(item); button->setUserString ("ToolTipType", "ItemPtr"); - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -278,7 +278,7 @@ namespace MWGui if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; - button->setUserData(MWWorld::ConstPtr(item)); + button->setUserData(item); break; } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 82962aa15f..1dac7138fb 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -56,7 +56,7 @@ void Recharge::start (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); - mGemIcon->setUserData(MWWorld::ConstPtr(item)); + mGemIcon->setUserData(item); updateView(); } @@ -116,7 +116,7 @@ void Recharge::updateView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(MWWorld::ConstPtr(*iter)); + icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a625c07aba..49d5735a46 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -53,7 +53,7 @@ void Repair::startRepairItem(const MWWorld::Ptr &item) mToolIcon->setItem(item); mToolIcon->setUserString("ToolTipType", "ItemPtr"); - mToolIcon->setUserData(MWWorld::ConstPtr(item)); + mToolIcon->setUserData(item); updateRepairView(); } @@ -119,7 +119,7 @@ void Repair::updateRepairView() "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(MWWorld::ConstPtr(*iter)); + icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ca1219e91c..06809bb49f 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -278,7 +278,7 @@ namespace MWGui { if (spell.mType == Spell::Type_EnchantedItem) { - widget->setUserData(MWWorld::ConstPtr(spell.mItem)); + widget->setUserData(spell.mItem); widget->setUserString("ToolTipType", "ItemPtr"); } else diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e24c33b39f..cb3d0d0a1f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -182,7 +182,7 @@ namespace MWGui } else if (type == "ItemPtr") { - mFocusObject = *focus->getUserData(); + mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); } else if (type == "ItemModelIndex") From 4c1411776118558633ce872602d2e5733aaf4b15 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 19 Dec 2015 20:03:00 -0500 Subject: [PATCH 1803/1812] Added checks to verifier for container inventories --- .../opencs/model/tools/referenceablecheck.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 336a5e7132..bbff372abf 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -397,6 +397,41 @@ void CSMTools::ReferenceableCheckStage::containerCheck( //checking for name if (container.mName.empty()) messages.push_back (std::make_pair (id, container.mId + " has an empty name")); + + //checking contained items + const std::vector& itemList = container.mInventory.mList; + for (unsigned i = 0; i < itemList.size(); ++i) + { + std::string itemName = itemList[i].mItem.toString(); + CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); + + if (localIndex.first == -1) + messages.push_back (std::make_pair (id, + container.mId + " contains unreferenced item " + itemName)); + else + { + switch (localIndex.second) + { + case CSMWorld::UniversalId::Type_Potion: + case CSMWorld::UniversalId::Type_Apparatus: + case CSMWorld::UniversalId::Type_Armor: + case CSMWorld::UniversalId::Type_Book: + case CSMWorld::UniversalId::Type_Clothing: + case CSMWorld::UniversalId::Type_Ingredient: + case CSMWorld::UniversalId::Type_Light: + case CSMWorld::UniversalId::Type_Lockpick: + case CSMWorld::UniversalId::Type_Miscellaneous: + case CSMWorld::UniversalId::Type_Probe: + case CSMWorld::UniversalId::Type_Repair: + case CSMWorld::UniversalId::Type_Weapon: + case CSMWorld::UniversalId::Type_ItemLevelledList: + break; + default: + messages.push_back (std::make_pair(id, + container.mId + " contains illegal item " + itemName)); + } + } + } // Check that mentioned scripts exist scriptCheck(container, messages, id.toString()); From 9bd14215d7a33995b24cfff29fe7131f96819fb2 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 19 Dec 2015 22:02:39 -0500 Subject: [PATCH 1804/1812] Expanded inventory check to creatures and NPCs --- .../opencs/model/tools/referenceablecheck.cpp | 79 +++++++++++-------- .../opencs/model/tools/referenceablecheck.hpp | 4 +- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index bbff372abf..ce78e52b22 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -399,39 +399,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck( messages.push_back (std::make_pair (id, container.mId + " has an empty name")); //checking contained items - const std::vector& itemList = container.mInventory.mList; - for (unsigned i = 0; i < itemList.size(); ++i) - { - std::string itemName = itemList[i].mItem.toString(); - CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); - - if (localIndex.first == -1) - messages.push_back (std::make_pair (id, - container.mId + " contains unreferenced item " + itemName)); - else - { - switch (localIndex.second) - { - case CSMWorld::UniversalId::Type_Potion: - case CSMWorld::UniversalId::Type_Apparatus: - case CSMWorld::UniversalId::Type_Armor: - case CSMWorld::UniversalId::Type_Book: - case CSMWorld::UniversalId::Type_Clothing: - case CSMWorld::UniversalId::Type_Ingredient: - case CSMWorld::UniversalId::Type_Light: - case CSMWorld::UniversalId::Type_Lockpick: - case CSMWorld::UniversalId::Type_Miscellaneous: - case CSMWorld::UniversalId::Type_Probe: - case CSMWorld::UniversalId::Type_Repair: - case CSMWorld::UniversalId::Type_Weapon: - case CSMWorld::UniversalId::Type_ItemLevelledList: - break; - default: - messages.push_back (std::make_pair(id, - container.mId + " contains illegal item " + itemName)); - } - } - } + inventoryListCheck(container.mInventory.mList, messages, id.toString()); // Check that mentioned scripts exist scriptCheck(container, messages, id.toString()); @@ -506,6 +474,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mScale == 0) messages.push_back (std::make_pair (id, creature.mId + " has zero scale value")); + // Check inventory + inventoryListCheck(creature.mInventory.mList, messages, id.toString()); + // Check that mentioned scripts exist scriptCheck(creature, messages, id.toString()); } @@ -777,6 +748,9 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( //TODO: reputation, Disposition, rank, everything else + // Check inventory + inventoryListCheck(npc.mInventory.mList, messages, id.toString()); + // Check that mentioned scripts exist scriptCheck(npc, messages, id.toString()); } @@ -926,6 +900,45 @@ void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages) "There is no player record")); } +void CSMTools::ReferenceableCheckStage::inventoryListCheck( + const std::vector& itemList, + CSMDoc::Messages& messages, + const std::string& id) +{ + for (size_t i = 0; i < itemList.size(); ++i) + { + std::string itemName = itemList[i].mItem.toString(); + CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); + + if (localIndex.first == -1) + messages.push_back (std::make_pair (id, + id + " contains non-existing item (" + itemName + ")")); + else + { + // Needs to accomodate Containers, Creatures, and NPCs + switch (localIndex.second) + { + case CSMWorld::UniversalId::Type_Potion: + case CSMWorld::UniversalId::Type_Apparatus: + case CSMWorld::UniversalId::Type_Armor: + case CSMWorld::UniversalId::Type_Book: + case CSMWorld::UniversalId::Type_Clothing: + case CSMWorld::UniversalId::Type_Ingredient: + case CSMWorld::UniversalId::Type_Light: + case CSMWorld::UniversalId::Type_Lockpick: + case CSMWorld::UniversalId::Type_Miscellaneous: + case CSMWorld::UniversalId::Type_Probe: + case CSMWorld::UniversalId::Type_Repair: + case CSMWorld::UniversalId::Type_Weapon: + case CSMWorld::UniversalId::Type_ItemLevelledList: + break; + default: + messages.push_back (std::make_pair(id, + id + " contains item of invalid type (" + itemName + ")")); + } + } + } +} //Templates begins here diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index a34f3a7891..4356e50b22 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -47,7 +47,9 @@ namespace CSMTools //FINAL CHECK void finalCheck (CSMDoc::Messages& messages); - //TEMPLATE CHECKS + //Convenience functions + void inventoryListCheck(const std::vector& itemList, CSMDoc::Messages& messages, const std::string& id); + template void inventoryItemCheck(const ITEM& someItem, CSMDoc::Messages& messages, const std::string& someID, From fb2384a7d6d4098e1bcc258fd0aada987790f747 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 20 Dec 2015 09:26:39 +0100 Subject: [PATCH 1805/1812] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index a12aa0e70d..292c1e9e3d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -13,6 +13,7 @@ Programmers Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) + Aesylwinn Aleksandar Jovanov Alex Haddad (rainChu) Alex McKibben (WeirdSexy) From 0efb8e29493b4f26bd591e5a359414a1c1088395 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Dec 2015 17:18:32 +0100 Subject: [PATCH 1806/1812] osgDB::ObjectCache was added in 3.3.3, not 3.4.0 Fixes redefinition error on builds with OSG >3.3.3 <3.4.0 --- components/resource/objectcache.cpp | 2 +- components/resource/objectcache.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 8c2c524165..7264d05aa7 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -13,7 +13,7 @@ #include -#if OSG_VERSION_LESS_THAN(3,4,0) +#if OSG_VERSION_LESS_THAN(3,3,3) #include "objectcache.hpp" diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 0a342f27f6..cae48ca6b7 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -19,7 +19,7 @@ #include -#if OSG_VERSION_GREATER_OR_EQUAL(3,4,0) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) #include #else From a1e163ed209d436c84160ba768af60f246b3003a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 00:26:13 +0100 Subject: [PATCH 1807/1812] Correct an error in the timestamp subtracting logic (Fixes #3105) --- apps/openmw/mwworld/timestamp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index bd07b91f37..ffb1cacb86 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -96,7 +96,7 @@ namespace MWWorld if (left.getHour() Date: Sat, 26 Dec 2015 18:15:57 +0100 Subject: [PATCH 1808/1812] Disable Ready Magic and Cycle Weapon/Spell hotkeys for werewolves (Fixes #3100) --- apps/openmw/mwinput/inputmanagerimp.cpp | 41 +++++++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 71938dfb04..a46f1778bb 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -302,16 +302,20 @@ namespace MWInput quickLoad(); break; case A_CycleSpellLeft: - MWBase::Environment::get().getWindowManager()->cycleSpell(false); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleSpell(false); break; case A_CycleSpellRight: - MWBase::Environment::get().getWindowManager()->cycleSpell(true); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleSpell(true); break; case A_CycleWeaponLeft: - MWBase::Environment::get().getWindowManager()->cycleWeapon(false); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleWeapon(false); break; case A_CycleWeaponRight: - MWBase::Environment::get().getWindowManager()->cycleWeapon(true); + if (checkAllowedToUseItems()) + MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; case A_Sneak: if (mSneakToggles) @@ -346,6 +350,18 @@ namespace MWInput } } + bool InputManager::checkAllowedToUseItems() const + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + if (player.getClass().getNpcStats(player).isWerewolf()) + { + // Cannot use items or spells while in werewolf form + MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + return false; + } + return true; + } + void InputManager::update(float dt, bool disableControls, bool disableEvents) { mControlsDisabled = disableControls; @@ -902,6 +918,9 @@ namespace MWInput if (!mControlSwitch["playermagic"] || !mControlSwitch["playercontrols"]) return; + if (!checkAllowedToUseItems()) + return; + // Not allowed if no spell selected MWWorld::InventoryStore& inventory = mPlayer->getPlayer().getClass().getInventoryStore(mPlayer->getPlayer()); if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() && @@ -1016,13 +1035,8 @@ namespace MWInput { if (!mControlSwitch["playercontrols"]) return; - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.getClass().getNpcStats(player).isWerewolf()) - { - // Cannot use items or spells while in werewolf form - MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + if (!checkAllowedToUseItems()) return; - } if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWindowManager()->activateQuickKey (index); @@ -1033,13 +1047,8 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) { - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.getClass().getNpcStats(player).isWerewolf()) - { - // Cannot use items or spells while in werewolf form - MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); + if (!checkAllowedToUseItems()) return; - } MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3b11e04c09..6443916883 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -213,6 +213,8 @@ namespace MWInput void updateCursorMode(); + bool checkAllowedToUseItems() const; + private: void toggleMainMenu(); void toggleSpell(); From f052c05018455e938b27408115aded79151f90d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:22:21 +0100 Subject: [PATCH 1809/1812] Move werewolf functions from World to MechanicsManager --- apps/openmw/mwbase/mechanicsmanager.hpp | 7 ++ apps/openmw/mwbase/world.hpp | 7 -- .../mwmechanics/mechanicsmanagerimp.cpp | 105 ++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 + apps/openmw/mwscript/statsextensions.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 105 ------------------ apps/openmw/mwworld/worldimp.hpp | 4 - 7 files changed, 117 insertions(+), 118 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 31afc126a1..42da1a052a 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -221,6 +221,13 @@ namespace MWBase virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; + + /// Turn actor into werewolf or normal form. + virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; + + /// Sets the NPC's Acrobatics skill to match the fWerewolfAcrobatics GMST. + /// It only applies to the current form the NPC is in. + virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5ae21022ca..ebce2e1bf8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -456,13 +456,6 @@ namespace MWBase /// Returns true if levitation spell effect is allowed. virtual bool isLevitationEnabled() const = 0; - /// Turn actor into werewolf or normal form. - virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; - - /// Sets the NPC's Acrobatics skill to match the fWerewolfAcrobatics GMST. - /// It only applies to the current form the NPC is in. - virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; - virtual bool getGodModeState() = 0; virtual bool toggleGodMode() = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9dafebffa7..f88d27fce1 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1585,4 +1585,109 @@ namespace MWMechanics { return mActors.isReadyToBlock(ptr); } + + void MechanicsManager::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) + { + MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); + + // The actor does not have to change state + if (npcStats.isWerewolf() == werewolf) + return; + + MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); + + if (actor == player->getPlayer()) + { + if (werewolf) + { + player->saveSkillsAttributes(); + player->setWerewolfSkillsAttributes(); + } + else + player->restoreSkillsAttributes(); + } + + npcStats.setWerewolf(werewolf); + + // This is a bit dangerous. Equipped items other than WerewolfRobe may reference + // bones that do not even exist with the werewolf object root. + // Therefore, make sure to unequip everything at once, and only fire the change event + // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. + MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); + invStore.unequipAll(actor); + + if(werewolf) + { + MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); + + inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); + } + else + { + actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); + } + + if(actor == player->getPlayer()) + { + MWBase::Environment::get().getWorld()->reattachPlayerCamera(); + + // Update the GUI only when called on the player + MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); + + if (werewolf) + { + windowManager->forceHide(MWGui::GW_Inventory); + windowManager->forceHide(MWGui::GW_Magic); + } + else + { + windowManager->unsetForceHide(MWGui::GW_Inventory); + windowManager->unsetForceHide(MWGui::GW_Magic); + } + + windowManager->setWerewolfOverlay(werewolf); + + // Witnesses of the player's transformation will make them a globally known werewolf + std::vector closeActors; + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->getFloat(), closeActors); + + bool detected = false, reported = false; + for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) + { + if (*it == actor) + continue; + + if (!it->getClass().isNpc()) + continue; + + if (MWBase::Environment::get().getWorld()->getLOS(*it, actor) && awarenessCheck(actor, *it)) + detected = true; + if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0) + reported = true; + } + + if (detected) + { + windowManager->messageBox("#{sWerewolfAlarmMessage}"); + MWBase::Environment::get().getWorld()->setGlobalInt("pcknownwerewolf", 1); + + if (reported) + { + npcStats.setBounty(npcStats.getBounty()+ + gmst.find("iWereWolfBounty")->getInt()); + windowManager->messageBox("#{sCrimeMessage}"); + } + } + } + } + + void MechanicsManager::applyWerewolfAcrobatics(const MWWorld::Ptr &actor) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); + + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 603888adc2..fb29c07ea2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -187,6 +187,9 @@ namespace MWMechanics /// @return is \a ptr allowed to take/use \a cellref or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); + virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 2a504f2aba..cdf60d3298 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1096,7 +1096,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->setWerewolf(ptr, set); + MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, set); } }; @@ -1108,7 +1108,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->applyWerewolfAcrobatics(ptr); + MWBase::Environment::get().getMechanicsManager()->applyWerewolfAcrobatics(ptr); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c2c8e58334..15826009d6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2453,111 +2453,6 @@ namespace MWWorld mRendering->rebuildPtr(getPlayerPtr()); } - void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) - { - MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); - - // The actor does not have to change state - if (npcStats.isWerewolf() == werewolf) - return; - - if (actor == getPlayerPtr()) - { - if (werewolf) - { - mPlayer->saveSkillsAttributes(); - mPlayer->setWerewolfSkillsAttributes(); - } - else - mPlayer->restoreSkillsAttributes(); - } - - npcStats.setWerewolf(werewolf); - - // This is a bit dangerous. Equipped items other than WerewolfRobe may reference - // bones that do not even exist with the werewolf object root. - // Therefore, make sure to unequip everything at once, and only fire the change event - // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. - MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); - invStore.unequipAll(actor); - - if(werewolf) - { - InventoryStore &inv = actor.getClass().getInventoryStore(actor); - - inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); - } - else - { - actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); - } - - // NpcAnimation::updateParts will already rebuild the animation when it detects change of Npc type. - // the following is just for reattaching the camera properly. - mRendering->rebuildPtr(actor); - - if(actor == getPlayerPtr()) - { - // Update the GUI only when called on the player - MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); - - if (werewolf) - { - windowManager->forceHide(MWGui::GW_Inventory); - windowManager->forceHide(MWGui::GW_Magic); - } - else - { - windowManager->unsetForceHide(MWGui::GW_Inventory); - windowManager->unsetForceHide(MWGui::GW_Magic); - } - - windowManager->setWerewolfOverlay(werewolf); - - // Witnesses of the player's transformation will make them a globally known werewolf - std::vector closeActors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange(actor.getRefData().getPosition().asVec3(), - getStore().get().search("fAlarmRadius")->getFloat(), - closeActors); - - bool detected = false, reported = false; - for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) - { - if (*it == actor) - continue; - - if (!it->getClass().isNpc()) - continue; - - if (getLOS(*it, actor) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it)) - detected = true; - if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0) - reported = true; - } - - if (detected) - { - windowManager->messageBox("#{sWerewolfAlarmMessage}"); - setGlobalInt("pcknownwerewolf", 1); - - if (reported) - { - npcStats.setBounty(npcStats.getBounty()+ - mStore.get().find("iWereWolfBounty")->getInt()); - windowManager->messageBox("#{sCrimeMessage}"); - } - } - } - } - - void World::applyWerewolfAcrobatics(const Ptr &actor) - { - const Store &gmst = getStore().get(); - MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); - } - bool World::getGodModeState() { return mGodMode; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ceda1321a9..4ed97759ef 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -560,10 +560,6 @@ namespace MWWorld /// Returns true if levitation spell effect is allowed. virtual bool isLevitationEnabled() const; - virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); - - virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); - virtual bool getGodModeState(); virtual bool toggleGodMode(); From 6b67911658f7813419cff9e1d0588f9e50a26f51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:26:55 +0100 Subject: [PATCH 1810/1812] Unset DrawState_Spell when becoming a werewolf --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f88d27fce1..b98e5daa36 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1607,15 +1607,18 @@ namespace MWMechanics player->restoreSkillsAttributes(); } - npcStats.setWerewolf(werewolf); - - // This is a bit dangerous. Equipped items other than WerewolfRobe may reference - // bones that do not even exist with the werewolf object root. - // Therefore, make sure to unequip everything at once, and only fire the change event - // (which will rebuild the animation parts) afterwards. unequipAll will do this for us. + // Equipped items other than WerewolfRobe may reference bones that do not even + // exist with the werewolf object root, so make sure to unequip all items + // *before* we become a werewolf. MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); invStore.unequipAll(actor); + // Werewolfs can not cast spells, so we need to unset the prepared spell if there is one. + if (npcStats.getDrawState() == MWMechanics::DrawState_Spell) + npcStats.setDrawState(MWMechanics::DrawState_Nothing); + + npcStats.setWerewolf(werewolf); + if(werewolf) { MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); From 0bec6e5fbefe6017c757b36e07192c8f9a7c8b19 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:45:09 +0100 Subject: [PATCH 1811/1812] Fix 'failed to find animation' warnings when a spell was equipped before the werewolf transformation --- apps/openmw/mwmechanics/character.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ba6a8fe4b0..db1b82ba6e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -520,6 +520,8 @@ void getWeaponGroup(WeaponType weaptype, std::string &group) const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype)); if(info != sWeaponTypeListEnd) group = info->longgroup; + else + group.clear(); } @@ -1092,11 +1094,14 @@ bool CharacterController::updateWeaponState() std::string weapgroup; if(weaptype == WeapType_None) { - getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "unequip start", "unequip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_UnEquipingWeap; + if ((!isWerewolf || mWeaponType != WeapType_Spell)) + { + getWeaponGroup(mWeaponType, weapgroup); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "unequip start", "unequip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_UnEquipingWeap; + } } else { From 63b9b075aa3e4c759a3d9d27d6a69426116b1e5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Dec 2015 18:47:03 +0100 Subject: [PATCH 1812/1812] Do not allow soul trapping the same creature more than once (Fixes #3102) --- apps/openmw/mwmechanics/actors.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7f857a7008..4046010d79 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -149,14 +149,20 @@ namespace MWMechanics { MWWorld::Ptr mCreature; MWWorld::Ptr mActor; + bool mTrapped; public: SoulTrap(MWWorld::Ptr trappedCreature) - : mCreature(trappedCreature) {} + : mCreature(trappedCreature) + , mTrapped(false) + { + } virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { + if (mTrapped) + return; if (key.mId != ESM::MagicEffect::Soultrap) return; if (magnitude <= 0) @@ -203,6 +209,8 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); + mTrapped = true; + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}");